Passed
Branch develop (5cbde9)
by
unknown
26:38
created

SupplierProposal::load_state_board()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 35
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 21
c 0
b 0
f 0
nc 6
nop 0
dl 0
loc 35
rs 9.2728
1
<?php
2
/* Copyright (C) 2002-2004 Rodolphe Quiedeville		<[email protected]>
3
 * Copyright (C) 2004      Eric Seigne				<[email protected]>
4
 * Copyright (C) 2004-2011 Laurent Destailleur		<[email protected]>
5
 * Copyright (C) 2005      Marc Barilley			<[email protected]>
6
 * Copyright (C) 2005-2013 Regis Houssin			<[email protected]>
7
 * Copyright (C) 2006      Andre Cianfarani			<[email protected]>
8
 * Copyright (C) 2008      Raphael Bertrand			<[email protected]>
9
 * Copyright (C) 2010-2015 Juanjo Menent			<[email protected]>
10
 * Copyright (C) 2010-2018 Philippe Grand			<[email protected]>
11
 * Copyright (C) 2012-2014 Christophe Battarel  	<[email protected]>
12
 * Copyright (C) 2013      Florian Henry		  	<[email protected]>
13
 * Copyright (C) 2014      Marcos García            <[email protected]>
14
 * Copyright (C) 2016      Ferran Marcet            <[email protected]>
15
 * Copyright (C) 2018      Nicolas ZABOURI			<[email protected]>
16
 * Copyright (C) 2019       Frédéric France         <[email protected]>
17
 *
18
 * This program is free software; you can redistribute it and/or modify
19
 * it under the terms of the GNU General Public License as published by
20
 * the Free Software Foundation; either version 3 of the License, or
21
 * (at your option) any later version.
22
 *
23
 * This program is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
 * GNU General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU General Public License
29
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30
 */
31
32
/**
33
 *	\file       htdocs/supplier_proposal/class/supplier_proposal.class.php
34
 *	\brief      File of class to manage supplier proposals
35
 */
36
37
require_once DOL_DOCUMENT_ROOT .'/fourn/class/fournisseur.product.class.php';
38
require_once DOL_DOCUMENT_ROOT .'/core/class/commonobject.class.php';
39
require_once DOL_DOCUMENT_ROOT .'/product/class/product.class.php';
40
require_once DOL_DOCUMENT_ROOT .'/contact/class/contact.class.php';
41
require_once DOL_DOCUMENT_ROOT .'/margin/lib/margins.lib.php';
42
require_once DOL_DOCUMENT_ROOT .'/multicurrency/class/multicurrency.class.php';
43
44
/**
45
 *	Class to manage price ask supplier
46
 */
47
class SupplierProposal extends CommonObject
48
{
49
    /**
50
     * @var string ID to identify managed object
51
     */
52
    public $element='supplier_proposal';
53
54
    /**
55
     * @var string Name of table without prefix where object is stored
56
     */
57
    public $table_element='supplier_proposal';
58
59
    /**
60
     * @var int    Name of subtable line
61
     */
62
    public $table_element_line='supplier_proposaldet';
63
64
    /**
65
     * @var int Field with ID of parent key if this field has a parent
66
     */
67
    public $fk_element='fk_supplier_proposal';
68
69
    public $picto='propal';
70
71
    /**
72
     * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
73
     * @var int
74
     */
75
    public $ismultientitymanaged = 1;
76
77
    /**
78
     * 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
79
     * @var integer
80
     */
81
    public $restrictiononfksoc = 1;
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    protected $table_ref_field = 'ref';
87
88
    public $socid;		// Id client
89
90
    /**
91
     * @deprecated
92
     * @see $user_author_id
93
     */
94
    public $author;
95
96
    public $ref_fourn;					//Reference saisie lors de l'ajout d'une ligne à la demande
97
    public $ref_supplier;				//Reference saisie lors de l'ajout d'une ligne à la demande
98
    public $statut;					// 0 (draft), 1 (validated), 2 (signed), 3 (not signed), 4 (processed/billed)
99
    public $date;						// Date of proposal
100
    public $date_livraison;
101
102
    /**
103
     * @deprecated
104
     * @see $date_creation
105
     */
106
    public $datec;
107
108
    /**
109
     * Creation date
110
     * @var int
111
     */
112
    public $date_creation;
113
114
    /**
115
     * @deprecated
116
     * @see $date_validation
117
     */
118
    public $datev;
119
120
    /**
121
     * Validation date
122
     * @var int
123
     */
124
    public $date_validation;
125
126
127
    public $user_author_id;
128
    public $user_valid_id;
129
    public $user_close_id;
130
131
    /**
132
     * @deprecated
133
     * @see $price_ht
134
     */
135
    public $price;
136
137
    /**
138
     * @deprecated
139
     * @see $total_tva
140
     */
141
    public $tva;
142
143
    /**
144
     * @deprecated
145
     * @see $total_ttc
146
     */
147
    public $total;
148
149
    public $cond_reglement_code;
150
    public $mode_reglement_code;
151
    public $remise = 0;
152
    public $remise_percent = 0;
153
    public $remise_absolue = 0;
154
155
    public $products=array();
156
    public $extraparams=array();
157
158
    public $lines = array();
159
    public $line;
160
161
    public $labelstatut=array();
162
    public $labelstatut_short=array();
163
164
    public $nbtodo;
165
    public $nbtodolate;
166
167
    public $specimen;
168
169
    // Multicurrency
170
    /**
171
     * @var int ID
172
     */
173
    public $fk_multicurrency;
174
175
    public $multicurrency_code;
176
    public $multicurrency_tx;
177
    public $multicurrency_total_ht;
178
    public $multicurrency_total_tva;
179
    public $multicurrency_total_ttc;
180
181
    /**
182
     * Draft status
183
     */
184
    const STATUS_DRAFT = 0;
185
186
    /**
187
     * Validated status
188
     */
189
    const STATUS_VALIDATED = 1;
190
191
    /**
192
     * Signed quote
193
     */
194
    const STATUS_SIGNED = 2;
195
196
    /**
197
     * Not signed quote, canceled
198
     */
199
    const STATUS_NOTSIGNED = 3;
200
201
    /**
202
     * Billed or closed/processed quote
203
     */
204
    const STATUS_CLOSE = 4;
205
206
207
208
    /**
209
     *	Constructor
210
     *
211
     *	@param      DoliDB	$db         Database handler
212
     *	@param      int		$socid		Id third party
213
     *	@param      int		$supplier_proposalid   Id supplier_proposal
214
     */
215
    public function __construct($db, $socid = "", $supplier_proposalid = 0)
216
    {
217
        global $conf,$langs;
218
219
        $this->db = $db;
220
221
        $this->socid = $socid;
222
        $this->id = $supplier_proposalid;
223
224
        $this->products = array();
225
    }
226
227
228
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
229
    /**
230
     * 	Add line into array products
231
     *  $this->client doit etre charge
232
     *
233
     * 	@param  int		$idproduct       	Product Id to add
234
     * 	@param  int		$qty             	Quantity
235
     * 	@param  int		$remise_percent  	Discount effected on Product
236
     *  @return	int							<0 if KO, >0 if OK
237
     *
238
     *	TODO	Remplacer les appels a cette fonction par generation objet Ligne
239
     *			insere dans tableau $this->products
240
     */
241
    public function add_product($idproduct, $qty, $remise_percent = 0)
242
    {
243
        // phpcs:enable
244
        global $conf, $mysoc;
245
246
        if (! $qty) $qty = 1;
247
248
        dol_syslog(get_class($this)."::add_product $idproduct, $qty, $remise_percent");
249
        if ($idproduct > 0)
250
        {
251
            $prod=new Product($this->db);
252
            $prod->fetch($idproduct);
253
254
            $productdesc = $prod->description;
255
256
            $tva_tx = get_default_tva($mysoc, $this->thirdparty, $prod->id);
257
            $tva_npr = get_default_npr($mysoc, $this->thirdparty, $prod->id);
258
            if (empty($tva_tx)) $tva_npr=0;
259
            $localtax1_tx = get_localtax($tva_tx, 1, $mysoc, $this->thirdparty, $tva_npr);
260
            $localtax2_tx = get_localtax($tva_tx, 2, $mysoc, $this->thirdparty, $tva_npr);
261
262
            // multiprix
263
            if($conf->global->PRODUIT_MULTIPRICES && $this->thirdparty->price_level)
264
            {
265
                $price = $prod->multiprices[$this->thirdparty->price_level];
266
            }
267
            else
268
            {
269
                $price = $prod->price;
270
            }
271
272
            $line = new SupplierProposalLine($this->db);
273
274
            $line->fk_product=$idproduct;
275
            $line->desc=$productdesc;
276
            $line->qty=$qty;
277
            $line->subprice=$price;
278
            $line->remise_percent=$remise_percent;
279
            $line->tva_tx=$tva_tx;
280
281
            $this->lines[]=$line;
282
        }
283
    }
284
285
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
286
    /**
287
     *	Adding line of fixed discount in the proposal in DB
288
     *
289
     *	@param     int		$idremise			Id of fixed discount
290
     *  @return    int          				>0 if OK, <0 if KO
291
     */
292
    public function insert_discount($idremise)
293
    {
294
        // phpcs:enable
295
        global $langs;
296
297
        include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
298
        include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
299
300
        $this->db->begin();
301
302
        $remise=new DiscountAbsolute($this->db);
303
        $result=$remise->fetch($idremise);
304
305
        if ($result > 0)
306
        {
307
            if ($remise->fk_facture)	// Protection against multiple submission
308
            {
309
                $this->error=$langs->trans("ErrorDiscountAlreadyUsed");
310
                $this->db->rollback();
311
                return -5;
312
            }
313
314
            $supplier_proposalligne=new SupplierProposalLine($this->db);
315
            $supplier_proposalligne->fk_supplier_proposal=$this->id;
316
            $supplier_proposalligne->fk_remise_except=$remise->id;
317
            $supplier_proposalligne->desc=$remise->description;   	// Description ligne
318
            $supplier_proposalligne->tva_tx=$remise->tva_tx;
319
            $supplier_proposalligne->subprice=-$remise->amount_ht;
320
            $supplier_proposalligne->fk_product=0;					// Id produit predefini
321
            $supplier_proposalligne->qty=1;
322
            $supplier_proposalligne->remise=0;
1 ignored issue
show
Deprecated Code introduced by
The property SupplierProposalLine::$remise has been deprecated. ( Ignorable by Annotation )

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

322
            /** @scrutinizer ignore-deprecated */ $supplier_proposalligne->remise=0;
Loading history...
323
            $supplier_proposalligne->remise_percent=0;
324
            $supplier_proposalligne->rang=-1;
325
            $supplier_proposalligne->info_bits=2;
326
327
            // TODO deprecated
328
            $supplier_proposalligne->price=-$remise->amount_ht;
1 ignored issue
show
Deprecated Code introduced by
The property SupplierProposalLine::$price has been deprecated. ( Ignorable by Annotation )

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

328
            /** @scrutinizer ignore-deprecated */ $supplier_proposalligne->price=-$remise->amount_ht;
Loading history...
329
330
            $supplier_proposalligne->total_ht  = -$remise->amount_ht;
331
            $supplier_proposalligne->total_tva = -$remise->amount_tva;
332
            $supplier_proposalligne->total_ttc = -$remise->amount_ttc;
333
334
            $result=$supplier_proposalligne->insert();
335
            if ($result > 0)
336
            {
337
                $result=$this->update_price(1);
338
                if ($result > 0)
339
                {
340
                    $this->db->commit();
341
                    return 1;
342
                }
343
                else
344
                {
345
                    $this->db->rollback();
346
                    return -1;
347
                }
348
            }
349
            else
350
            {
351
                $this->error=$supplier_proposalligne->error;
352
                $this->db->rollback();
353
                return -2;
354
            }
355
        }
356
        else
357
        {
358
            $this->db->rollback();
359
            return -2;
360
        }
361
    }
362
363
    /**
364
     *    	Add a proposal line into database (linked to product/service or not)
365
     * 		Les parametres sont deja cense etre juste et avec valeurs finales a l'appel
366
     *		de cette methode. Aussi, pour le taux tva, il doit deja avoir ete defini
367
     *		par l'appelant par la methode get_default_tva(societe_vendeuse,societe_acheteuse,'',produit)
368
     *		et le desc doit deja avoir la bonne valeur (a l'appelant de gerer le multilangue)
369
     *
370
     * 		@param    	string		$desc				Description de la ligne
371
     * 		@param    	double		$pu_ht				Prix unitaire
372
     * 		@param    	double		$qty             	Quantite
373
     * 		@param    	double		$txtva           	Taux de tva
374
     * 		@param		double		$txlocaltax1		Local tax 1 rate
375
     *  	@param		double		$txlocaltax2		Local tax 2 rate
376
     *		@param    	int			$fk_product      	Product/Service ID predefined
377
     * 		@param    	double		$remise_percent  	Percentage discount of the line
378
     * 		@param    	string		$price_base_type	HT or TTC
379
     * 		@param    	double		$pu_ttc             Prix unitaire TTC
380
     * 		@param    	int			$info_bits			Bits of type of lines
381
     *      @param      int			$type               Type of line (product, service)
382
     *      @param      int			$rang               Position of line
383
     *      @param		int			$special_code		Special code (also used by externals modules!)
384
     *      @param		int			$fk_parent_line		Id of parent line
385
     *      @param		int			$fk_fournprice		Id supplier price
386
     *      @param		int			$pa_ht				Buying price without tax
387
     *      @param		string		$label				???
388
     *      @param		array		$array_option		extrafields array
389
     * 		@param		string		$ref_supplier			Supplier price reference
390
     * 		@param		int			$fk_unit			Id of the unit to use.
391
     * 		@param		string		$origin				'order', 'supplier_proposal', ...
392
     * 		@param		int			$origin_id			Id of origin line
393
     * 		@param		double		$pu_ht_devise		Amount in currency
394
     *    	@return    	int         	    			>0 if OK, <0 if KO
395
     *
396
     *    	@see       	add_product()
397
     */
398
    public function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $fk_product = 0, $remise_percent = 0, $price_base_type = 'HT', $pu_ttc = 0, $info_bits = 0, $type = 0, $rang = -1, $special_code = 0, $fk_parent_line = 0, $fk_fournprice = 0, $pa_ht = 0, $label = '', $array_option = 0, $ref_supplier = '', $fk_unit = '', $origin = '', $origin_id = 0, $pu_ht_devise = 0)
399
    {
400
        global $mysoc, $conf;
401
402
        dol_syslog(get_class($this)."::addline supplier_proposalid=$this->id, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_except=$remise_percent, price_base_type=$price_base_type, pu_ttc=$pu_ttc, info_bits=$info_bits, type=$type");
403
        include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
404
405
        // Clean parameters
406
        if (empty($remise_percent)) $remise_percent=0;
407
        if (empty($qty)) $qty=0;
408
        if (empty($info_bits)) $info_bits=0;
409
        if (empty($rang)) $rang=0;
410
        if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0;
411
        if (empty($pu_ht)) $pu_ht=0;
412
413
        $remise_percent=price2num($remise_percent);
414
        $qty=price2num($qty);
415
        $pu_ht=price2num($pu_ht);
416
        $pu_ttc=price2num($pu_ttc);
417
        $txtva=price2num($txtva);
418
        $txlocaltax1=price2num($txlocaltax1);
419
        $txlocaltax2=price2num($txlocaltax2);
420
            $pa_ht=price2num($pa_ht);
421
        if ($price_base_type=='HT')
422
        {
423
            $pu=$pu_ht;
424
        }
425
        else
426
        {
427
            $pu=$pu_ttc;
428
        }
429
430
        // Check parameters
431
        if ($type < 0) return -1;
432
433
        if ($this->statut == self::STATUS_DRAFT)
434
        {
435
            $this->db->begin();
436
437
            if ($fk_product > 0)
438
            {
439
                if (! empty($conf->global->SUPPLIER_PROPOSAL_WITH_PREDEFINED_PRICES_ONLY))
440
                {
441
                    // Check quantity is enough
442
                    dol_syslog(get_class($this)."::addline we check supplier prices fk_product=".$fk_product." fk_fournprice=".$fk_fournprice." qty=".$qty." ref_supplier=".$ref_supplier);
443
                    $prod = new Product($this->db, $fk_product);
1 ignored issue
show
Unused Code introduced by
The call to Product::__construct() has too many arguments starting with $fk_product. ( Ignorable by Annotation )

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

443
                    $prod = /** @scrutinizer ignore-call */ new Product($this->db, $fk_product);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
444
                    if ($prod->fetch($fk_product) > 0)
445
                    {
446
                        $product_type = $prod->type;
447
                        $label = $prod->label;
448
                        $fk_prod_fourn_price = $fk_fournprice;
449
450
                        // We use 'none' instead of $ref_supplier, because fourn_ref may not exists anymore. So we will take the first supplier price ok.
451
                        // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
452
                        $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
453
                        if ($result > 0)
454
                        {
455
                            $pu = $prod->fourn_pu;       // Unit price supplier price set by get_buyprice
456
                            $ref_supplier = $prod->ref_supplier;   // Ref supplier price set by get_buyprice
457
                            // is remise percent not keyed but present for the product we add it
458
                            if ($remise_percent == 0 && $prod->remise_percent !=0)
459
                                $remise_percent =$prod->remise_percent;
460
                        }
461
                        if ($result == 0)                   // If result == 0, we failed to found the supplier reference price
462
                        {
463
                            $langs->load("errors");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $langs seems to be never defined.
Loading history...
464
                            $this->error = "Ref " . $prod->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier");
465
                            $this->db->rollback();
466
                            dol_syslog(get_class($this)."::addline we did not found supplier price, so we can't guess unit price");
467
                            //$pu    = $prod->fourn_pu;     // We do not overwrite unit price
468
                            //$ref   = $prod->ref_fourn;    // We do not overwrite ref supplier price
469
                            return -1;
470
                        }
471
                        if ($result == -1)
472
                        {
473
                            $langs->load("errors");
474
                            $this->error = "Ref " . $prod->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier");
475
                            $this->db->rollback();
476
                            dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_DEBUG);
477
                            return -1;
478
                        }
479
                        if ($result < -1)
480
                        {
481
                            $this->error=$prod->error;
482
                            $this->db->rollback();
483
                            dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_ERR);
484
                            return -1;
485
                        }
486
                    }
487
                    else
488
                    {
489
                        $this->error=$prod->error;
490
                        $this->db->rollback();
491
                        return -1;
492
                    }
493
                }
494
            }
495
            else
496
            {
497
                $product_type = $type;
498
            }
499
500
            // Calcul du total TTC et de la TVA pour la ligne a partir de
501
            // qty, pu, remise_percent et txtva
502
            // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
503
            // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
504
505
            $localtaxes_type=getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
506
            $txtva = preg_replace('/\s*\(.*\)/', '', $txtva);  // Remove code into vatrate.
507
508
            if ($conf->multicurrency->enabled && $pu_ht_devise > 0) {
509
                $pu = 0;
510
            }
511
512
            $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);
513
            $total_ht  = $tabprice[0];
514
            $total_tva = $tabprice[1];
515
            $total_ttc = $tabprice[2];
516
            $total_localtax1 = $tabprice[9];
517
            $total_localtax2 = $tabprice[10];
518
            $pu = $pu_ht = $tabprice[3];
519
520
            // MultiCurrency
521
            $multicurrency_total_ht  = $tabprice[16];
522
            $multicurrency_total_tva = $tabprice[17];
523
            $multicurrency_total_ttc = $tabprice[18];
524
            $pu_ht_devise = $tabprice[19];
525
526
            // Rang to use
527
            $rangtouse = $rang;
528
            if ($rangtouse == -1)
529
            {
530
                $rangmax = $this->line_max($fk_parent_line);
531
                $rangtouse = $rangmax + 1;
532
            }
533
534
            // TODO A virer
535
            // Anciens indicateurs: $price, $remise (a ne plus utiliser)
536
            $price = $pu;
537
            $remise = 0;
538
            if ($remise_percent > 0)
539
            {
540
                $remise = round(($pu * $remise_percent / 100), 2);
541
                $price = $pu - $remise;
542
            }
543
544
            // Insert line
545
            $this->line=new SupplierProposalLine($this->db);
546
547
            $this->line->fk_supplier_proposal=$this->id;
548
            $this->line->label=$label;
549
            $this->line->desc=$desc;
550
            $this->line->qty=$qty;
551
            $this->line->tva_tx=$txtva;
552
            $this->line->localtax1_tx=($total_localtax1?$localtaxes_type[1]:0);
553
            $this->line->localtax2_tx=($total_localtax2?$localtaxes_type[3]:0);
554
            $this->line->localtax1_type = $localtaxes_type[0];
555
            $this->line->localtax2_type = $localtaxes_type[2];
556
            $this->line->fk_product=$fk_product;
557
            $this->line->remise_percent=$remise_percent;
558
            $this->line->subprice=$pu_ht;
559
            $this->line->rang=$rangtouse;
560
            $this->line->info_bits=$info_bits;
561
            $this->line->total_ht=$total_ht;
562
            $this->line->total_tva=$total_tva;
563
            $this->line->total_localtax1=$total_localtax1;
564
            $this->line->total_localtax2=$total_localtax2;
565
            $this->line->total_ttc=$total_ttc;
566
            $this->line->product_type=$type;
567
            $this->line->special_code=$special_code;
568
            $this->line->fk_parent_line=$fk_parent_line;
569
            $this->line->fk_unit=$fk_unit;
570
            $this->line->origin=$origin;
571
            $this->line->origin_id=$origin_id;
572
            $this->line->ref_fourn = $this->db->escape($ref_supplier);
573
574
            // infos marge
575
            if (!empty($fk_product) && empty($fk_fournprice) && empty($pa_ht)) {
576
                // by external module, take lowest buying price
577
                include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
578
                $productFournisseur = new ProductFournisseur($this->db);
579
                $productFournisseur->find_min_price_product_fournisseur($fk_product);
580
                $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id;
581
            } else {
582
                $this->line->fk_fournprice = $fk_fournprice;
583
            }
584
            $this->line->pa_ht = $pa_ht;
585
586
            // Multicurrency
587
            $this->line->fk_multicurrency			= $this->fk_multicurrency;
588
            $this->line->multicurrency_code			= $this->multicurrency_code;
589
            $this->line->multicurrency_subprice		= $pu_ht_devise;
590
            $this->line->multicurrency_total_ht 	= $multicurrency_total_ht;
591
            $this->line->multicurrency_total_tva 	= $multicurrency_total_tva;
592
            $this->line->multicurrency_total_ttc 	= $multicurrency_total_ttc;
593
594
            // Mise en option de la ligne
595
            if (empty($qty) && empty($special_code)) $this->line->special_code=3;
596
597
            // TODO deprecated
598
            $this->line->price=$price;
1 ignored issue
show
Deprecated Code introduced by
The property SupplierProposalLine::$price has been deprecated. ( Ignorable by Annotation )

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

598
            /** @scrutinizer ignore-deprecated */ $this->line->price=$price;
Loading history...
599
            $this->line->remise=$remise;
1 ignored issue
show
Deprecated Code introduced by
The property SupplierProposalLine::$remise has been deprecated. ( Ignorable by Annotation )

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

599
            /** @scrutinizer ignore-deprecated */ $this->line->remise=$remise;
Loading history...
600
601
            if (is_array($array_option) && count($array_option)>0) {
602
                $this->line->array_options=$array_option;
603
            }
604
605
            $result=$this->line->insert();
606
            if ($result > 0)
607
            {
608
                // Reorder if child line
609
                if (! empty($fk_parent_line)) $this->line_order(true, 'DESC');
610
611
                // Mise a jour informations denormalisees au niveau de la propale meme
612
                $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.
613
                if ($result > 0)
614
                {
615
                    $this->db->commit();
616
                    return $this->line->rowid;
617
                }
618
                else
619
                {
620
                    $this->error=$this->db->error();
621
                    $this->db->rollback();
622
                    return -1;
623
                }
624
            }
625
            else
626
            {
627
                $this->error=$this->line->error;
628
                $this->db->rollback();
629
                return -2;
630
            }
631
        }
632
    }
633
634
635
    /**
636
     *  Update a proposal line
637
     *
638
     *  @param      int			$rowid           	Id de la ligne
639
     *  @param      double		$pu		     	  	Prix unitaire (HT ou TTC selon price_base_type)
640
     *  @param      double		$qty            	Quantity
641
     *  @param      double		$remise_percent  	Remise effectuee sur le produit
642
     *  @param      double		$txtva	          	Taux de TVA
643
     * 	@param	  	double		$txlocaltax1		Local tax 1 rate
644
     *  @param	  	double		$txlocaltax2		Local tax 2 rate
645
     *  @param      string		$desc            	Description
646
     *	@param	  	double		$price_base_type	HT ou TTC
647
     *	@param      int			$info_bits        	Miscellaneous informations
648
     *	@param		int			$special_code		Special code (also used by externals modules!)
649
     * 	@param		int			$fk_parent_line		Id of parent line (0 in most cases, used by modules adding sublevels into lines).
650
     * 	@param		int			$skip_update_total	Keep fields total_xxx to 0 (used for special lines by some modules)
651
     *  @param		int			$fk_fournprice		Id of origin supplier price
652
     *  @param		int			$pa_ht				Price (without tax) of product when it was bought
653
     *  @param		string		$label				???
654
     *  @param		int			$type				0/1=Product/service
655
     *  @param		array		$array_option		extrafields array
656
     * 	@param		string		$ref_supplier			Supplier price reference
657
     *	@param		int			$fk_unit			Id of the unit to use.
658
	 * 	@param		double		$pu_ht_devise		Unit price in currency
659
     *  @return     int     		        		0 if OK, <0 if KO
660
     */
661
    public function updateline($rowid, $pu, $qty, $remise_percent, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $desc = '', $price_base_type = 'HT', $info_bits = 0, $special_code = 0, $fk_parent_line = 0, $skip_update_total = 0, $fk_fournprice = 0, $pa_ht = 0, $label = '', $type = 0, $array_option = 0, $ref_supplier = '', $fk_unit = '', $pu_ht_devise = 0)
662
    {
663
        global $conf,$user,$langs, $mysoc;
664
665
        dol_syslog(get_class($this)."::updateLine $rowid, $pu, $qty, $remise_percent, $txtva, $desc, $price_base_type, $info_bits");
666
        include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
667
668
        // Clean parameters
669
        $remise_percent=price2num($remise_percent);
670
        $qty=price2num($qty);
671
        $pu = price2num($pu);
672
        $txtva = price2num($txtva);
673
        $txlocaltax1=price2num($txlocaltax1);
674
        $txlocaltax2=price2num($txlocaltax2);
675
        $pa_ht=price2num($pa_ht);
676
        if (empty($qty) && empty($special_code)) $special_code=3;    // Set option tag
677
        if (! empty($qty) && $special_code == 3) $special_code=0;    // Remove option tag
678
679
        if ($this->statut == 0)
680
        {
681
            $this->db->begin();
682
683
            // Calcul du total TTC et de la TVA pour la ligne a partir de
684
            // qty, pu, remise_percent et txtva
685
            // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
686
            // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
687
688
            $localtaxes_type=getLocalTaxesFromRate($txtva, 0, $mysoc, $this->thirdparty);
689
690
            // Clean vat code
691
            $vat_src_code='';
692
            if (preg_match('/\((.*)\)/', $txtva, $reg))
693
            {
694
            	$vat_src_code = $reg[1];
695
            	$txtva = preg_replace('/\s*\(.*\)/', '', $txtva);    // Remove code into vatrate.
696
            }
697
698
            $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);
699
            $total_ht  = $tabprice[0];
700
            $total_tva = $tabprice[1];
701
            $total_ttc = $tabprice[2];
702
            $total_localtax1 = $tabprice[9];
703
            $total_localtax2 = $tabprice[10];
704
705
            // MultiCurrency
706
            $multicurrency_total_ht  = $tabprice[16];
707
            $multicurrency_total_tva = $tabprice[17];
708
            $multicurrency_total_ttc = $tabprice[18];
709
710
            // Anciens indicateurs: $price, $remise (a ne plus utiliser)
711
            $price = $pu;
712
            if ($remise_percent > 0)
713
            {
714
                $remise = round(($pu * $remise_percent / 100), 2);
715
                $price = $pu - $remise;
716
            }
717
718
            // Update line
719
            $this->line=new SupplierProposalLine($this->db);
720
721
            // Stock previous line records
722
            $staticline=new SupplierProposalLine($this->db);
723
            $staticline->fetch($rowid);
724
            $this->line->oldline = $staticline;
725
726
            // Reorder if fk_parent_line change
727
            if (! empty($fk_parent_line) && ! empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line)
728
            {
729
                $rangmax = $this->line_max($fk_parent_line);
730
                $this->line->rang = $rangmax + 1;
731
            }
732
733
            $this->line->rowid				= $rowid;
734
            $this->line->label				= $label;
735
            $this->line->desc				= $desc;
736
            $this->line->qty				= $qty;
737
            $this->line->product_type		= $type;
738
739
            $this->line->vat_src_code       = $vat_src_code;
0 ignored issues
show
Bug introduced by
The property vat_src_code does not seem to exist on SupplierProposalLine.
Loading history...
740
            $this->line->tva_tx				= $txtva;
741
            $this->line->localtax1_tx		= $txlocaltax1;
742
            $this->line->localtax2_tx		= $txlocaltax2;
743
            $this->line->localtax1_type		= $localtaxes_type[0];
744
            $this->line->localtax2_type		= $localtaxes_type[2];
745
            $this->line->remise_percent		= $remise_percent;
746
            $this->line->subprice			= $pu;
747
            $this->line->info_bits			= $info_bits;
748
            $this->line->total_ht			= $total_ht;
749
            $this->line->total_tva			= $total_tva;
750
            $this->line->total_localtax1	= $total_localtax1;
751
            $this->line->total_localtax2	= $total_localtax2;
752
            $this->line->total_ttc			= $total_ttc;
753
            $this->line->special_code		= $special_code;
754
            $this->line->fk_parent_line		= $fk_parent_line;
755
            $this->line->skip_update_total	= $skip_update_total;
756
            $this->line->ref_fourn			= $ref_supplier;
757
            $this->line->fk_unit			= $fk_unit;
758
759
            // infos marge
760
            if (!empty($fk_product) && empty($fk_fournprice) && empty($pa_ht)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fk_product seems to never exist and therefore empty should always be true.
Loading history...
761
                // by external module, take lowest buying price
762
                include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
763
                $productFournisseur = new ProductFournisseur($this->db);
764
                $productFournisseur->find_min_price_product_fournisseur($fk_product);
765
                $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id;
766
            } else {
767
                $this->line->fk_fournprice = $fk_fournprice;
768
            }
769
            $this->line->pa_ht = $pa_ht;
770
771
            // TODO deprecated
772
            $this->line->price=$price;
1 ignored issue
show
Deprecated Code introduced by
The property SupplierProposalLine::$price has been deprecated. ( Ignorable by Annotation )

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

772
            /** @scrutinizer ignore-deprecated */ $this->line->price=$price;
Loading history...
773
            $this->line->remise=$remise;
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $remise does not seem to be defined for all execution paths leading up to this point.
Loading history...
Deprecated Code introduced by
The property SupplierProposalLine::$remise has been deprecated. ( Ignorable by Annotation )

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

773
            /** @scrutinizer ignore-deprecated */ $this->line->remise=$remise;
Loading history...
774
775
            if (is_array($array_option) && count($array_option)>0) {
776
                $this->line->array_options=$array_option;
777
            }
778
779
            // Multicurrency
780
            $this->line->multicurrency_subprice		= price2num($pu * $this->multicurrency_tx);
781
            $this->line->multicurrency_total_ht 	= $multicurrency_total_ht;
782
            $this->line->multicurrency_total_tva 	= $multicurrency_total_tva;
783
            $this->line->multicurrency_total_ttc 	= $multicurrency_total_ttc;
784
785
            $result=$this->line->update();
786
            if ($result > 0)
787
            {
788
                // Reorder if child line
789
                if (! empty($fk_parent_line)) $this->line_order(true, 'DESC');
790
791
                $this->update_price(1);
792
793
                $this->fk_supplier_proposal = $this->id;
794
                $this->rowid = $rowid;
795
796
                $this->db->commit();
797
                return $result;
798
            }
799
            else
800
            {
801
                $this->error=$this->db->error();
802
                $this->db->rollback();
803
                return -1;
804
            }
805
        }
806
        else
807
        {
808
            dol_syslog(get_class($this)."::updateline Erreur -2 SupplierProposal en mode incompatible pour cette action");
809
            return -2;
810
        }
811
    }
812
813
814
    /**
815
     *  Delete detail line
816
     *
817
     *  @param		int		$lineid			Id of line to delete
818
     *  @return     int         			>0 if OK, <0 if KO
819
     */
820
    public function deleteline($lineid)
821
    {
822
        if ($this->statut == 0)
823
        {
824
            $line=new SupplierProposalLine($this->db);
825
826
            // For triggers
827
            $line->fetch($lineid);
828
829
            if ($line->delete() > 0)
830
            {
831
                $this->update_price(1);
832
833
                return 1;
834
            }
835
            else
836
            {
837
                return -1;
838
            }
839
        }
840
        else
841
        {
842
            return -2;
843
        }
844
    }
845
846
847
    /**
848
     *  Create commercial proposal into database
849
     * 	this->ref can be set or empty. If empty, we will use "(PROVid)"
850
     *
851
     * 	@param		User	$user		User that create
852
     * 	@param		int		$notrigger	1=Does not execute triggers, 0= execute triggers
853
     *  @return     int     			<0 if KO, >=0 if OK
854
     */
855
    public function create($user, $notrigger = 0)
856
    {
857
        global $langs, $conf, $mysoc, $hookmanager;
858
        $error=0;
859
860
        $now=dol_now();
861
862
        dol_syslog(get_class($this)."::create");
863
864
        // Check parameters
865
        $result=$this->fetch_thirdparty();
866
        if ($result < 0)
867
        {
868
            $this->error="Failed to fetch company";
869
            dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
870
            return -3;
871
        }
872
873
        // Check parameters
874
        if (! empty($this->ref))	// We check that ref is not already used
875
        {
876
            $result=self::isExistingObject($this->element, 0, $this->ref);	// Check ref is not yet used
877
            if ($result > 0)
878
            {
879
                $this->error='ErrorRefAlreadyExists';
880
                dol_syslog(get_class($this)."::create ".$this->error, LOG_WARNING);
881
                $this->db->rollback();
882
                return -1;
883
            }
884
        }
885
886
        // Multicurrency
887
        if (!empty($this->multicurrency_code)) list($this->fk_multicurrency,$this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
888
        if (empty($this->fk_multicurrency))
889
        {
890
            $this->multicurrency_code = $conf->currency;
891
            $this->fk_multicurrency = 0;
892
            $this->multicurrency_tx = 1;
893
        }
894
895
        $this->db->begin();
896
897
        // Insert into database
898
        $sql = "INSERT INTO ".MAIN_DB_PREFIX."supplier_proposal (";
899
        $sql.= "fk_soc";
900
        $sql.= ", price";
901
        $sql.= ", remise";
902
        $sql.= ", remise_percent";
903
        $sql.= ", remise_absolue";
904
        $sql.= ", tva";
905
        $sql.= ", total";
906
        $sql.= ", datec";
907
        $sql.= ", ref";
908
        $sql.= ", fk_user_author";
909
        $sql.= ", note_private";
910
        $sql.= ", note_public";
911
        $sql.= ", model_pdf";
912
        $sql.= ", fk_cond_reglement";
913
        $sql.= ", fk_mode_reglement";
914
        $sql.= ", fk_account";
915
        $sql.= ", date_livraison";
916
        $sql.= ", fk_shipping_method";
917
        $sql.= ", fk_projet";
918
        $sql.= ", entity";
919
        $sql.= ", fk_multicurrency";
920
        $sql.= ", multicurrency_code";
921
        $sql.= ", multicurrency_tx";
922
        $sql.= ") ";
923
        $sql.= " VALUES (";
924
        $sql.= $this->socid;
925
        $sql.= ", 0";
926
        $sql.= ", ".$this->remise;
927
        $sql.= ", ".($this->remise_percent?$this->db->escape($this->remise_percent):'null');
928
        $sql.= ", ".($this->remise_absolue?$this->db->escape($this->remise_absolue):'null');
929
        $sql.= ", 0";
930
        $sql.= ", 0";
931
        $sql.= ", '".$this->db->idate($now)."'";
932
        $sql.= ", '(PROV)'";
933
        $sql.= ", ".($user->id > 0 ? "'".$user->id."'":"null");
934
        $sql.= ", '".$this->db->escape($this->note_private)."'";
935
        $sql.= ", '".$this->db->escape($this->note_public)."'";
936
        $sql.= ", '".$this->db->escape($this->modelpdf)."'";
937
        $sql.= ", ".($this->cond_reglement_id > 0 ? $this->cond_reglement_id : 'NULL');
938
        $sql.= ", ".($this->mode_reglement_id > 0 ? $this->mode_reglement_id : 'NULL');
939
        $sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL');
940
        $sql.= ", ".($this->date_livraison!=''?"'".$this->db->idate($this->date_livraison)."'":"null");
941
        $sql.= ", ".($this->shipping_method_id>0?$this->shipping_method_id:'NULL');
942
        $sql.= ", ".($this->fk_project?$this->fk_project:"null");
943
        $sql.= ", ".$conf->entity;
944
        $sql.= ", ".(int) $this->fk_multicurrency;
945
        $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
946
        $sql.= ", ".(double) $this->multicurrency_tx;
947
        $sql.= ")";
948
949
        dol_syslog(get_class($this)."::create", LOG_DEBUG);
950
        $resql=$this->db->query($sql);
951
        if ($resql)
952
        {
953
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."supplier_proposal");
954
955
            if ($this->id)
956
            {
957
                $this->ref='(PROV'.$this->id.')';
958
                $sql = 'UPDATE '.MAIN_DB_PREFIX."supplier_proposal SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".$this->id;
959
960
                dol_syslog(get_class($this)."::create", LOG_DEBUG);
961
                $resql=$this->db->query($sql);
962
                if (! $resql) $error++;
963
964
                if (! empty($this->linkedObjectsIds) && empty($this->linked_objects))	// To use new linkedObjectsIds instead of old linked_objects
965
                {
966
                    $this->linked_objects = $this->linkedObjectsIds;	// TODO Replace linked_objects with linkedObjectsIds
967
                }
968
969
                // Add object linked
970
                if (! $error && $this->id && is_array($this->linked_objects) && ! empty($this->linked_objects))
971
                {
972
                    foreach($this->linked_objects as $origin => $tmp_origin_id)
973
                    {
974
                        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, ...))
975
                        {
976
                            foreach($tmp_origin_id as $origin_id)
977
                            {
978
                                $ret = $this->add_object_linked($origin, $origin_id);
979
                                if (! $ret)
980
                                {
981
                                    dol_print_error($this->db);
982
                                    $error++;
983
                                }
984
                            }
985
                        }
986
                    }
987
                }
988
989
                // Add linked object (deprecated, use ->linkedObjectsIds instead)
990
                if (! $error && $this->origin && $this->origin_id)
991
                {
992
                    $ret = $this->add_object_linked();
993
                    if (! $ret)	dol_print_error($this->db);
994
                }
995
996
                /*
997
                 *  Insertion du detail des produits dans la base
998
                 */
999
                if (! $error)
1000
                {
1001
                    $fk_parent_line=0;
1002
                    $num=count($this->lines);
1003
1004
                    for ($i=0;$i<$num;$i++)
1005
                    {
1006
                        // Reset fk_parent_line for no child products and special product
1007
                        if (($this->lines[$i]->product_type != 9 && empty($this->lines[$i]->fk_parent_line)) || $this->lines[$i]->product_type == 9) {
1008
                            $fk_parent_line = 0;
1009
                        }
1010
1011
                        $result = $this->addline(
1012
                            $this->lines[$i]->desc,
1013
                            $this->lines[$i]->subprice,
1014
                            $this->lines[$i]->qty,
1015
                            $this->lines[$i]->tva_tx,
1016
                            $this->lines[$i]->localtax1_tx,
1017
                            $this->lines[$i]->localtax2_tx,
1018
                            $this->lines[$i]->fk_product,
1019
                            $this->lines[$i]->remise_percent,
1020
                            'HT',
1021
                            0,
1022
                            0,
1023
                            $this->lines[$i]->product_type,
1024
                            $this->lines[$i]->rang,
1025
                            $this->lines[$i]->special_code,
1026
                            $fk_parent_line,
1027
                            $this->lines[$i]->fk_fournprice,
1028
                            $this->lines[$i]->pa_ht,
1029
                            $this->lines[$i]->label,
1030
                            $this->lines[$i]->array_options,
1031
                            $this->lines[$i]->ref_fourn,
1032
                            $this->lines[$i]->fk_unit,
1033
                            'supplier_proposal',
1034
                            $this->lines[$i]->rowid
1035
                        );
1036
1037
                        if ($result < 0)
1038
                        {
1039
                            $error++;
1040
                            $this->error=$this->db->error;
1041
                            dol_print_error($this->db);
1042
                            break;
1043
                        }
1044
                        // Defined the new fk_parent_line
1045
                        if ($result > 0 && $this->lines[$i]->product_type == 9) {
1046
                            $fk_parent_line = $result;
1047
                        }
1048
                    }
1049
                }
1050
1051
                if (! $error)
1052
                {
1053
                    // Mise a jour infos denormalisees
1054
                    $resql=$this->update_price(1);
1055
                    if ($resql)
1056
                    {
1057
                        $action='update';
1058
1059
                        // Actions on extra fields
1060
                        if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))
1061
                        {
1062
                            $result=$this->insertExtraFields();
1063
                            if ($result < 0)
1064
                            {
1065
                                $error++;
1066
                            }
1067
                        }
1068
1069
                        if (! $error && ! $notrigger)
1070
                        {
1071
                            // Call trigger
1072
                            $result=$this->call_trigger('PROPAL_SUPPLIER_CREATE', $user);
1073
                            if ($result < 0) { $error++; }
1074
                            // End call triggers
1075
                        }
1076
                    }
1077
                    else
1078
                    {
1079
                        $this->error=$this->db->lasterror();
1080
                        $error++;
1081
                    }
1082
                }
1083
            }
1084
            else
1085
            {
1086
                $this->error=$this->db->lasterror();
1087
                $error++;
1088
            }
1089
1090
            if (! $error)
1091
            {
1092
                $this->db->commit();
1093
                dol_syslog(get_class($this)."::create done id=".$this->id);
1094
                return $this->id;
1095
            }
1096
            else
1097
            {
1098
                $this->db->rollback();
1099
                return -2;
1100
            }
1101
        }
1102
        else
1103
        {
1104
            $this->error=$this->db->lasterror();
1105
            $this->db->rollback();
1106
            return -1;
1107
        }
1108
    }
1109
1110
1111
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1112
    /**
1113
     *	Insert into DB a supplier_proposal object completely defined by its data members (ex, results from copy).
1114
     *
1115
     *	@param 		User	$user	User that create
1116
     *	@return    	int				Id of the new object if ok, <0 if ko
1117
     *	@see       	create()
1118
     */
1119
    public function create_from($user)
1120
    {
1121
        // phpcs:enable
1122
        $this->products=$this->lines;
1123
1124
        return $this->create($user);
1125
    }
1126
1127
    /**
1128
     *		Load an object from its id and create a new one in database
1129
     *
1130
	 *      @param	    User	$user		    User making the clone
1131
     *		@param		int		$fromid			Id of thirdparty
1132
     * 	 	@return		int						New id of clone
1133
     */
1134
    public function createFromClone(User $user, $fromid = 0)
1135
    {
1136
        global $conf,$hookmanager;
1137
1138
        $error=0;
1139
        $now=dol_now();
1140
1141
        $this->db->begin();
1142
1143
        // get extrafields so they will be clone
1144
        foreach($this->lines as $line)
1145
            $line->fetch_optionals();
1146
1147
        // Load source object
1148
        $objFrom = clone $this;
1149
1150
        $objsoc=new Societe($this->db);
1151
1152
        // Change socid if needed
1153
        if (! empty($fromid) && $fromid != $this->socid)
1154
        {
1155
            if ($objsoc->fetch($fromid) > 0)
1156
            {
1157
                $this->socid 				= $objsoc->id;
1158
                $this->cond_reglement_id	= (! empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
1159
                $this->mode_reglement_id	= (! empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
1160
                $this->fk_project			= '';
1 ignored issue
show
Documentation Bug introduced by
The property $fk_project was declared of type integer, but '' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1161
            }
1162
1163
            // TODO Change product price if multi-prices
1164
        }
1165
        else
1166
        {
1167
            $objsoc->fetch($this->socid);
1168
        }
1169
1170
        $this->id=0;
1171
        $this->statut=0;
1172
1173
        if (empty($conf->global->SUPPLIER_PROPOSAL_ADDON) || ! is_readable(DOL_DOCUMENT_ROOT ."/core/modules/supplier_proposal/".$conf->global->SUPPLIER_PROPOSAL_ADDON.".php"))
1174
        {
1175
            $this->error='ErrorSetupNotComplete';
1176
            return -1;
1177
        }
1178
1179
        // Clear fields
1180
        $this->user_author	= $user->id;
1181
        $this->user_valid	= '';
1182
        $this->date			= $now;
1183
1184
        // Set ref
1185
        require_once DOL_DOCUMENT_ROOT ."/core/modules/supplier_proposal/".$conf->global->SUPPLIER_PROPOSAL_ADDON.'.php';
1186
        $obj = $conf->global->SUPPLIER_PROPOSAL_ADDON;
1187
        $modSupplierProposal = new $obj;
1188
        $this->ref = $modSupplierProposal->getNextValue($objsoc, $this);
1189
1190
        // Create clone
1191
        $this->context['createfromclone'] = 'createfromclone';
1192
        $result=$this->create($user);
1193
        if ($result < 0) $error++;
1194
1195
        if (! $error)
1196
        {
1197
            // Hook of thirdparty module
1198
            if (is_object($hookmanager))
1199
            {
1200
                $parameters=array('objFrom'=>$objFrom);
1201
                $action='';
1202
                $reshook=$hookmanager->executeHooks('createFrom', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
1203
                if ($reshook < 0) $error++;
1204
            }
1205
        }
1206
1207
        unset($this->context['createfromclone']);
1208
1209
        // End
1210
        if (! $error)
1211
        {
1212
            $this->db->commit();
1213
            return $this->id;
1214
        }
1215
        else
1216
        {
1217
            $this->db->rollback();
1218
            return -1;
1219
        }
1220
    }
1221
1222
    /**
1223
     *	Load a proposal from database and its ligne array
1224
     *
1225
     *	@param      int			$rowid		id of object to load
1226
     *	@param		string		$ref		Ref of proposal
1227
     *	@return     int         			>0 if OK, <0 if KO
1228
     */
1229
    public function fetch($rowid, $ref = '')
1230
    {
1231
        global $conf;
1232
1233
        $sql = "SELECT p.rowid, p.entity, p.ref, p.remise, p.remise_percent, p.remise_absolue, p.fk_soc";
1234
        $sql.= ", p.total, p.tva, p.localtax1, p.localtax2, p.total_ht";
1235
        $sql.= ", p.datec";
1236
        $sql.= ", p.date_valid as datev";
1237
        $sql.= ", p.date_livraison as date_livraison";
1238
        $sql.= ", p.model_pdf, p.extraparams";
1239
        $sql.= ", p.note_private, p.note_public";
1240
        $sql.= ", p.fk_projet as fk_project, p.fk_statut";
1241
        $sql.= ", p.fk_user_author, p.fk_user_valid, p.fk_user_cloture";
1242
        $sql.= ", p.fk_cond_reglement";
1243
        $sql.= ", p.fk_mode_reglement";
1244
        $sql.= ', p.fk_account';
1245
        $sql.= ", p.fk_shipping_method";
1246
        $sql.= ", p.fk_multicurrency, p.multicurrency_code, p.multicurrency_tx, p.multicurrency_total_ht, p.multicurrency_total_tva, p.multicurrency_total_ttc";
1247
        $sql.= ", c.label as statut_label";
1248
        $sql.= ", cr.code as cond_reglement_code, cr.libelle as cond_reglement, cr.libelle_facture as cond_reglement_libelle_doc";
1249
        $sql.= ", cp.code as mode_reglement_code, cp.libelle as mode_reglement";
1250
        $sql.= " FROM ".MAIN_DB_PREFIX."c_propalst as c, ".MAIN_DB_PREFIX."supplier_proposal as p";
1251
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as cp ON p.fk_mode_reglement = cp.id';
1252
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON p.fk_cond_reglement = cr.rowid';
1253
        $sql.= " WHERE p.fk_statut = c.id";
1254
        $sql.= " AND p.entity IN (".getEntity('supplier_proposal').")";
1255
        if ($ref) $sql.= " AND p.ref='".$ref."'";
1256
        else $sql.= " AND p.rowid=".$rowid;
1257
1258
        dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1259
        $resql=$this->db->query($sql);
1260
        if ($resql)
1261
        {
1262
            if ($this->db->num_rows($resql))
1263
            {
1264
                $obj = $this->db->fetch_object($resql);
1265
1266
                $this->id                   = $obj->rowid;
1267
                $this->entity               = $obj->entity;
1268
1269
                $this->ref                  = $obj->ref;
1270
                $this->remise               = $obj->remise;
1271
                $this->remise_percent       = $obj->remise_percent;
1272
                $this->remise_absolue       = $obj->remise_absolue;
1273
                $this->total                = $obj->total; // TODO deprecated
1274
                $this->total_ht             = $obj->total_ht;
1275
                $this->total_tva            = $obj->tva;
1276
                $this->total_localtax1		= $obj->localtax1;
1277
                $this->total_localtax2		= $obj->localtax2;
1278
                $this->total_ttc            = $obj->total;
1279
                $this->socid                = $obj->fk_soc;
1280
                $this->fk_project           = $obj->fk_project;
1281
                $this->modelpdf             = $obj->model_pdf;
1282
                $this->note                 = $obj->note_private; // TODO deprecated
1283
                $this->note_private         = $obj->note_private;
1284
                $this->note_public          = $obj->note_public;
1285
                $this->statut               = (int) $obj->fk_statut;
1286
                $this->statut_libelle       = $obj->statut_label;
1287
                $this->datec                = $this->db->jdate($obj->datec); // TODO deprecated
1288
                $this->datev                = $this->db->jdate($obj->datev); // TODO deprecated
1289
                $this->date_creation		= $this->db->jdate($obj->datec); //Creation date
1290
                $this->date_validation		= $this->db->jdate($obj->datev); //Validation date
1291
                $this->date_livraison       = $this->db->jdate($obj->date_livraison);
1292
                $this->shipping_method_id   = ($obj->fk_shipping_method>0)?$obj->fk_shipping_method:null;
1293
1294
                $this->mode_reglement_id    = $obj->fk_mode_reglement;
1295
                $this->mode_reglement_code  = $obj->mode_reglement_code;
1296
                $this->mode_reglement       = $obj->mode_reglement;
1297
                $this->fk_account           = ($obj->fk_account>0)?$obj->fk_account:null;
1298
                $this->cond_reglement_id    = $obj->fk_cond_reglement;
1299
                $this->cond_reglement_code  = $obj->cond_reglement_code;
1300
                $this->cond_reglement       = $obj->cond_reglement;
1301
                $this->cond_reglement_doc   = $obj->cond_reglement_libelle_doc;
1302
1303
                $this->extraparams			= (array) json_decode($obj->extraparams, true);
1304
1305
                $this->user_author_id = $obj->fk_user_author;
1306
                $this->user_valid_id  = $obj->fk_user_valid;
1307
                $this->user_close_id  = $obj->fk_user_cloture;
1308
1309
                // Multicurrency
1310
                $this->fk_multicurrency 		= $obj->fk_multicurrency;
1311
                $this->multicurrency_code 		= $obj->multicurrency_code;
1312
                $this->multicurrency_tx 		= $obj->multicurrency_tx;
1313
                $this->multicurrency_total_ht 	= $obj->multicurrency_total_ht;
1314
                $this->multicurrency_total_tva 	= $obj->multicurrency_total_tva;
1315
                $this->multicurrency_total_ttc 	= $obj->multicurrency_total_ttc;
1316
1317
                if ($obj->fk_statut == 0)
1318
                {
1319
                    $this->brouillon = 1;
1320
                }
1321
1322
                // Retreive all extrafield
1323
                // fetch optionals attributes and labels
1324
                $this->fetch_optionals();
1325
1326
                $this->db->free($resql);
1327
1328
                $this->lines = array();
1329
1330
                // Lines of supplier proposals
1331
                $sql = "SELECT d.rowid, d.fk_supplier_proposal, d.fk_parent_line, d.label as custom_label, d.description, d.price, d.tva_tx, d.localtax1_tx, d.localtax2_tx, d.qty, d.fk_remise_except, d.remise_percent, d.subprice, d.fk_product,";
1332
                $sql.= " d.info_bits, d.total_ht, d.total_tva, d.total_localtax1, d.total_localtax2, d.total_ttc, d.fk_product_fournisseur_price as fk_fournprice, d.buy_price_ht as pa_ht, d.special_code, d.rang, d.product_type,";
1333
                $sql.= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label,';
1334
                $sql.= ' d.ref_fourn as ref_produit_fourn,';
1335
                $sql.= ' d.fk_multicurrency, d.multicurrency_code, d.multicurrency_subprice, d.multicurrency_total_ht, d.multicurrency_total_tva, d.multicurrency_total_ttc, d.fk_unit';
1336
                $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposaldet as d";
1337
                $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON d.fk_product = p.rowid";
1338
                $sql.= " WHERE d.fk_supplier_proposal = ".$this->id;
1339
                $sql.= " ORDER by d.rang";
1340
1341
                $result = $this->db->query($sql);
1342
                if ($result)
1343
                {
1344
                    $num = $this->db->num_rows($result);
1345
                    $i = 0;
1346
1347
                    while ($i < $num)
1348
                    {
1349
                        $objp                   = $this->db->fetch_object($result);
1350
1351
                        $line                   = new SupplierProposalLine($this->db);
1352
1353
                        $line->rowid			= $objp->rowid; // deprecated
1354
                        $line->id				= $objp->rowid;
1355
                        $line->fk_supplier_proposal		= $objp->fk_supplier_proposal;
1356
                        $line->fk_parent_line	= $objp->fk_parent_line;
1357
                        $line->product_type     = $objp->product_type;
1358
                        $line->label            = $objp->custom_label;
1359
                        $line->desc             = $objp->description;  // Description ligne
1360
                        $line->qty              = $objp->qty;
1361
                        $line->tva_tx           = $objp->tva_tx;
1362
                        $line->localtax1_tx		= $objp->localtax1_tx;
1363
                        $line->localtax2_tx		= $objp->localtax2_tx;
1364
                        $line->subprice         = $objp->subprice;
1365
                        $line->fk_remise_except = $objp->fk_remise_except;
1366
                        $line->remise_percent   = $objp->remise_percent;
1367
                        $line->price            = $objp->price;		// TODO deprecated
1368
1369
                        $line->info_bits        = $objp->info_bits;
1370
                        $line->total_ht         = $objp->total_ht;
1371
                        $line->total_tva        = $objp->total_tva;
1372
                        $line->total_localtax1	= $objp->total_localtax1;
1373
                        $line->total_localtax2	= $objp->total_localtax2;
1374
                        $line->total_ttc        = $objp->total_ttc;
1375
                          $line->fk_fournprice 	= $objp->fk_fournprice;
1376
                        $marginInfos			= getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
1377
                        $line->pa_ht 			= $marginInfos[0];
1378
                        $line->marge_tx			= $marginInfos[1];
1379
                        $line->marque_tx		= $marginInfos[2];
1380
                        $line->special_code     = $objp->special_code;
1381
                        $line->rang             = $objp->rang;
1382
1383
                        $line->fk_product       = $objp->fk_product;
1384
1385
                        $line->ref				= $objp->product_ref;		// TODO deprecated
1386
                        $line->product_ref		= $objp->product_ref;
1387
                        $line->libelle			= $objp->product_label;		// TODO deprecated
1388
                        $line->product_label	= $objp->product_label;
1389
                        $line->product_desc     = $objp->product_desc; 		// Description produit
1390
                        $line->fk_product_type  = $objp->fk_product_type;
1391
1392
                        $line->ref_fourn		= $objp->ref_produit_fourn;
1393
1394
                        // Multicurrency
1395
                        $line->fk_multicurrency 		= $objp->fk_multicurrency;
1396
                        $line->multicurrency_code 		= $objp->multicurrency_code;
1397
                        $line->multicurrency_subprice 	= $objp->multicurrency_subprice;
1398
                        $line->multicurrency_total_ht 	= $objp->multicurrency_total_ht;
1399
                        $line->multicurrency_total_tva 	= $objp->multicurrency_total_tva;
1400
                        $line->multicurrency_total_ttc 	= $objp->multicurrency_total_ttc;
1401
                        $line->fk_unit					= $objp->fk_unit;
1402
1403
                        $this->lines[$i]        = $line;
1404
1405
                        $i++;
1406
                    }
1407
                    $this->db->free($result);
1408
                }
1409
                else
1410
                {
1411
                    $this->error=$this->db->error();
1412
                    return -1;
1413
                }
1414
1415
                // Retreive all extrafield
1416
                // fetch optionals attributes and labels
1417
                $this->fetch_optionals();
1418
1419
                return 1;
1420
            }
1421
1422
            $this->error="Record Not Found";
1423
            return 0;
1424
        }
1425
        else
1426
        {
1427
            $this->error=$this->db->error();
1428
            return -1;
1429
        }
1430
    }
1431
1432
    /**
1433
     *  Set status to validated
1434
     *
1435
     *  @param	User	$user       Object user that validate
1436
     *  @param	int		$notrigger	1=Does not execute triggers, 0= execute triggers
1437
     *  @return int         		<0 if KO, >=0 if OK
1438
     */
1439
    public function valid($user, $notrigger = 0)
1440
    {
1441
        require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1442
1443
        global $conf,$langs;
1444
1445
        $error=0;
1446
        $now=dol_now();
1447
1448
        if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->supplier_proposal->creer))
1449
           || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->supplier_proposal->validate_advance)))
1450
        {
1451
            $this->db->begin();
1452
1453
            // Numbering module definition
1454
            $soc = new Societe($this->db);
1455
            $soc->fetch($this->socid);
1456
1457
            // Define new ref
1458
            if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life
1459
            {
1460
                $num = $this->getNextNumRef($soc);
1461
            }
1462
            else
1463
            {
1464
                $num = $this->ref;
1465
            }
1466
            $this->newref = $num;
1467
1468
            $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal";
1469
            $sql.= " SET ref = '".$this->db->escape($num)."',";
1470
            $sql.= " fk_statut = 1, date_valid='".$this->db->idate($now)."', fk_user_valid=".$user->id;
1471
            $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
1472
1473
            dol_syslog(get_class($this)."::valid", LOG_DEBUG);
1474
            $resql=$this->db->query($sql);
1475
            if (! $resql)
1476
            {
1477
                dol_print_error($this->db);
1478
                $error++;
1479
            }
1480
1481
               // Trigger calls
1482
            if (! $error && ! $notrigger)
1483
            {
1484
                // Call trigger
1485
                $result=$this->call_trigger('SUPPLIER_PROPOSAL_VALIDATE', $user);
1486
                if ($result < 0) { $error++; }
1487
                // End call triggers
1488
            }
1489
1490
            if (! $error)
1491
            {
1492
                $this->oldref = $this->ref;
1493
1494
                // Rename directory if dir was a temporary ref
1495
                if (preg_match('/^[\(]?PROV/i', $this->ref))
1496
                {
1497
                	// Now we rename also files into index
1498
                	$sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref)+1).")), filepath = 'supplier_proposal/".$this->db->escape($this->newref)."'";
1499
                	$sql.= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'supplier_proposal/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1500
                	$resql = $this->db->query($sql);
1501
                	if (! $resql) { $error++; $this->error = $this->db->lasterror(); }
1502
1503
                	// We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1504
                	$oldref = dol_sanitizeFileName($this->ref);
1505
                    $newref = dol_sanitizeFileName($num);
1506
                    $dirsource = $conf->supplier_proposal->dir_output.'/'.$oldref;
1507
                    $dirdest = $conf->supplier_proposal->dir_output.'/'.$newref;
1508
                    if (! $error && file_exists($dirsource))
1509
                    {
1510
                        dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
1511
                        if (@rename($dirsource, $dirdest))
1512
                        {
1513
                            dol_syslog("Rename ok");
1514
                            // Rename docs starting with $oldref with $newref
1515
                            $listoffiles=dol_dir_list($conf->supplier_proposal->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
1516
                            foreach($listoffiles as $fileentry)
1517
                            {
1518
                                $dirsource=$fileentry['name'];
1519
                                $dirdest=preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1520
                                $dirsource=$fileentry['path'].'/'.$dirsource;
1521
                                $dirdest=$fileentry['path'].'/'.$dirdest;
1522
                                @rename($dirsource, $dirdest);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rename(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

1522
                                /** @scrutinizer ignore-unhandled */ @rename($dirsource, $dirdest);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1523
                            }
1524
                        }
1525
                    }
1526
                }
1527
1528
                $this->ref=$num;
1529
                $this->brouillon=0;
1530
                $this->statut = 1;
1531
                $this->user_valid_id=$user->id;
1532
                $this->datev=$now;
1 ignored issue
show
Deprecated Code introduced by
The property SupplierProposal::$datev has been deprecated. ( Ignorable by Annotation )

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

1532
                /** @scrutinizer ignore-deprecated */ $this->datev=$now;
Loading history...
1533
1534
                $this->db->commit();
1535
                return 1;
1536
            }
1537
            else
1538
            {
1539
                $this->db->rollback();
1540
                return -1;
1541
            }
1542
        }
1543
        else
1544
        {
1545
            dol_syslog("You don't have permission to validate supplier proposal", LOG_WARNING);
1546
            return -2;
1547
        }
1548
    }
1549
1550
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1551
    /**
1552
     *	Set delivery date
1553
     *
1554
     *	@param      User 		$user        		Object user that modify
1555
     *	@param      int			$date_livraison     Delivery date
1556
     *	@return     int         					<0 if ko, >0 if ok
1557
     */
1558
    public function set_date_livraison($user, $date_livraison)
1559
    {
1560
        // phpcs:enable
1561
        if (! empty($user->rights->supplier_proposal->creer))
1562
        {
1563
            $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal ";
1564
            $sql.= " SET date_livraison = ".($date_livraison!=''?"'".$this->db->idate($date_livraison)."'":'null');
1565
            $sql.= " WHERE rowid = ".$this->id;
1566
1567
            if ($this->db->query($sql))
1568
            {
1569
                $this->date_livraison = $date_livraison;
1570
                return 1;
1571
            }
1572
            else
1573
            {
1574
                $this->error=$this->db->error();
1575
                dol_syslog(get_class($this)."::set_date_livraison Erreur SQL");
1576
                return -1;
1577
            }
1578
        }
1579
    }
1580
1581
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1582
    /**
1583
     *	Set an overall discount on the proposal
1584
     *
1585
     *	@param      User	$user       Object user that modify
1586
     *	@param      double	$remise      Amount discount
1587
     *	@return     int         		<0 if ko, >0 if ok
1588
     */
1589
    public function set_remise_percent($user, $remise)
1590
    {
1591
        // phpcs:enable
1592
        $remise=trim($remise)?trim($remise):0;
1593
1594
        if (! empty($user->rights->supplier_proposal->creer))
1595
        {
1596
            $remise = price2num($remise);
1597
1598
            $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal SET remise_percent = ".$remise;
1599
            $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
1600
1601
            if ($this->db->query($sql) )
1602
            {
1603
                $this->remise_percent = $remise;
1604
                $this->update_price(1);
1605
                return 1;
1606
            }
1607
            else
1608
            {
1609
                $this->error=$this->db->error();
1610
                return -1;
1611
            }
1612
        }
1613
    }
1614
1615
1616
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1617
    /**
1618
     *	Set an absolute overall discount on the proposal
1619
     *
1620
     *	@param      User	$user        Object user that modify
1621
     *	@param      double	$remise      Amount discount
1622
     *	@return     int         		<0 if ko, >0 if ok
1623
     */
1624
    public function set_remise_absolue($user, $remise)
1625
    {
1626
        // phpcs:enable
1627
        $remise=trim($remise)?trim($remise):0;
1628
1629
        if (! empty($user->rights->supplier_proposal->creer))
1630
        {
1631
            $remise = price2num($remise);
1632
1633
            $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal ";
1634
            $sql.= " SET remise_absolue = ".$remise;
1635
            $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
1636
1637
            if ($this->db->query($sql) )
1638
            {
1639
                $this->remise_absolue = $remise;
1640
                $this->update_price(1);
1641
                return 1;
1642
            }
1643
            else
1644
            {
1645
                $this->error=$this->db->error();
1646
                return -1;
1647
            }
1648
        }
1649
    }
1650
1651
1652
1653
    /**
1654
     *	Reopen the commercial proposal
1655
     *
1656
     *	@param      User	$user		Object user that close
1657
     *	@param      int		$statut		Statut
1658
     *	@param      string	$note		Comment
1659
     *  @param		int		$notrigger	1=Does not execute triggers, 0= execute triggers
1660
     *	@return     int         		<0 if KO, >0 if OK
1661
     */
1662
    public function reopen($user, $statut, $note = '', $notrigger = 0)
1663
    {
1664
        global $langs,$conf;
1665
1666
        $this->statut = $statut;
1667
        $error=0;
1668
1669
        $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal";
1670
        $sql.= " SET fk_statut = ".$this->statut.",";
1671
        if (! empty($note)) $sql.= " note_private = '".$this->db->escape($note)."',";
1672
        $sql.= " date_cloture=NULL, fk_user_cloture=NULL";
1673
        $sql.= " WHERE rowid = ".$this->id;
1674
1675
        $this->db->begin();
1676
1677
        dol_syslog(get_class($this)."::reopen", LOG_DEBUG);
1678
        $resql = $this->db->query($sql);
1679
        if (! $resql) {
1680
            $error++; $this->errors[]="Error ".$this->db->lasterror();
1681
        }
1682
        if (! $error)
1683
        {
1684
            if (! $notrigger)
1685
            {
1686
                // Call trigger
1687
                $result=$this->call_trigger('SUPPLIER_PROPOSAL_REOPEN', $user);
1688
                if ($result < 0) { $error++; }
1689
                // End call triggers
1690
            }
1691
        }
1692
1693
        // Commit or rollback
1694
        if ($error)
1695
        {
1696
            if (!empty($this->errors))
1697
            {
1698
                foreach($this->errors as $errmsg)
1699
                {
1700
                    dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
1701
                    $this->error.=($this->error?', '.$errmsg:$errmsg);
1702
                }
1703
            }
1704
            $this->db->rollback();
1705
            return -1*$error;
1706
        }
1707
        else
1708
        {
1709
            $this->db->commit();
1710
            return 1;
1711
        }
1712
    }
1713
1714
1715
    /**
1716
     *	Close the askprice
1717
     *
1718
     *	@param      User	$user		Object user that close
1719
     *	@param      int		$statut		Statut
1720
     *	@param      string	$note		Comment
1721
     *	@return     int         		<0 if KO, >0 if OK
1722
     */
1723
    public function cloture($user, $statut, $note)
1724
    {
1725
        global $langs,$conf;
1726
1727
        $this->statut = $statut;
1728
        $error=0;
1729
        $now=dol_now();
1730
1731
        $this->db->begin();
1732
1733
        $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal";
1734
        $sql.= " SET fk_statut = ".$statut.", note_private = '".$this->db->escape($note)."', date_cloture='".$this->db->idate($now)."', fk_user_cloture=".$user->id;
1735
        $sql.= " WHERE rowid = ".$this->id;
1736
1737
        $resql=$this->db->query($sql);
1738
        if ($resql)
1739
        {
1740
            $modelpdf=$conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_CLOSED?$conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_CLOSED:$this->modelpdf;
1741
            $trigger_name='SUPPLIER_PROPOSAL_CLOSE_REFUSED';
1742
1743
            if ($statut == 2)
1744
            {
1745
                $trigger_name='SUPPLIER_PROPOSAL_CLOSE_SIGNED';
1746
                $modelpdf=$conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_TOBILL?$conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_TOBILL:$this->modelpdf;
1747
1748
                if (! empty($conf->global->SUPPLIER_PROPOSAL_UPDATE_PRICE_ON_SUPPlIER_PROPOSAL))     // TODO This option was not tested correctly. Error if product ref does not exists
1749
                {
1750
                    $result = $this->updateOrCreatePriceFournisseur($user);
1751
                }
1752
            }
1753
            if ($statut == 4)
1754
            {
1755
                $trigger_name='SUPPLIER_PROPOSAL_CLASSIFY_BILLED';
1756
            }
1757
1758
            if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
1759
            {
1760
                 // Define output language
1761
                  $outputlangs = $langs;
1762
                   if (! empty($conf->global->MAIN_MULTILANGS))
1763
                   {
1764
                       $outputlangs = new Translate("", $conf);
1765
                       $newlang=(GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $this->thirdparty->default_lang);
1766
                       $outputlangs->setDefaultLang($newlang);
1767
                   }
1768
                   //$ret=$object->fetch($id);    // Reload to get new records
1769
                   $this->generateDocument($modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $hidedetails seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $hidedesc seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $hideref seems to be never defined.
Loading history...
1770
            }
1771
1772
            // Call trigger
1773
            $result=$this->call_trigger($trigger_name, $user);
1774
            if ($result < 0) { $error++; }
1775
            // End call triggers
1776
1777
            if ( ! $error )
1778
            {
1779
                $this->db->commit();
1780
                return 1;
1781
            }
1782
            else
1783
            {
1784
                $this->db->rollback();
1785
                return -1;
1786
            }
1787
        }
1788
        else
1789
        {
1790
            $this->error=$this->db->lasterror();
1791
            $this->errors[]=$this->db->lasterror();
1792
            $this->db->rollback();
1793
            return -1;
1794
        }
1795
    }
1796
1797
    /**
1798
     *	Add or update supplier price according to result of proposal
1799
     *
1800
     *	@param     User	    $user       Object user
1801
     *  @return    int                  > 0 if OK
1802
     */
1803
    public function updateOrCreatePriceFournisseur($user)
1804
    {
1805
        $productsupplier = new ProductFournisseur($this->db);
1806
1807
        dol_syslog(get_class($this)."::updateOrCreatePriceFournisseur", LOG_DEBUG);
1808
        foreach ($this->lines as $product)
1809
        {
1810
            if ($product->subprice <= 0) continue;
1811
1812
            $idProductFourn = $productsupplier->find_min_price_product_fournisseur($product->fk_product, $product->qty);
1813
            $res = $productsupplier->fetch($idProductFourn);
1814
1815
            if ($productsupplier->id) {
1816
                if ($productsupplier->fourn_qty == $product->qty) {
1817
                    $this->updatePriceFournisseur($productsupplier->product_fourn_price_id, $product, $user);
1818
                } else {
1819
                    $this->createPriceFournisseur($product, $user);
1820
                }
1821
            } else {
1822
                $this->createPriceFournisseur($product, $user);
1823
            }
1824
        }
1825
1826
        return 1;
1827
    }
1828
1829
    /**
1830
     *	Upate ProductFournisseur
1831
     *
1832
     * 	@param		int 	$idProductFournPrice	id of llx_product_fournisseur_price
1833
     * 	@param		Product $product				contain informations to update
1834
     *	@param      User	$user					Object user
1835
     *	@return     int         					<0 if KO, >0 if OK
1836
     */
1837
    public function updatePriceFournisseur($idProductFournPrice, $product, $user)
1838
    {
1839
        $price=price2num($product->subprice*$product->qty, 'MU');
1840
        $unitPrice = price2num($product->subprice, 'MU');
1841
1842
        $sql = 'UPDATE '.MAIN_DB_PREFIX.'product_fournisseur_price SET '.(!empty($product->ref_fourn) ? 'ref_fourn = "'.$product->ref_fourn.'", ' : '').' price ='.$price.', unitprice ='.$unitPrice.' WHERE rowid = '.$idProductFournPrice;
1 ignored issue
show
Deprecated Code introduced by
The property Product::$ref_fourn has been deprecated. ( Ignorable by Annotation )

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

1842
        $sql = 'UPDATE '.MAIN_DB_PREFIX.'product_fournisseur_price SET '.(!empty(/** @scrutinizer ignore-deprecated */ $product->ref_fourn) ? 'ref_fourn = "'.$product->ref_fourn.'", ' : '').' price ='.$price.', unitprice ='.$unitPrice.' WHERE rowid = '.$idProductFournPrice;
Loading history...
1843
1844
        $resql = $this->db->query($sql);
1845
        if (!$resql) {
1846
            $this->error=$this->db->error();
1847
            $this->db->rollback();
1848
            return -1;
1849
        }
1850
    }
1851
1852
     /**
1853
     *	Create ProductFournisseur
1854
     *
1855
     *	@param		Product 	$product	Object Product
1856
     *	@param      User		$user		Object user
1857
     *	@return     int         			<0 if KO, >0 if OK
1858
     */
1859
    public function createPriceFournisseur($product, $user)
1860
    {
1861
        $price=price2num($product->subprice*$product->qty, 'MU');
1862
        $qty=price2num($product->qty);
1863
        $unitPrice = price2num($product->subprice, 'MU');
1864
        $now=dol_now();
1865
1866
        $values = array(
1867
            "'".$this->db->idate($now)."'",
1868
            $product->fk_product,
1869
            $this->thirdparty->id,
1870
            "'".$product->ref_fourn."'",
1 ignored issue
show
Deprecated Code introduced by
The property Product::$ref_fourn has been deprecated. ( Ignorable by Annotation )

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

1870
            "'"./** @scrutinizer ignore-deprecated */ $product->ref_fourn."'",
Loading history...
1871
            $price,
1872
            $qty,
1873
            $unitPrice,
1874
            $product->tva_tx,
1875
            $user->id
1876
        );
1877
1878
        $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'product_fournisseur_price ';
1879
        $sql .= '(datec, fk_product, fk_soc, ref_fourn, price, quantity, unitprice, tva_tx, fk_user) VALUES ('.implode(',', $values).')';
1880
1881
        $resql = $this->db->query($sql);
1882
        if (!$resql) {
1883
            $this->error=$this->db->error();
1884
            $this->db->rollback();
1885
            return -1;
1886
        }
1887
    }
1888
1889
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1890
    /**
1891
     *  Set draft status
1892
     *
1893
     *	@param		User	$user		Object user that modify
1894
     *	@return		int					<0 if KO, >0 if OK
1895
     */
1896
    public function setDraft($user)
1897
    {
1898
        // phpcs:enable
1899
        global $conf,$langs;
1900
1901
        $error = 0;
1902
1903
        if ($this->statut == self::STATUS_DRAFT)
1904
        {
1905
            dol_syslog(get_class($this)."::setDraft already draft status", LOG_WARNING);
1906
            return 0;
1907
        }
1908
1909
        $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal";
1910
        $sql.= " SET fk_statut = ".self::STATUS_DRAFT;
1911
        $sql.= " WHERE rowid = ".$this->id;
1912
1913
        if ($this->db->query($sql))
1914
        {
1915
            if (!$error) {
1916
                $this->oldcopy = clone $this;
1917
            }
1918
1919
            if (!$error) {
1920
                // Call trigger
1921
                $result=$this->call_trigger('SUPPLIER_PROPOSAL_UNVALIDATE', $user);
1922
                if ($result < 0) $error++;
1923
            }
1924
1925
            if (!$error) {
1926
                $this->statut=self::STATUS_DRAFT;
1927
                $this->brouillon = 1;
1928
                $this->db->commit();
1929
                return 1;
1930
            } else {
1931
                $this->db->rollback();
1932
                return -1;
1933
            }
1934
        }
1935
        else
1936
        {
1937
            return -1;
1938
        }
1939
    }
1940
1941
1942
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1943
    /**
1944
     *    Return list of askprice (eventually filtered on user) into an array
1945
     *
1946
     *    @param	int		$shortlist			0=Return array[id]=ref, 1=Return array[](id=>id,ref=>ref,name=>name)
1947
     *    @param	int		$draft				0=not draft, 1=draft
1948
     *    @param	int		$notcurrentuser		0=all user, 1=not current user
1949
     *    @param    int		$socid				Id third pary
1950
     *    @param    int		$limit				For pagination
1951
     *    @param    int		$offset				For pagination
1952
     *    @param    string	$sortfield			Sort criteria
1953
     *    @param    string	$sortorder			Sort order
1954
     *    @return	int		       				-1 if KO, array with result if OK
1955
     */
1956
    public function liste_array($shortlist = 0, $draft = 0, $notcurrentuser = 0, $socid = 0, $limit = 0, $offset = 0, $sortfield = 'p.datec', $sortorder = 'DESC')
1957
    {
1958
        // phpcs:enable
1959
        global $conf,$user;
1960
1961
        $ga = array();
1962
1963
        $sql = "SELECT s.rowid, s.nom as name, s.client,";
1964
        $sql.= " p.rowid as supplier_proposalid, p.fk_statut, p.total_ht, p.ref, p.remise, ";
1965
        $sql.= " p.datep as dp, p.fin_validite as datelimite";
1966
        if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", sc.fk_soc, sc.fk_user";
1967
        $sql.= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."supplier_proposal as p, ".MAIN_DB_PREFIX."c_propalst as c";
1968
        if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
1969
        $sql.= " WHERE p.entity IN (".getEntity('supplier_proposal').")";
1970
        $sql.= " AND p.fk_soc = s.rowid";
1971
        $sql.= " AND p.fk_statut = c.id";
1972
        if (! $user->rights->societe->client->voir && ! $socid) //restriction
1973
        {
1974
            $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id;
1975
        }
1976
        if ($socid) $sql.= " AND s.rowid = ".$socid;
1977
        if ($draft)	$sql.= " AND p.fk_statut = 0";
1978
        if ($notcurrentuser > 0) $sql.= " AND p.fk_user_author <> ".$user->id;
1979
        $sql.= $this->db->order($sortfield, $sortorder);
1980
        $sql.= $this->db->plimit($limit, $offset);
1981
1982
        $result=$this->db->query($sql);
1983
        if ($result)
1984
        {
1985
            $num = $this->db->num_rows($result);
1986
            if ($num)
1987
            {
1988
                $i = 0;
1989
                while ($i < $num)
1990
                {
1991
                    $obj = $this->db->fetch_object($result);
1992
1993
                    if ($shortlist == 1)
1994
                    {
1995
                        $ga[$obj->supplier_proposalid] = $obj->ref;
1996
                    }
1997
                    elseif ($shortlist == 2)
1998
                    {
1999
                        $ga[$obj->supplier_proposalid] = $obj->ref.' ('.$obj->name.')';
2000
                    }
2001
                    else
2002
                    {
2003
                        $ga[$i]['id']	= $obj->supplier_proposalid;
2004
                        $ga[$i]['ref'] 	= $obj->ref;
2005
                        $ga[$i]['name'] = $obj->name;
2006
                    }
2007
2008
                    $i++;
2009
                }
2010
            }
2011
            return $ga;
2012
        }
2013
        else
2014
        {
2015
            dol_print_error($this->db);
2016
            return -1;
2017
        }
2018
    }
2019
2020
    /**
2021
     *	Delete askprice
2022
     *
2023
     *	@param	User	$user        	Object user that delete
2024
     *	@param	int		$notrigger		1=Does not execute triggers, 0= execute triggers
2025
     *	@return	int						1 if ok, otherwise if error
2026
     */
2027
    public function delete($user, $notrigger = 0)
2028
    {
2029
        global $conf,$langs;
2030
        require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2031
2032
        $error=0;
2033
2034
        $this->db->begin();
2035
2036
        if (! $notrigger)
2037
        {
2038
            // Call trigger
2039
            $result=$this->call_trigger('SUPPLIER_PROPOSAL_DELETE', $user);
2040
            if ($result < 0) { $error++; }
2041
            // End call triggers
2042
        }
2043
2044
        if (! $error)
2045
        {
2046
            $sql = "DELETE FROM ".MAIN_DB_PREFIX."supplier_proposaldet WHERE fk_supplier_proposal = ".$this->id;
2047
            if ($this->db->query($sql))
2048
            {
2049
                $sql = "DELETE FROM ".MAIN_DB_PREFIX."supplier_proposal WHERE rowid = ".$this->id;
2050
                if ($this->db->query($sql))
2051
                {
2052
                    // Delete linked object
2053
                    $res = $this->deleteObjectLinked();
2054
                    if ($res < 0) $error++;
2055
2056
                    if (! $error)
2057
                    {
2058
                        // We remove directory
2059
                        $ref = dol_sanitizeFileName($this->ref);
2060
                        if ($conf->supplier_proposal->dir_output && !empty($this->ref))
2061
                        {
2062
                            $dir = $conf->supplier_proposal->dir_output . "/" . $ref ;
2063
                            $file = $dir . "/" . $ref . ".pdf";
2064
                            if (file_exists($file))
2065
                            {
2066
                                dol_delete_preview($this);
2067
2068
                                if (! dol_delete_file($file, 0, 0, 0, $this)) // For triggers
2069
                                {
2070
                                    $this->error='ErrorFailToDeleteFile';
2071
                                    $this->errors=array('ErrorFailToDeleteFile');
2072
                                    $this->db->rollback();
2073
                                    return 0;
2074
                                }
2075
                            }
2076
                            if (file_exists($dir))
2077
                            {
2078
                                $res=@dol_delete_dir_recursive($dir);
2079
                                if (! $res)
2080
                                {
2081
                                    $this->error='ErrorFailToDeleteDir';
2082
                                    $this->errors=array('ErrorFailToDeleteDir');
2083
                                    $this->db->rollback();
2084
                                    return 0;
2085
                                }
2086
                            }
2087
                        }
2088
                    }
2089
2090
                    // Removed extrafields
2091
                    if (! $error)
2092
                    {
2093
                        if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
2094
                        {
2095
                            $result=$this->deleteExtraFields();
2096
                            if ($result < 0)
2097
                            {
2098
                                $error++;
2099
                                $errorflag=-4;
2100
                                dol_syslog(get_class($this)."::delete erreur ".$errorflag." ".$this->error, LOG_ERR);
2101
                            }
2102
                        }
2103
                    }
2104
2105
                    if (! $error)
2106
                    {
2107
                        dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
2108
                        $this->db->commit();
2109
                        return 1;
2110
                    }
2111
                    else
2112
                    {
2113
                        $this->error=$this->db->lasterror();
2114
                        $this->db->rollback();
2115
                        return 0;
2116
                    }
2117
                }
2118
                else
2119
                {
2120
                    $this->error=$this->db->lasterror();
2121
                    $this->db->rollback();
2122
                    return -3;
2123
                }
2124
            }
2125
            else
2126
            {
2127
                $this->error=$this->db->lasterror();
2128
                $this->db->rollback();
2129
                return -2;
2130
            }
2131
        }
2132
        else
2133
        {
2134
            $this->db->rollback();
2135
            return -1;
2136
        }
2137
    }
2138
2139
    /**
2140
     *	Object SupplierProposal Information
2141
     *
2142
     * 	@param	int		$id		Proposal id
2143
     *  @return	void
2144
     */
2145
    public function info($id)
2146
    {
2147
        $sql = "SELECT c.rowid, ";
2148
        $sql.= " c.datec, c.date_valid as datev, c.date_cloture as dateo,";
2149
        $sql.= " c.fk_user_author, c.fk_user_valid, c.fk_user_cloture";
2150
        $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposal as c";
2151
        $sql.= " WHERE c.rowid = ".$id;
2152
2153
        $result = $this->db->query($sql);
2154
2155
        if ($result)
2156
        {
2157
            if ($this->db->num_rows($result))
2158
            {
2159
                $obj = $this->db->fetch_object($result);
2160
2161
                $this->id                = $obj->rowid;
2162
2163
                $this->date_creation     = $this->db->jdate($obj->datec);
2164
                $this->date_validation   = $this->db->jdate($obj->datev);
2165
                $this->date_cloture      = $this->db->jdate($obj->dateo);
2166
2167
                $cuser = new User($this->db);
2168
                $cuser->fetch($obj->fk_user_author);
2169
                $this->user_creation     = $cuser;
2170
2171
                if ($obj->fk_user_valid)
2172
                {
2173
                    $vuser = new User($this->db);
2174
                    $vuser->fetch($obj->fk_user_valid);
2175
                    $this->user_validation     = $vuser;
2176
                }
2177
2178
                if ($obj->fk_user_cloture)
2179
                {
2180
                    $cluser = new User($this->db);
2181
                    $cluser->fetch($obj->fk_user_cloture);
2182
                    $this->user_cloture     = $cluser;
2183
                }
2184
            }
2185
            $this->db->free($result);
2186
        }
2187
        else
2188
        {
2189
            dol_print_error($this->db);
2190
        }
2191
    }
2192
2193
2194
    /**
2195
     *    	Return label of status of proposal (draft, validated, ...)
2196
     *
2197
     *    	@param      int			$mode        0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
2198
     *    	@return     string		Label
2199
     */
2200
    public function getLibStatut($mode = 0)
2201
    {
2202
        return $this->LibStatut($this->statut, $mode);
2203
    }
2204
2205
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2206
    /**
2207
     *  Return label of a status (draft, validated, ...)
2208
     *
2209
     *  @param      int			$statut		id statut
2210
     *  @param      int			$mode      	0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
2211
     *  @return     string      Label
2212
     */
2213
    public function LibStatut($statut, $mode = 1)
2214
    {
2215
        // phpcs:enable
2216
        // Init/load array of translation of status
2217
        if (empty($this->labelstatut) || empty($this->labelstatut_short))
2218
        {
2219
            global $langs;
2220
            $langs->load("supplier_proposal");
2221
            $this->labelstatut[0]=$langs->trans("SupplierProposalStatusDraft");
2222
            $this->labelstatut[1]=$langs->trans("SupplierProposalStatusValidated");
2223
            $this->labelstatut[2]=$langs->trans("SupplierProposalStatusSigned");
2224
            $this->labelstatut[3]=$langs->trans("SupplierProposalStatusNotSigned");
2225
            $this->labelstatut[4]=$langs->trans("SupplierProposalStatusClosed");
2226
            $this->labelstatut_short[0]=$langs->trans("SupplierProposalStatusDraftShort");
2227
            $this->labelstatut_short[1]=$langs->trans("Opened");
2228
            $this->labelstatut_short[2]=$langs->trans("SupplierProposalStatusSignedShort");
2229
            $this->labelstatut_short[3]=$langs->trans("SupplierProposalStatusNotSignedShort");
2230
            $this->labelstatut_short[4]=$langs->trans("SupplierProposalStatusClosedShort");
2231
        }
2232
2233
        $statuttrans='';
2234
        if ($statut==0) $statuttrans='statut0';
2235
        elseif ($statut==1) $statuttrans='statut1';
2236
        elseif ($statut==2) $statuttrans='statut3';
2237
        elseif ($statut==3) $statuttrans='statut5';
2238
        elseif ($statut==4) $statuttrans='statut6';
2239
2240
        if ($mode == 0)	return $this->labelstatut[$statut];
2241
        elseif ($mode == 1)	return $this->labelstatut_short[$statut];
2242
        elseif ($mode == 2)	return img_picto($this->labelstatut[$statut], $statuttrans).' '.$this->labelstatut_short[$statut];
2243
        elseif ($mode == 3)	return img_picto($this->labelstatut[$statut], $statuttrans);
2244
        elseif ($mode == 4)	return img_picto($this->labelstatut[$statut], $statuttrans).' '.$this->labelstatut[$statut];
2245
        elseif ($mode == 5)	return '<span class="hideonsmartphone">'.$this->labelstatut_short[$statut].' </span>'.img_picto($this->labelstatut[$statut], $statuttrans);
2246
        elseif ($mode == 6)	return '<span class="hideonsmartphone">'.$this->labelstatut[$statut].' </span>'.img_picto($this->labelstatut[$statut], $statuttrans);
2247
    }
2248
2249
2250
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2251
    /**
2252
     *      Load indicators for dashboard (this->nbtodo and this->nbtodolate)
2253
     *
2254
     *      @param          User	$user   Object user
2255
     *      @param          int		$mode   "opened" for askprice to close, "signed" for proposal to invoice
2256
     *      @return         int             <0 if KO, >0 if OK
2257
     */
2258
    public function load_board($user, $mode)
2259
    {
2260
        // phpcs:enable
2261
        global $conf, $user, $langs;
2262
2263
        $now=dol_now();
2264
2265
        $this->nbtodo=$this->nbtodolate=0;
2266
        $clause = " WHERE";
2267
2268
        $sql = "SELECT p.rowid, p.ref, p.datec as datec";
2269
        $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposal as p";
2270
        if (!$user->rights->societe->client->voir && !$user->socid)
2271
        {
2272
            $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc";
2273
            $sql.= " WHERE sc.fk_user = " .$user->id;
2274
            $clause = " AND";
2275
        }
2276
        $sql.= $clause." p.entity IN (".getEntity('supplier_proposal').")";
2277
        if ($mode == 'opened') $sql.= " AND p.fk_statut = 1";
2278
        if ($mode == 'signed') $sql.= " AND p.fk_statut = 2";
2279
        if ($user->socid) $sql.= " AND p.fk_soc = ".$user->socid;
2280
2281
        $resql=$this->db->query($sql);
2282
        if ($resql)
2283
        {
2284
            if ($mode == 'opened') {
2285
                $delay_warning=$conf->supplier_proposal->cloture->warning_delay;
2286
                $statut = self::STATUS_VALIDATED;
2287
                $label = $langs->trans("SupplierProposalsToClose");
2288
            }
2289
            if ($mode == 'signed') {
2290
                $delay_warning=$conf->supplier_proposal->facturation->warning_delay;
2291
                $statut = self::STATUS_SIGNED;
2292
                $label = $langs->trans("SupplierProposalsToProcess");      // May be billed or ordered
2293
            }
2294
2295
            $response = new WorkboardResponse();
2296
            $response->warning_delay = $delay_warning/60/60/24;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $delay_warning does not seem to be defined for all execution paths leading up to this point.
Loading history...
2297
            $response->label = $label;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $label does not seem to be defined for all execution paths leading up to this point.
Loading history...
2298
            $response->url = DOL_URL_ROOT.'/supplier_proposal/list.php?viewstatut='.$statut;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $statut does not seem to be defined for all execution paths leading up to this point.
Loading history...
2299
            $response->img = img_object('', "propal");
2300
2301
            // This assignment in condition is not a bug. It allows walking the results.
2302
            while ($obj=$this->db->fetch_object($resql))
2303
            {
2304
                $response->nbtodo++;
2305
                if ($mode == 'opened')
2306
                {
2307
                    $datelimit = $this->db->jdate($obj->datefin);
2308
                    if ($datelimit < ($now - $delay_warning))
2309
                    {
2310
                        $response->nbtodolate++;
2311
                    }
2312
                }
2313
                // TODO Definir regle des propales a facturer en retard
2314
                // if ($mode == 'signed' && ! count($this->FactureListeArray($obj->rowid))) $this->nbtodolate++;
2315
            }
2316
            return $response;
2317
        }
2318
        else
2319
        {
2320
            $this->error=$this->db->lasterror();
2321
            return -1;
2322
        }
2323
    }
2324
2325
2326
    /**
2327
     *  Initialise an instance with random values.
2328
     *  Used to build previews or test instances.
2329
     *	id must be 0 if object instance is a specimen.
2330
     *
2331
     *  @return	void
2332
     */
2333
    public function initAsSpecimen()
2334
    {
2335
        global $user,$langs,$conf;
2336
2337
        // Load array of products prodids
2338
        $num_prods = 0;
2339
        $prodids = array();
2340
        $sql = "SELECT rowid";
2341
        $sql.= " FROM ".MAIN_DB_PREFIX."product";
2342
        $sql.= " WHERE entity IN (".getEntity('product').")";
2343
        $resql = $this->db->query($sql);
2344
        if ($resql)
2345
        {
2346
            $num_prods = $this->db->num_rows($resql);
2347
            $i = 0;
2348
            while ($i < $num_prods)
2349
            {
2350
                $i++;
2351
                $row = $this->db->fetch_row($resql);
2352
                $prodids[$i] = $row[0];
2353
            }
2354
        }
2355
2356
        // Initialise parametres
2357
        $this->id=0;
2358
        $this->ref = 'SPECIMEN';
2359
        $this->specimen=1;
2360
        $this->socid = 1;
2361
        $this->date = time();
2362
        $this->cond_reglement_id   = 1;
2363
        $this->cond_reglement_code = 'RECEP';
2364
        $this->mode_reglement_id   = 7;
2365
        $this->mode_reglement_code = 'CHQ';
2366
        $this->note_public='This is a comment (public)';
2367
        $this->note_private='This is a comment (private)';
2368
        // Lines
2369
        $nbp = 5;
2370
        $xnbp = 0;
2371
        while ($xnbp < $nbp)
2372
        {
2373
            $line=new SupplierProposalLine($this->db);
2374
            $line->desc=$langs->trans("Description")." ".$xnbp;
2375
            $line->qty=1;
2376
            $line->subprice=100;
2377
            $line->price=100;
1 ignored issue
show
Deprecated Code introduced by
The property SupplierProposalLine::$price has been deprecated. ( Ignorable by Annotation )

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

2377
            /** @scrutinizer ignore-deprecated */ $line->price=100;
Loading history...
2378
            $line->tva_tx=19.6;
2379
            $line->localtax1_tx=0;
2380
            $line->localtax2_tx=0;
2381
            if ($xnbp == 2)
2382
            {
2383
                $line->total_ht=50;
2384
                $line->total_ttc=59.8;
2385
                $line->total_tva=9.8;
2386
                $line->remise_percent=50;
2387
            }
2388
            else
2389
            {
2390
                $line->total_ht=100;
2391
                $line->total_ttc=119.6;
2392
                $line->total_tva=19.6;
2393
                $line->remise_percent=00;
2394
            }
2395
2396
            if ($num_prods > 0)
2397
            {
2398
                $prodid = mt_rand(1, $num_prods);
2399
                $line->fk_product=$prodids[$prodid];
2400
            }
2401
2402
            $this->lines[$xnbp]=$line;
2403
2404
            $this->total_ht       += $line->total_ht;
2405
            $this->total_tva      += $line->total_tva;
2406
            $this->total_ttc      += $line->total_ttc;
2407
2408
            $xnbp++;
2409
        }
2410
    }
2411
2412
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2413
    /**
2414
     *      Charge indicateurs this->nb de tableau de bord
2415
     *
2416
     *      @return     int         <0 if ko, >0 if ok
2417
     */
2418
    public function load_state_board()
2419
    {
2420
        // phpcs:enable
2421
        global $conf, $user;
2422
2423
        $this->nb=array();
2424
        $clause = "WHERE";
2425
2426
        $sql = "SELECT count(p.rowid) as nb";
2427
        $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposal as p";
2428
        $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
2429
        if (!$user->rights->societe->client->voir && !$user->socid)
2430
        {
2431
            $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
2432
            $sql.= " WHERE sc.fk_user = " .$user->id;
2433
            $clause = "AND";
2434
        }
2435
        $sql.= " ".$clause." p.entity IN (".getEntity('supplier_proposal').")";
2436
2437
        $resql=$this->db->query($sql);
2438
        if ($resql)
2439
        {
2440
            // This assignment in condition is not a bug. It allows walking the results.
2441
            while ($obj=$this->db->fetch_object($resql))
2442
            {
2443
                $this->nb["askprice"]=$obj->nb;
2444
            }
2445
            $this->db->free($resql);
2446
            return 1;
2447
        }
2448
        else
2449
        {
2450
            dol_print_error($this->db);
2451
            $this->error=$this->db->lasterror();
2452
            return -1;
2453
        }
2454
    }
2455
2456
2457
    /**
2458
     *  Returns the reference to the following non used Proposal used depending on the active numbering module
2459
     *  defined into SUPPLIER_PROPOSAL_ADDON
2460
     *
2461
     *  @param	Societe		$soc  	Object thirdparty
2462
     *  @return string      		Reference libre pour la propale
2463
     */
2464
    public function getNextNumRef($soc)
2465
    {
2466
        global $conf, $db, $langs;
2467
        $langs->load("supplier_proposal");
2468
2469
        if (! empty($conf->global->SUPPLIER_PROPOSAL_ADDON))
2470
        {
2471
            $mybool=false;
2472
2473
            $file = $conf->global->SUPPLIER_PROPOSAL_ADDON.".php";
2474
            $classname = $conf->global->SUPPLIER_PROPOSAL_ADDON;
2475
2476
            // Include file with class
2477
            $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2478
            foreach ($dirmodels as $reldir) {
2479
2480
                $dir = dol_buildpath($reldir."core/modules/supplier_proposal/");
2481
2482
                // Load file with numbering class (if found)
2483
                $mybool|=@include_once $dir.$file;
2484
            }
2485
2486
            if (! $mybool)
1 ignored issue
show
Bug Best Practice introduced by
The expression $mybool of type false|integer is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2487
            {
2488
                dol_print_error('', "Failed to include file ".$file);
2489
                return '';
2490
            }
2491
2492
            $obj = new $classname();
2493
            $numref = "";
2494
            $numref = $obj->getNextValue($soc, $this);
2495
2496
            if ($numref != "")
2497
            {
2498
                return $numref;
2499
            }
2500
            else
2501
            {
2502
                $this->error=$obj->error;
2503
                return "";
2504
            }
2505
        }
2506
        else
2507
        {
2508
            $langs->load("errors");
2509
            print $langs->trans("Error")." ".$langs->trans("ErrorModuleSetupNotComplete");
2510
            return "";
2511
        }
2512
    }
2513
2514
    /**
2515
     *	Return clicable link of object (with eventually picto)
2516
     *
2517
     *	@param      int		$withpicto					Add picto into link
2518
     *	@param      string	$option						Where point the link ('compta', 'expedition', 'document', ...)
2519
     *	@param      string	$get_params    				Parametres added to url
2520
     *  @param	    int   	$notooltip					1=Disable tooltip
2521
     *  @param      int     $save_lastsearch_value		-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
2522
     *	@return     string          					String with URL
2523
     */
2524
    public function getNomUrl($withpicto = 0, $option = '', $get_params = '', $notooltip = 0, $save_lastsearch_value = -1)
2525
    {
2526
        global $langs, $conf, $user;
2527
2528
        if (! empty($conf->dol_no_mouse_hover)) $notooltip=1;   // Force disable tooltips
2529
2530
        $url='';
2531
        $result='';
2532
2533
        $label='<u>'.$langs->trans("ShowSupplierProposal").'</u>';
2534
        if (! empty($this->ref))
2535
        $label.= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
2536
        if (! empty($this->ref_fourn))
2537
            $label.= '<br><b>'.$langs->trans('RefSupplier').':</b> '.$this->ref_fourn;
2538
        if (! empty($this->total_ht))
2539
            $label.= '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
2540
        if (! empty($this->total_tva))
2541
            $label.= '<br><b>' . $langs->trans('VAT') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
2542
        if (! empty($this->total_ttc))
2543
            $label.= '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
2544
        if ($option == '') {
2545
            $url = DOL_URL_ROOT.'/supplier_proposal/card.php?id='.$this->id. $get_params;
2546
        }
2547
        if ($option == 'document') {
2548
            $url = DOL_URL_ROOT.'/supplier_proposal/document.php?id='.$this->id. $get_params;
2549
        }
2550
2551
        if ($option !== 'nolink')
2552
        {
2553
            // Add param to save lastsearch_values or not
2554
            $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
2555
            if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
2556
            if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
2557
        }
2558
2559
        $linkclose='';
2560
        if (empty($notooltip) && $user->rights->propal->lire)
2561
        {
2562
            if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
2563
            {
2564
                $label=$langs->trans("ShowSupplierProposal");
2565
                $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
2566
            }
2567
            $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
2568
            $linkclose.=' class="classfortooltip"';
2569
        }
2570
2571
        $linkstart = '<a href="'.$url.'"';
2572
        $linkstart.=$linkclose.'>';
2573
        $linkend='</a>';
2574
2575
        $picto='supplier_proposal';
2576
2577
        $result .= $linkstart;
2578
        if ($withpicto) $result.=img_object(($notooltip?'':$label), $this->picto, ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
2579
        if ($withpicto != 2) $result.= $this->ref;
2580
        $result .= $linkend;
2581
2582
        return $result;
2583
    }
2584
2585
    /**
2586
     * 	Retrieve an array of supplier proposal lines
2587
     *
2588
     * 	@return int		>0 if OK, <0 if KO
2589
     */
2590
    public function getLinesArray()
2591
    {
2592
        // For other object, here we call fetch_lines. But fetch_lines does not exists on supplier proposal
2593
2594
        $sql = 'SELECT pt.rowid, pt.label as custom_label, pt.description, pt.fk_product, pt.fk_remise_except,';
2595
        $sql.= ' pt.qty, pt.tva_tx, pt.remise_percent, pt.subprice, pt.info_bits,';
2596
        $sql.= ' pt.total_ht, pt.total_tva, pt.total_ttc, pt.fk_product_fournisseur_price as fk_fournprice, pt.buy_price_ht as pa_ht, pt.special_code, pt.localtax1_tx, pt.localtax2_tx,';
2597
        $sql.= ' pt.product_type, pt.rang, pt.fk_parent_line,';
2598
        $sql.= ' p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid,';
2599
        $sql.= ' p.description as product_desc, pt.ref_fourn as ref_supplier,';
2600
        $sql.= ' pt.fk_multicurrency, pt.multicurrency_code, pt.multicurrency_subprice, pt.multicurrency_total_ht, pt.multicurrency_total_tva, pt.multicurrency_total_ttc, pt.fk_unit';
2601
        $sql.= ' FROM '.MAIN_DB_PREFIX.'supplier_proposaldet as pt';
2602
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pt.fk_product=p.rowid';
2603
        $sql.= ' WHERE pt.fk_supplier_proposal = '.$this->id;
2604
        $sql.= ' ORDER BY pt.rang ASC, pt.rowid';
2605
2606
        dol_syslog(get_class($this).'::getLinesArray', LOG_DEBUG);
2607
        $resql = $this->db->query($sql);
2608
        if ($resql)
2609
        {
2610
            $num = $this->db->num_rows($resql);
2611
            $i = 0;
2612
2613
            while ($i < $num)
2614
            {
2615
                $obj = $this->db->fetch_object($resql);
2616
2617
                $this->lines[$i]					= new SupplierProposalLine($this->db);
2618
                $this->lines[$i]->id				= $obj->rowid; // for backward compatibility
2619
                $this->lines[$i]->rowid				= $obj->rowid;
2620
                $this->lines[$i]->label 			= $obj->custom_label;
2621
                $this->lines[$i]->description 		= $obj->description;
2622
                $this->lines[$i]->fk_product		= $obj->fk_product;
2623
                $this->lines[$i]->ref				= $obj->ref;
2624
                $this->lines[$i]->product_label		= $obj->product_label;
2625
                $this->lines[$i]->product_desc		= $obj->product_desc;
2626
                $this->lines[$i]->fk_product_type	= $obj->fk_product_type;  // deprecated
2627
                $this->lines[$i]->product_type		= $obj->product_type;
2628
                $this->lines[$i]->qty				= $obj->qty;
2629
                $this->lines[$i]->subprice			= $obj->subprice;
2630
                $this->lines[$i]->fk_remise_except 	= $obj->fk_remise_except;
2631
                $this->lines[$i]->remise_percent	= $obj->remise_percent;
2632
                $this->lines[$i]->tva_tx			= $obj->tva_tx;
2633
                $this->lines[$i]->info_bits			= $obj->info_bits;
2634
                $this->lines[$i]->total_ht			= $obj->total_ht;
2635
                $this->lines[$i]->total_tva			= $obj->total_tva;
2636
                $this->lines[$i]->total_ttc			= $obj->total_ttc;
2637
                $this->lines[$i]->fk_fournprice		= $obj->fk_fournprice;
2638
                $marginInfos						= getMarginInfos($obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, $this->lines[$i]->fk_fournprice, $obj->pa_ht);
2639
                $this->lines[$i]->pa_ht				= $marginInfos[0];
2640
                $this->lines[$i]->marge_tx			= $marginInfos[1];
2641
                $this->lines[$i]->marque_tx			= $marginInfos[2];
2642
                $this->lines[$i]->fk_parent_line	= $obj->fk_parent_line;
2643
                $this->lines[$i]->special_code		= $obj->special_code;
2644
                $this->lines[$i]->rang				= $obj->rang;
2645
2646
                $this->lines[$i]->ref_fourn				= $obj->ref_supplier;	// deprecated
2647
                $this->lines[$i]->ref_supplier			= $obj->ref_supplier;
2648
2649
                // Multicurrency
2650
                $this->lines[$i]->fk_multicurrency 			= $obj->fk_multicurrency;
2651
                $this->lines[$i]->multicurrency_code 		= $obj->multicurrency_code;
2652
                $this->lines[$i]->multicurrency_subprice 	= $obj->multicurrency_subprice;
2653
                $this->lines[$i]->multicurrency_total_ht 	= $obj->multicurrency_total_ht;
2654
                $this->lines[$i]->multicurrency_total_tva 	= $obj->multicurrency_total_tva;
2655
                $this->lines[$i]->multicurrency_total_ttc 	= $obj->multicurrency_total_ttc;
2656
                $this->lines[$i]->fk_unit				 	= $obj->fk_unit;
2657
2658
                $i++;
2659
            }
2660
            $this->db->free($resql);
2661
2662
            return 1;
2663
        }
2664
        else
2665
        {
2666
            $this->error=$this->db->error();
2667
            return -1;
2668
        }
2669
    }
2670
2671
    /**
2672
     *  Create a document onto disk according to template module.
2673
     *
2674
     * 	@param	    string		$modele			Force model to use ('' to not force)
2675
     * 	@param		Translate	$outputlangs	Object langs to use for output
2676
     *  @param      int			$hidedetails    Hide details of lines
2677
     *  @param      int			$hidedesc       Hide description
2678
     *  @param      int			$hideref        Hide ref
2679
         *  @param   null|array  $moreparams     Array to provide more information
2680
     * 	@return     int         				0 if KO, 1 if OK
2681
     */
2682
    public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
2683
    {
2684
        global $conf, $langs;
2685
2686
        $langs->load("supplier_proposal");
2687
2688
        if (! dol_strlen($modele)) {
2689
2690
            $modele = 'aurore';
2691
2692
            if ($this->modelpdf) {
2693
                $modele = $this->modelpdf;
2694
            } elseif (! empty($conf->global->SUPPLIER_PROPOSAL_ADDON_PDF)) {
2695
                $modele = $conf->global->SUPPLIER_PROPOSAL_ADDON_PDF;
2696
            }
2697
        }
2698
2699
        $modelpath = "core/modules/supplier_proposal/doc/";
2700
2701
        return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2702
    }
2703
2704
2705
    /**
2706
     * Function used to replace a thirdparty id with another one.
2707
     *
2708
     * @param DoliDB $db Database handler
2709
     * @param int $origin_id Old thirdparty id
2710
     * @param int $dest_id New thirdparty id
2711
     * @return bool
2712
     */
2713
    public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
2714
    {
2715
        $tables = array(
2716
            'supplier_proposal'
2717
        );
2718
2719
        return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
2720
    }
2721
}
2722
2723
2724
/**
2725
 *	Class to manage supplier_proposal lines
2726
 */
2727
class SupplierProposalLine extends CommonObjectLine
2728
{
2729
    /**
2730
     * @var DoliDB Database handler.
2731
     */
2732
    public $db;
2733
2734
    /**
2735
     * @var string Error code (or message)
2736
     */
2737
    public $error='';
2738
2739
    /**
2740
     * @var string ID to identify managed object
2741
     */
2742
    public $element='supplier_proposaldet';
2743
2744
    /**
2745
     * @var string Name of table without prefix where object is stored
2746
     */
2747
    public $table_element='supplier_proposaldet';
2748
2749
    public $oldline;
2750
2751
    // From llx_supplier_proposaldet
2752
    public $rowid; // deprecated
2753
2754
    /**
2755
     * @var int ID
2756
     */
2757
    public $id;
2758
2759
    /**
2760
     * @var int ID
2761
     */
2762
    public $fk_supplier_proposal;
2763
2764
    /**
2765
     * @var int ID
2766
     */
2767
    public $fk_parent_line;
2768
2769
    public $desc;          	// Description ligne
2770
2771
    /**
2772
     * @var int ID
2773
     */
2774
    public $fk_product;		// Id produit predefini
2775
2776
    /**
2777
     * @deprecated
2778
     * @see $product_type
2779
     */
2780
    public $fk_product_type;
2781
    /**
2782
     * Product type
2783
     * @var int
2784
     * @see Product::TYPE_PRODUCT, Product::TYPE_SERVICE
2785
     */
2786
    public $product_type = Product::TYPE_PRODUCT;
2787
2788
    public $qty;
2789
    public $tva_tx;
2790
    public $subprice;
2791
    public $remise_percent;
2792
2793
    /**
2794
     * @var int ID
2795
     */
2796
    public $fk_remise_except;
2797
2798
    public $rang = 0;
2799
2800
    /**
2801
     * @var int ID
2802
     */
2803
    public $fk_fournprice;
2804
2805
    public $pa_ht;
2806
    public $marge_tx;
2807
    public $marque_tx;
2808
2809
    public $special_code;	// Tag for special lines (exlusive tags)
2810
    // 1: frais de port
2811
    // 2: ecotaxe
2812
    // 3: option line (when qty = 0)
2813
2814
    public $info_bits = 0;	// Liste d'options cumulables:
2815
    // Bit 0: 	0 si TVA normal - 1 si TVA NPR
2816
    // Bit 1:	0 ligne normale - 1 si ligne de remise fixe
2817
2818
    public $total_ht;			// Total HT  de la ligne toute quantite et incluant la remise ligne
2819
    public $total_tva;			// Total TVA  de la ligne toute quantite et incluant la remise ligne
2820
    public $total_ttc;			// Total TTC de la ligne toute quantite et incluant la remise ligne
2821
2822
    /**
2823
     * @deprecated
2824
     * @see remise_percent, fk_remise_except
2825
     */
2826
    public $remise;
2827
2828
    /**
2829
     * @deprecated
2830
     * @see subprice
2831
     */
2832
    public $price;
2833
2834
    // From llx_product
2835
    /**
2836
     * @deprecated
2837
     * @see product_ref
2838
     */
2839
    public $ref;
2840
2841
    /**
2842
     * Product reference
2843
     * @var string
2844
     */
2845
    public $product_ref;
2846
2847
    /**
2848
     * @deprecated
2849
     * @see $product_label
2850
     */
2851
    public $libelle;
2852
2853
    /**
2854
     *  Product label
2855
     * @var string
2856
     */
2857
    public $product_label;
2858
2859
    /**
2860
     * Product description
2861
     * @var string
2862
     */
2863
    public $product_desc;
2864
2865
    public $localtax1_tx;		// Local tax 1
2866
    public $localtax2_tx;		// Local tax 2
2867
    public $localtax1_type;	// Local tax 1 type
2868
    public $localtax2_type;	// Local tax 2 type
2869
    public $total_localtax1;  	// Line total local tax 1
2870
    public $total_localtax2;	// Line total local tax 2
2871
2872
    public $skip_update_total; // Skip update price total for special lines
2873
2874
    public $ref_fourn;
2875
    public $ref_supplier;
2876
2877
    // Multicurrency
2878
    /**
2879
     * @var int ID
2880
     */
2881
    public $fk_multicurrency;
2882
2883
    public $multicurrency_code;
2884
    public $multicurrency_subprice;
2885
    public $multicurrency_total_ht;
2886
    public $multicurrency_total_tva;
2887
    public $multicurrency_total_ttc;
2888
2889
    /**
2890
     * 	Class line Contructor
2891
     *
2892
     * 	@param	DoliDB	$db	Database handler
2893
     */
2894
    public function __construct($db)
2895
    {
2896
        $this->db= $db;
2897
    }
2898
2899
    /**
2900
     *	Retrieve the propal line object
2901
     *
2902
     *	@param	int		$rowid		Propal line id
2903
     *	@return	int					<0 if KO, >0 if OK
2904
     */
2905
    public function fetch($rowid)
2906
    {
2907
        $sql = 'SELECT pd.rowid, pd.fk_supplier_proposal, pd.fk_parent_line, pd.fk_product, pd.label as custom_label, pd.description, pd.price, pd.qty, pd.tva_tx,';
2908
        $sql.= ' pd.remise, pd.remise_percent, pd.fk_remise_except, pd.subprice,';
2909
        $sql.= ' pd.info_bits, pd.total_ht, pd.total_tva, pd.total_ttc, pd.fk_product_fournisseur_price as fk_fournprice, pd.buy_price_ht as pa_ht, pd.special_code, pd.rang,';
2910
        $sql.= ' pd.localtax1_tx, pd.localtax2_tx, pd.total_localtax1, pd.total_localtax2,';
2911
        $sql.= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,';
2912
        $sql.= ' pd.product_type, pd.ref_fourn as ref_produit_fourn,';
2913
        $sql.= ' pd.fk_multicurrency, pd.multicurrency_code, pd.multicurrency_subprice, pd.multicurrency_total_ht, pd.multicurrency_total_tva, pd.multicurrency_total_ttc, pd.fk_unit';
2914
        $sql.= ' FROM '.MAIN_DB_PREFIX.'supplier_proposaldet as pd';
2915
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pd.fk_product = p.rowid';
2916
        $sql.= ' WHERE pd.rowid = '.$rowid;
2917
2918
        $result = $this->db->query($sql);
2919
        if ($result)
2920
        {
2921
            $objp = $this->db->fetch_object($result);
2922
2923
            $this->rowid			= $objp->rowid; // deprecated
2924
            $this->id				= $objp->rowid;
2925
            $this->fk_supplier_proposal		= $objp->fk_supplier_proposal;
2926
            $this->fk_parent_line	= $objp->fk_parent_line;
2927
            $this->label			= $objp->custom_label;
2928
            $this->desc				= $objp->description;
2929
            $this->qty				= $objp->qty;
2930
            $this->price			= $objp->price;		// deprecated
2931
            $this->subprice			= $objp->subprice;
2932
            $this->tva_tx			= $objp->tva_tx;
2933
            $this->remise			= $objp->remise;
2934
            $this->remise_percent	= $objp->remise_percent;
2935
            $this->fk_remise_except = $objp->fk_remise_except;
2936
            $this->fk_product		= $objp->fk_product;
2937
            $this->info_bits		= $objp->info_bits;
2938
2939
            $this->total_ht			= $objp->total_ht;
2940
            $this->total_tva		= $objp->total_tva;
2941
            $this->total_ttc		= $objp->total_ttc;
2942
2943
            $this->fk_fournprice	= $objp->fk_fournprice;
2944
2945
            $marginInfos			= getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht);
2946
            $this->pa_ht			= $marginInfos[0];
2947
            $this->marge_tx			= $marginInfos[1];
2948
            $this->marque_tx		= $marginInfos[2];
2949
2950
            $this->special_code		= $objp->special_code;
2951
            $this->product_type		= $objp->product_type;
2952
            $this->rang				= $objp->rang;
2953
2954
            $this->ref				= $objp->product_ref;      // deprecated
2955
            $this->product_ref		= $objp->product_ref;
2956
            $this->libelle			= $objp->product_label;  // deprecated
2957
            $this->product_label	= $objp->product_label;
2958
            $this->product_desc		= $objp->product_desc;
2959
2960
            $this->ref_fourn		= $objp->ref_produit_forun;
2961
2962
            // Multicurrency
2963
            $this->fk_multicurrency 		= $objp->fk_multicurrency;
2964
            $this->multicurrency_code 		= $objp->multicurrency_code;
2965
            $this->multicurrency_subprice 	= $objp->multicurrency_subprice;
2966
            $this->multicurrency_total_ht 	= $objp->multicurrency_total_ht;
2967
            $this->multicurrency_total_tva 	= $objp->multicurrency_total_tva;
2968
            $this->multicurrency_total_ttc 	= $objp->multicurrency_total_ttc;
2969
            $this->fk_unit				 	= $objp->fk_unit;
2970
2971
            $this->db->free($result);
2972
        }
2973
        else
2974
        {
2975
            dol_print_error($this->db);
2976
        }
2977
    }
2978
2979
    /**
2980
     *  Insert object line propal in database
2981
     *
2982
     *	@param		int		$notrigger		1=Does not execute triggers, 0= execute triggers
2983
     *	@return		int						<0 if KO, >0 if OK
2984
     */
2985
    public function insert($notrigger = 0)
2986
    {
2987
        global $conf,$langs,$user;
2988
2989
        $error=0;
2990
2991
        dol_syslog(get_class($this)."::insert rang=".$this->rang);
2992
2993
        // Clean parameters
2994
        if (empty($this->tva_tx)) $this->tva_tx=0;
2995
        if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
2996
        if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
2997
        if (empty($this->localtax1_type)) $this->localtax1_type=0;
2998
        if (empty($this->localtax2_type)) $this->localtax2_type=0;
2999
        if (empty($this->total_localtax1)) $this->total_localtax1=0;
3000
        if (empty($this->total_localtax2)) $this->total_localtax2=0;
3001
        if (empty($this->rang)) $this->rang=0;
3002
        if (empty($this->remise)) $this->remise=0;
1 ignored issue
show
Deprecated Code introduced by
The property SupplierProposalLine::$remise has been deprecated. ( Ignorable by Annotation )

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

3002
        if (empty($this->remise)) /** @scrutinizer ignore-deprecated */ $this->remise=0;
Loading history...
3003
        if (empty($this->remise_percent)) $this->remise_percent=0;
3004
        if (empty($this->info_bits)) $this->info_bits=0;
3005
        if (empty($this->special_code)) $this->special_code=0;
3006
        if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
3007
        if (empty($this->fk_fournprice)) $this->fk_fournprice=0;
3008
        if (empty($this->fk_unit)) $this->fk_unit=0;
3009
        if (empty($this->subprice)) $this->subprice=0;
3010
3011
        if (empty($this->pa_ht)) $this->pa_ht=0;
3012
3013
        // if buy price not defined, define buyprice as configured in margin admin
3014
        if ($this->pa_ht == 0)
3015
        {
3016
            if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0)
3017
            {
3018
                return $result;
3019
            }
3020
            else
3021
            {
3022
                $this->pa_ht = $result;
3023
            }
3024
        }
3025
3026
        // Check parameters
3027
        if ($this->product_type < 0) return -1;
3028
3029
        $this->db->begin();
3030
3031
        // Insert line into database
3032
        $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'supplier_proposaldet';
3033
        $sql.= ' (fk_supplier_proposal, fk_parent_line, label, description, fk_product, product_type,';
3034
        $sql.= ' fk_remise_except, qty, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3035
        $sql.= ' subprice, remise_percent, ';
3036
        $sql.= ' info_bits, ';
3037
        $sql.= ' total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, fk_product_fournisseur_price, buy_price_ht, special_code, rang,';
3038
        $sql.= ' ref_fourn,';
3039
        $sql.= ' fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc, fk_unit)';
3040
        $sql.= " VALUES (".$this->fk_supplier_proposal.",";
3041
        $sql.= " ".($this->fk_parent_line>0?"'".$this->db->escape($this->fk_parent_line)."'":"null").",";
3042
        $sql.= " ".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null").",";
3043
        $sql.= " '".$this->db->escape($this->desc)."',";
3044
        $sql.= " ".($this->fk_product?"'".$this->db->escape($this->fk_product)."'":"null").",";
3045
        $sql.= " '".$this->db->escape($this->product_type)."',";
3046
        $sql.= " ".($this->fk_remise_except?"'".$this->db->escape($this->fk_remise_except)."'":"null").",";
3047
        $sql.= " ".price2num($this->qty).",";
3048
        $sql.= " ".price2num($this->tva_tx).",";
3049
        $sql.= " ".price2num($this->localtax1_tx).",";
3050
        $sql.= " ".price2num($this->localtax2_tx).",";
3051
        $sql.= " '".$this->db->escape($this->localtax1_type)."',";
3052
        $sql.= " '".$this->db->escape($this->localtax2_type)."',";
3053
        $sql.= " ".(!empty($this->subprice)?price2num($this->subprice):"null").",";
3054
        $sql.= " ".price2num($this->remise_percent).",";
3055
        $sql.= " ".(isset($this->info_bits)?"'".$this->db->escape($this->info_bits)."'":"null").",";
3056
        $sql.= " ".price2num($this->total_ht).",";
3057
        $sql.= " ".price2num($this->total_tva).",";
3058
        $sql.= " ".price2num($this->total_localtax1).",";
3059
        $sql.= " ".price2num($this->total_localtax2).",";
3060
        $sql.= " ".price2num($this->total_ttc).",";
3061
        $sql.= " ".(!empty($this->fk_fournprice)?"'".$this->db->escape($this->fk_fournprice)."'":"null").",";
3062
        $sql.= " ".(isset($this->pa_ht)?"'".price2num($this->pa_ht)."'":"null").",";
3063
        $sql.= ' '.$this->special_code.',';
3064
        $sql.= ' '.$this->rang.',';
3065
        $sql.= " '".$this->db->escape($this->ref_fourn)."'";
3066
        $sql.= ", ".($this->fk_multicurrency > 0?$this->fk_multicurrency:'null');
3067
        $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
3068
        $sql.= ", ".$this->multicurrency_subprice;
3069
        $sql.= ", ".$this->multicurrency_total_ht;
3070
        $sql.= ", ".$this->multicurrency_total_tva;
3071
        $sql.= ", ".$this->multicurrency_total_ttc;
3072
        $sql.= ", ".($this->fk_unit?$this->fk_unit:'null');
3073
        $sql.= ')';
3074
3075
        dol_syslog(get_class($this).'::insert', LOG_DEBUG);
3076
        $resql=$this->db->query($sql);
3077
        if ($resql)
3078
        {
3079
            $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'supplier_proposaldet');
3080
            $this->id=$this->rowid;
3081
3082
            if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
3083
            {
3084
                $result=$this->insertExtraFields();
3085
                if ($result < 0)
3086
                {
3087
                    $error++;
3088
                }
3089
            }
3090
3091
            if (! $error && ! $notrigger)
3092
            {
3093
                // Call trigger
3094
                $result=$this->call_trigger('LINESUPPLIER_PROPOSAL_INSERT', $user);
3095
                if ($result < 0)
3096
                {
3097
                    $this->db->rollback();
3098
                    return -1;
3099
                }
3100
                // End call triggers
3101
            }
3102
3103
            $this->db->commit();
3104
            return 1;
3105
        }
3106
        else
3107
        {
3108
            $this->error=$this->db->error()." sql=".$sql;
3109
            $this->db->rollback();
3110
            return -1;
3111
        }
3112
    }
3113
3114
    /**
3115
     * 	Delete line in database
3116
     *
3117
     *	@return	 int  <0 if ko, >0 if ok
3118
     */
3119
    public function delete()
3120
    {
3121
        global $conf,$langs,$user;
3122
3123
        $error=0;
3124
        $this->db->begin();
3125
3126
        $sql = "DELETE FROM ".MAIN_DB_PREFIX."supplier_proposaldet WHERE rowid = ".$this->rowid;
3127
        dol_syslog("SupplierProposalLine::delete", LOG_DEBUG);
3128
        if ($this->db->query($sql) )
3129
        {
3130
3131
            // Remove extrafields
3132
            if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used
3133
            {
3134
                $this->id=$this->rowid;
3135
                $result=$this->deleteExtraFields();
3136
                if ($result < 0)
3137
                {
3138
                    $error++;
3139
                    dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
3140
                }
3141
            }
3142
3143
            // Call trigger
3144
            $result=$this->call_trigger('LINESUPPLIER_PROPOSAL_DELETE', $user);
3145
            if ($result < 0)
3146
            {
3147
                $this->db->rollback();
3148
                return -1;
3149
            }
3150
            // End call triggers
3151
3152
            $this->db->commit();
3153
3154
            return 1;
3155
        }
3156
        else
3157
        {
3158
            $this->error=$this->db->error()." sql=".$sql;
3159
            $this->db->rollback();
3160
            return -1;
3161
        }
3162
    }
3163
3164
    /**
3165
     *	Update propal line object into DB
3166
     *
3167
     *	@param 	int		$notrigger	1=Does not execute triggers, 0= execute triggers
3168
     *	@return	int					<0 if ko, >0 if ok
3169
     */
3170
    public function update($notrigger = 0)
3171
    {
3172
        global $conf,$langs,$user;
3173
3174
        $error=0;
3175
3176
        // Clean parameters
3177
        if (empty($this->tva_tx)) $this->tva_tx=0;
3178
        if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
3179
        if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
3180
        if (empty($this->total_localtax1)) $this->total_localtax1=0;
3181
        if (empty($this->total_localtax2)) $this->total_localtax2=0;
3182
        if (empty($this->localtax1_type)) $this->localtax1_type=0;
3183
        if (empty($this->localtax2_type)) $this->localtax2_type=0;
3184
        if (empty($this->marque_tx)) $this->marque_tx=0;
3185
        if (empty($this->marge_tx)) $this->marge_tx=0;
3186
        if (empty($this->price)) $this->price=0;	// TODO A virer
1 ignored issue
show
Deprecated Code introduced by
The property SupplierProposalLine::$price has been deprecated. ( Ignorable by Annotation )

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

3186
        if (empty($this->price)) /** @scrutinizer ignore-deprecated */ $this->price=0;	// TODO A virer
Loading history...
3187
        if (empty($this->remise)) $this->remise=0;	// TODO A virer
1 ignored issue
show
Deprecated Code introduced by
The property SupplierProposalLine::$remise has been deprecated. ( Ignorable by Annotation )

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

3187
        if (empty(/** @scrutinizer ignore-deprecated */ $this->remise)) $this->remise=0;	// TODO A virer
Loading history...
3188
        if (empty($this->remise_percent)) $this->remise_percent=0;
3189
        if (empty($this->info_bits)) $this->info_bits=0;
3190
        if (empty($this->special_code)) $this->special_code=0;
3191
        if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
3192
        if (empty($this->fk_fournprice)) $this->fk_fournprice=0;
3193
        if (empty($this->fk_unit)) $this->fk_unit=0;
3194
        if (empty($this->subprice)) $this->subprice=0;
3195
3196
        if (empty($this->pa_ht)) $this->pa_ht=0;
3197
3198
        // if buy price not defined, define buyprice as configured in margin admin
3199
        if ($this->pa_ht == 0)
3200
        {
3201
            if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0)
3202
            {
3203
                return $result;
3204
            }
3205
            else
3206
            {
3207
                $this->pa_ht = $result;
3208
            }
3209
        }
3210
3211
        $this->db->begin();
3212
3213
        // Mise a jour ligne en base
3214
        $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposaldet SET";
3215
        $sql.= " description='".$this->db->escape($this->desc)."'";
3216
        $sql.= " , label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null");
3217
        $sql.= " , product_type=".$this->product_type;
3218
        $sql.= " , tva_tx='".price2num($this->tva_tx)."'";
3219
        $sql.= " , localtax1_tx=".price2num($this->localtax1_tx);
3220
        $sql.= " , localtax2_tx=".price2num($this->localtax2_tx);
3221
        $sql.= " , localtax1_type='".$this->db->escape($this->localtax1_type)."'";
3222
        $sql.= " , localtax2_type='".$this->db->escape($this->localtax2_type)."'";
3223
        $sql.= " , qty='".price2num($this->qty)."'";
3224
        $sql.= " , subprice=".price2num($this->subprice)."";
3225
        $sql.= " , remise_percent=".price2num($this->remise_percent)."";
3226
        $sql.= " , price=".price2num($this->price)."";					// TODO A virer
1 ignored issue
show
Deprecated Code introduced by
The property SupplierProposalLine::$price has been deprecated. ( Ignorable by Annotation )

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

3226
        $sql.= " , price=".price2num(/** @scrutinizer ignore-deprecated */ $this->price)."";					// TODO A virer
Loading history...
3227
        $sql.= " , remise=".price2num($this->remise)."";				// TODO A virer
1 ignored issue
show
Deprecated Code introduced by
The property SupplierProposalLine::$remise has been deprecated. ( Ignorable by Annotation )

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

3227
        $sql.= " , remise=".price2num(/** @scrutinizer ignore-deprecated */ $this->remise)."";				// TODO A virer
Loading history...
3228
        $sql.= " , info_bits='".$this->db->escape($this->info_bits)."'";
3229
        if (empty($this->skip_update_total))
3230
        {
3231
            $sql.= " , total_ht=".price2num($this->total_ht)."";
3232
            $sql.= " , total_tva=".price2num($this->total_tva)."";
3233
            $sql.= " , total_ttc=".price2num($this->total_ttc)."";
3234
            $sql.= " , total_localtax1=".price2num($this->total_localtax1)."";
3235
            $sql.= " , total_localtax2=".price2num($this->total_localtax2)."";
3236
        }
3237
        $sql.= " , fk_product_fournisseur_price=".(! empty($this->fk_fournprice)?"'".$this->db->escape($this->fk_fournprice)."'":"null");
3238
        $sql.= " , buy_price_ht=".price2num($this->pa_ht);
3239
        if (strlen($this->special_code)) $sql.= " , special_code=".$this->special_code;
3240
        $sql.= " , fk_parent_line=".($this->fk_parent_line>0?$this->fk_parent_line:"null");
3241
        if (! empty($this->rang)) $sql.= ", rang=".$this->rang;
3242
        $sql.= " , ref_fourn=".(! empty($this->ref_fourn)?"'".$this->db->escape($this->ref_fourn)."'":"null");
3243
        $sql.= " , fk_unit=".($this->fk_unit?$this->fk_unit:'null');
3244
3245
        // Multicurrency
3246
        $sql.= " , multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
3247
        $sql.= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
3248
        $sql.= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
3249
        $sql.= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
3250
3251
        $sql.= " WHERE rowid = ".$this->rowid;
3252
3253
        dol_syslog(get_class($this)."::update", LOG_DEBUG);
3254
        $resql=$this->db->query($sql);
3255
        if ($resql)
3256
        {
3257
            if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
3258
            {
3259
                $this->id=$this->rowid;
3260
                $result=$this->insertExtraFields();
3261
                if ($result < 0)
3262
                {
3263
                    $error++;
3264
                }
3265
            }
3266
3267
            if (! $error && ! $notrigger)
3268
            {
3269
                // Call trigger
3270
                $result=$this->call_trigger('LINESUPPLIER_PROPOSAL_UPDATE', $user);
3271
                if ($result < 0)
3272
                {
3273
                    $this->db->rollback();
3274
                    return -1;
3275
                }
3276
                // End call triggers
3277
            }
3278
3279
            $this->db->commit();
3280
            return 1;
3281
        }
3282
        else
3283
        {
3284
            $this->error=$this->db->error();
3285
            $this->db->rollback();
3286
            return -2;
3287
        }
3288
    }
3289
3290
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3291
    /**
3292
     *	Update DB line fields total_xxx
3293
     *	Used by migration
3294
     *
3295
     *	@return		int		<0 if ko, >0 if ok
3296
     */
3297
    public function update_total()
3298
    {
3299
        // phpcs:enable
3300
        $this->db->begin();
3301
3302
        // Mise a jour ligne en base
3303
        $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposaldet SET";
3304
        $sql.= " total_ht=".price2num($this->total_ht, 'MT')."";
3305
        $sql.= ",total_tva=".price2num($this->total_tva, 'MT')."";
3306
        $sql.= ",total_ttc=".price2num($this->total_ttc, 'MT')."";
3307
        $sql.= " WHERE rowid = ".$this->rowid;
3308
3309
        dol_syslog("SupplierProposalLine::update_total", LOG_DEBUG);
3310
3311
        $resql=$this->db->query($sql);
3312
        if ($resql)
3313
        {
3314
            $this->db->commit();
3315
            return 1;
3316
        }
3317
        else
3318
        {
3319
            $this->error=$this->db->error();
3320
            $this->db->rollback();
3321
            return -2;
3322
        }
3323
    }
3324
}
3325