Passed
Branch develop (74203a)
by
unknown
28:58
created

SupplierProposalLine::fetch()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 71
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 55
nc 2
nop 1
dl 0
loc 71
rs 8.9818
c 1
b 0
f 1

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* Copyright (C) 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;
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;
0 ignored issues
show
Bug introduced by
The property price does not exist on SupplierProposalLine. Did you mean price_level?
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
     * 		@param		int			$date_start			Date start
395
     * 		@param		int			$date_end			Date end
396
     *    	@return    	int         	    			>0 if OK, <0 if KO
397
     *
398
     *    	@see       	add_product()
399
     */
400
    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, $date_start = 0, $date_end = 0)
401
    {
402
        global $mysoc, $conf;
403
404
        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");
405
        include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
406
407
        // Clean parameters
408
        if (empty($remise_percent)) $remise_percent=0;
409
        if (empty($qty)) $qty=0;
410
        if (empty($info_bits)) $info_bits=0;
411
        if (empty($rang)) $rang=0;
412
        if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0;
413
        if (empty($pu_ht)) $pu_ht=0;
414
415
        $remise_percent=price2num($remise_percent);
416
        $qty=price2num($qty);
417
        $pu_ht=price2num($pu_ht);
418
        $pu_ttc=price2num($pu_ttc);
419
        $txtva=price2num($txtva);
420
        $txlocaltax1=price2num($txlocaltax1);
421
        $txlocaltax2=price2num($txlocaltax2);
422
            $pa_ht=price2num($pa_ht);
423
        if ($price_base_type=='HT')
424
        {
425
            $pu=$pu_ht;
426
        }
427
        else
428
        {
429
            $pu=$pu_ttc;
430
        }
431
432
        // Check parameters
433
        if ($type < 0) return -1;
434
435
        if ($this->statut == self::STATUS_DRAFT)
436
        {
437
            $this->db->begin();
438
439
            if ($fk_product > 0)
440
            {
441
                if (! empty($conf->global->SUPPLIER_PROPOSAL_WITH_PREDEFINED_PRICES_ONLY))
442
                {
443
                    // Check quantity is enough
444
                    dol_syslog(get_class($this)."::addline we check supplier prices fk_product=".$fk_product." fk_fournprice=".$fk_fournprice." qty=".$qty." ref_supplier=".$ref_supplier);
445
                    $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

445
                    $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...
446
                    if ($prod->fetch($fk_product) > 0)
447
                    {
448
                        $product_type = $prod->type;
449
                        $label = $prod->label;
450
                        $fk_prod_fourn_price = $fk_fournprice;
451
452
                        // We use 'none' instead of $ref_supplier, because fourn_ref may not exists anymore. So we will take the first supplier price ok.
453
                        // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
454
                        $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
455
                        if ($result > 0)
456
                        {
457
                            $pu = $prod->fourn_pu;       // Unit price supplier price set by get_buyprice
458
                            $ref_supplier = $prod->ref_supplier;   // Ref supplier price set by get_buyprice
459
                            // is remise percent not keyed but present for the product we add it
460
                            if ($remise_percent == 0 && $prod->remise_percent !=0)
461
                                $remise_percent =$prod->remise_percent;
462
                        }
463
                        if ($result == 0)                   // If result == 0, we failed to found the supplier reference price
464
                        {
465
                            $langs->load("errors");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $langs seems to be never defined.
Loading history...
466
                            $this->error = "Ref " . $prod->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier");
467
                            $this->db->rollback();
468
                            dol_syslog(get_class($this)."::addline we did not found supplier price, so we can't guess unit price");
469
                            //$pu    = $prod->fourn_pu;     // We do not overwrite unit price
470
                            //$ref   = $prod->ref_fourn;    // We do not overwrite ref supplier price
471
                            return -1;
472
                        }
473
                        if ($result == -1)
474
                        {
475
                            $langs->load("errors");
476
                            $this->error = "Ref " . $prod->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier");
477
                            $this->db->rollback();
478
                            dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_DEBUG);
479
                            return -1;
480
                        }
481
                        if ($result < -1)
482
                        {
483
                            $this->error=$prod->error;
484
                            $this->db->rollback();
485
                            dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_ERR);
486
                            return -1;
487
                        }
488
                    }
489
                    else
490
                    {
491
                        $this->error=$prod->error;
492
                        $this->db->rollback();
493
                        return -1;
494
                    }
495
                }
496
            }
497
            else
498
            {
499
                $product_type = $type;
500
            }
501
502
            // Calcul du total TTC et de la TVA pour la ligne a partir de
503
            // qty, pu, remise_percent et txtva
504
            // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
505
            // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
506
507
            $localtaxes_type=getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
508
            $txtva = preg_replace('/\s*\(.*\)/', '', $txtva);  // Remove code into vatrate.
509
510
            if ($conf->multicurrency->enabled && $pu_ht_devise > 0) {
511
                $pu = 0;
512
            }
513
514
            $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);
515
            $total_ht  = $tabprice[0];
516
            $total_tva = $tabprice[1];
517
            $total_ttc = $tabprice[2];
518
            $total_localtax1 = $tabprice[9];
519
            $total_localtax2 = $tabprice[10];
520
            $pu = $pu_ht = $tabprice[3];
521
522
            // MultiCurrency
523
            $multicurrency_total_ht  = $tabprice[16];
524
            $multicurrency_total_tva = $tabprice[17];
525
            $multicurrency_total_ttc = $tabprice[18];
526
            $pu_ht_devise = $tabprice[19];
527
528
            // Rang to use
529
            $ranktouse = $rang;
530
            if ($ranktouse == -1)
531
            {
532
                $rangmax = $this->line_max($fk_parent_line);
533
                $ranktouse = $rangmax + 1;
534
            }
535
536
            // TODO A virer
537
            // Anciens indicateurs: $price, $remise (a ne plus utiliser)
538
            $price = $pu;
539
            $remise = 0;
540
            if ($remise_percent > 0)
541
            {
542
                $remise = round(($pu * $remise_percent / 100), 2);
543
                $price = $pu - $remise;
544
            }
545
546
            // Insert line
547
            $this->line=new SupplierProposalLine($this->db);
548
549
            $this->line->fk_supplier_proposal=$this->id;
550
            $this->line->label=$label;
551
            $this->line->desc=$desc;
552
            $this->line->qty=$qty;
553
            $this->line->tva_tx=$txtva;
554
            $this->line->localtax1_tx=($total_localtax1?$localtaxes_type[1]:0);
555
            $this->line->localtax2_tx=($total_localtax2?$localtaxes_type[3]:0);
556
            $this->line->localtax1_type = $localtaxes_type[0];
557
            $this->line->localtax2_type = $localtaxes_type[2];
558
            $this->line->fk_product=$fk_product;
559
            $this->line->remise_percent=$remise_percent;
560
            $this->line->subprice=$pu_ht;
561
            $this->line->rang=$ranktouse;
562
            $this->line->info_bits=$info_bits;
563
            $this->line->total_ht=$total_ht;
564
            $this->line->total_tva=$total_tva;
565
            $this->line->total_localtax1=$total_localtax1;
566
            $this->line->total_localtax2=$total_localtax2;
567
            $this->line->total_ttc=$total_ttc;
568
            $this->line->product_type=$type;
569
            $this->line->special_code=$special_code;
570
            $this->line->fk_parent_line=$fk_parent_line;
571
            $this->line->fk_unit=$fk_unit;
572
            $this->line->origin=$origin;
573
            $this->line->origin_id=$origin_id;
574
            $this->line->ref_fourn = $this->db->escape($ref_supplier);
575
			$this->line->date_start = $date_start;
576
			$this->line->date_end = $date_end;
577
578
            // infos marge
579
            if (!empty($fk_product) && empty($fk_fournprice) && empty($pa_ht)) {
580
                // by external module, take lowest buying price
581
                include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
582
                $productFournisseur = new ProductFournisseur($this->db);
583
                $productFournisseur->find_min_price_product_fournisseur($fk_product);
584
                $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id;
585
            } else {
586
                $this->line->fk_fournprice = $fk_fournprice;
587
            }
588
            $this->line->pa_ht = $pa_ht;
589
590
            // Multicurrency
591
            $this->line->fk_multicurrency			= $this->fk_multicurrency;
592
            $this->line->multicurrency_code			= $this->multicurrency_code;
593
            $this->line->multicurrency_subprice		= $pu_ht_devise;
594
            $this->line->multicurrency_total_ht 	= $multicurrency_total_ht;
595
            $this->line->multicurrency_total_tva 	= $multicurrency_total_tva;
596
            $this->line->multicurrency_total_ttc 	= $multicurrency_total_ttc;
597
598
            // Mise en option de la ligne
599
            if (empty($qty) && empty($special_code)) $this->line->special_code=3;
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->id;
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
        else
633
        {
634
        	$this->error = 'BadStatusOfObjectToAddLine';
635
        	return -5;
636
        }
637
    }
638
639
640
    /**
641
     *  Update a proposal line
642
     *
643
     *  @param      int			$rowid           	Id de la ligne
644
     *  @param      double		$pu		     	  	Prix unitaire (HT ou TTC selon price_base_type)
645
     *  @param      double		$qty            	Quantity
646
     *  @param      double		$remise_percent  	Remise effectuee sur le produit
647
     *  @param      double		$txtva	          	Taux de TVA
648
     * 	@param	  	double		$txlocaltax1		Local tax 1 rate
649
     *  @param	  	double		$txlocaltax2		Local tax 2 rate
650
     *  @param      string		$desc            	Description
651
     *	@param	  	double		$price_base_type	HT ou TTC
652
     *	@param      int			$info_bits        	Miscellaneous informations
653
     *	@param		int			$special_code		Special code (also used by externals modules!)
654
     * 	@param		int			$fk_parent_line		Id of parent line (0 in most cases, used by modules adding sublevels into lines).
655
     * 	@param		int			$skip_update_total	Keep fields total_xxx to 0 (used for special lines by some modules)
656
     *  @param		int			$fk_fournprice		Id of origin supplier price
657
     *  @param		int			$pa_ht				Price (without tax) of product when it was bought
658
     *  @param		string		$label				???
659
     *  @param		int			$type				0/1=Product/service
660
     *  @param		array		$array_option		extrafields array
661
     * 	@param		string		$ref_supplier			Supplier price reference
662
     *	@param		int			$fk_unit			Id of the unit to use.
663
	 * 	@param		double		$pu_ht_devise		Unit price in currency
664
     *  @return     int     		        		0 if OK, <0 if KO
665
     */
666
    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)
667
    {
668
        global $conf,$user,$langs, $mysoc;
669
670
        dol_syslog(get_class($this)."::updateLine $rowid, $pu, $qty, $remise_percent, $txtva, $desc, $price_base_type, $info_bits");
671
        include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
672
673
        // Clean parameters
674
        $remise_percent=price2num($remise_percent);
675
        $qty=price2num($qty);
676
        $pu = price2num($pu);
677
        $txtva = price2num($txtva);
678
        $txlocaltax1=price2num($txlocaltax1);
679
        $txlocaltax2=price2num($txlocaltax2);
680
        $pa_ht=price2num($pa_ht);
681
        if (empty($qty) && empty($special_code)) $special_code=3;    // Set option tag
682
        if (! empty($qty) && $special_code == 3) $special_code=0;    // Remove option tag
683
684
        if ($this->statut == 0)
685
        {
686
            $this->db->begin();
687
688
            // Calcul du total TTC et de la TVA pour la ligne a partir de
689
            // qty, pu, remise_percent et txtva
690
            // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
691
            // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
692
693
            $localtaxes_type=getLocalTaxesFromRate($txtva, 0, $mysoc, $this->thirdparty);
694
695
            // Clean vat code
696
            $reg = array();
697
            $vat_src_code='';
698
            if (preg_match('/\((.*)\)/', $txtva, $reg))
699
            {
700
            	$vat_src_code = $reg[1];
701
            	$txtva = preg_replace('/\s*\(.*\)/', '', $txtva);    // Remove code into vatrate.
702
            }
703
704
            $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);
705
            $total_ht  = $tabprice[0];
706
            $total_tva = $tabprice[1];
707
            $total_ttc = $tabprice[2];
708
            $total_localtax1 = $tabprice[9];
709
            $total_localtax2 = $tabprice[10];
710
711
            // MultiCurrency
712
            $multicurrency_total_ht  = $tabprice[16];
713
            $multicurrency_total_tva = $tabprice[17];
714
            $multicurrency_total_ttc = $tabprice[18];
715
716
            // Update line
717
            $this->line=new SupplierProposalLine($this->db);
718
719
            // Stock previous line records
720
            $staticline=new SupplierProposalLine($this->db);
721
            $staticline->fetch($rowid);
722
            $this->line->oldline = $staticline;
723
724
            // Reorder if fk_parent_line change
725
            if (! empty($fk_parent_line) && ! empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line)
726
            {
727
                $rangmax = $this->line_max($fk_parent_line);
728
                $this->line->rang = $rangmax + 1;
729
            }
730
731
            $this->line->id					= $rowid;
732
            $this->line->label				= $label;
733
            $this->line->desc				= $desc;
734
            $this->line->qty				= $qty;
735
            $this->line->product_type		= $type;
736
737
            $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...
738
            $this->line->tva_tx				= $txtva;
739
            $this->line->localtax1_tx		= $txlocaltax1;
740
            $this->line->localtax2_tx		= $txlocaltax2;
741
            $this->line->localtax1_type		= $localtaxes_type[0];
742
            $this->line->localtax2_type		= $localtaxes_type[2];
743
            $this->line->remise_percent		= $remise_percent;
744
            $this->line->subprice			= $pu;
745
            $this->line->info_bits			= $info_bits;
746
            $this->line->total_ht			= $total_ht;
747
            $this->line->total_tva			= $total_tva;
748
            $this->line->total_localtax1	= $total_localtax1;
749
            $this->line->total_localtax2	= $total_localtax2;
750
            $this->line->total_ttc			= $total_ttc;
751
            $this->line->special_code		= $special_code;
752
            $this->line->fk_parent_line		= $fk_parent_line;
753
            $this->line->skip_update_total	= $skip_update_total;
754
            $this->line->ref_fourn			= $ref_supplier;
755
            $this->line->fk_unit			= $fk_unit;
756
757
            // infos marge
758
            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...
759
                // by external module, take lowest buying price
760
                include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
761
                $productFournisseur = new ProductFournisseur($this->db);
762
                $productFournisseur->find_min_price_product_fournisseur($fk_product);
763
                $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id;
764
            } else {
765
                $this->line->fk_fournprice = $fk_fournprice;
766
            }
767
            $this->line->pa_ht = $pa_ht;
768
769
            if (is_array($array_option) && count($array_option)>0) {
770
                $this->line->array_options=$array_option;
771
            }
772
773
            // Multicurrency
774
            $this->line->multicurrency_subprice		= price2num($pu * $this->multicurrency_tx);
775
            $this->line->multicurrency_total_ht 	= $multicurrency_total_ht;
776
            $this->line->multicurrency_total_tva 	= $multicurrency_total_tva;
777
            $this->line->multicurrency_total_ttc 	= $multicurrency_total_ttc;
778
779
            $result=$this->line->update();
780
            if ($result > 0)
781
            {
782
                // Reorder if child line
783
                if (! empty($fk_parent_line)) $this->line_order(true, 'DESC');
784
785
                $this->update_price(1);
786
787
                $this->fk_supplier_proposal = $this->id;
788
789
                $this->db->commit();
790
                return $result;
791
            }
792
            else
793
            {
794
                $this->error=$this->db->error();
795
                $this->db->rollback();
796
                return -1;
797
            }
798
        }
799
        else
800
        {
801
            dol_syslog(get_class($this)."::updateline Erreur -2 SupplierProposal en mode incompatible pour cette action");
802
            return -2;
803
        }
804
    }
805
806
807
    /**
808
     *  Delete detail line
809
     *
810
     *  @param		int		$lineid			Id of line to delete
811
     *  @return     int         			>0 if OK, <0 if KO
812
     */
813
    public function deleteline($lineid)
814
    {
815
        if ($this->statut == 0)
816
        {
817
            $line=new SupplierProposalLine($this->db);
818
819
            // For triggers
820
            $line->fetch($lineid);
821
822
            if ($line->delete() > 0)
823
            {
824
                $this->update_price(1);
825
826
                return 1;
827
            }
828
            else
829
            {
830
                return -1;
831
            }
832
        }
833
        else
834
        {
835
            return -2;
836
        }
837
    }
838
839
840
    /**
841
     *  Create commercial proposal into database
842
     * 	this->ref can be set or empty. If empty, we will use "(PROVid)"
843
     *
844
     * 	@param		User	$user		User that create
845
     * 	@param		int		$notrigger	1=Does not execute triggers, 0= execute triggers
846
     *  @return     int     			<0 if KO, >=0 if OK
847
     */
848
    public function create($user, $notrigger = 0)
849
    {
850
        global $langs, $conf, $mysoc, $hookmanager;
851
        $error=0;
852
853
        $now=dol_now();
854
855
        dol_syslog(get_class($this)."::create");
856
857
        // Check parameters
858
        $result=$this->fetch_thirdparty();
859
        if ($result < 0)
860
        {
861
            $this->error="Failed to fetch company";
862
            dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
863
            return -3;
864
        }
865
866
        // Check parameters
867
        if (! empty($this->ref))	// We check that ref is not already used
868
        {
869
            $result=self::isExistingObject($this->element, 0, $this->ref);	// Check ref is not yet used
870
            if ($result > 0)
871
            {
872
                $this->error='ErrorRefAlreadyExists';
873
                dol_syslog(get_class($this)."::create ".$this->error, LOG_WARNING);
874
                $this->db->rollback();
875
                return -1;
876
            }
877
        }
878
879
        // Multicurrency
880
        if (!empty($this->multicurrency_code)) list($this->fk_multicurrency,$this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
881
        if (empty($this->fk_multicurrency))
882
        {
883
            $this->multicurrency_code = $conf->currency;
884
            $this->fk_multicurrency = 0;
885
            $this->multicurrency_tx = 1;
886
        }
887
888
        $this->db->begin();
889
890
        // Insert into database
891
        $sql = "INSERT INTO ".MAIN_DB_PREFIX."supplier_proposal (";
892
        $sql.= "fk_soc";
893
        $sql.= ", price";
894
        $sql.= ", remise";
895
        $sql.= ", remise_percent";
896
        $sql.= ", remise_absolue";
897
        $sql.= ", tva";
898
        $sql.= ", total";
899
        $sql.= ", datec";
900
        $sql.= ", ref";
901
        $sql.= ", fk_user_author";
902
        $sql.= ", note_private";
903
        $sql.= ", note_public";
904
        $sql.= ", model_pdf";
905
        $sql.= ", fk_cond_reglement";
906
        $sql.= ", fk_mode_reglement";
907
        $sql.= ", fk_account";
908
        $sql.= ", date_livraison";
909
        $sql.= ", fk_shipping_method";
910
        $sql.= ", fk_projet";
911
        $sql.= ", entity";
912
        $sql.= ", fk_multicurrency";
913
        $sql.= ", multicurrency_code";
914
        $sql.= ", multicurrency_tx";
915
        $sql.= ") ";
916
        $sql.= " VALUES (";
917
        $sql.= $this->socid;
918
        $sql.= ", 0";
919
        $sql.= ", ".$this->remise;
920
        $sql.= ", ".($this->remise_percent?$this->db->escape($this->remise_percent):'null');
921
        $sql.= ", ".($this->remise_absolue?$this->db->escape($this->remise_absolue):'null');
922
        $sql.= ", 0";
923
        $sql.= ", 0";
924
        $sql.= ", '".$this->db->idate($now)."'";
925
        $sql.= ", '(PROV)'";
926
        $sql.= ", ".($user->id > 0 ? "'".$user->id."'":"null");
927
        $sql.= ", '".$this->db->escape($this->note_private)."'";
928
        $sql.= ", '".$this->db->escape($this->note_public)."'";
929
        $sql.= ", '".$this->db->escape($this->modelpdf)."'";
930
        $sql.= ", ".($this->cond_reglement_id > 0 ? $this->cond_reglement_id : 'NULL');
931
        $sql.= ", ".($this->mode_reglement_id > 0 ? $this->mode_reglement_id : 'NULL');
932
        $sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL');
933
        $sql.= ", ".($this->date_livraison!=''?"'".$this->db->idate($this->date_livraison)."'":"null");
934
        $sql.= ", ".($this->shipping_method_id>0?$this->shipping_method_id:'NULL');
935
        $sql.= ", ".($this->fk_project?$this->fk_project:"null");
936
        $sql.= ", ".$conf->entity;
937
        $sql.= ", ".(int) $this->fk_multicurrency;
938
        $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
939
        $sql.= ", ".(double) $this->multicurrency_tx;
940
        $sql.= ")";
941
942
        dol_syslog(get_class($this)."::create", LOG_DEBUG);
943
        $resql=$this->db->query($sql);
944
        if ($resql)
945
        {
946
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."supplier_proposal");
947
948
            if ($this->id)
949
            {
950
                $this->ref='(PROV'.$this->id.')';
951
                $sql = 'UPDATE '.MAIN_DB_PREFIX."supplier_proposal SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".$this->id;
952
953
                dol_syslog(get_class($this)."::create", LOG_DEBUG);
954
                $resql=$this->db->query($sql);
955
                if (! $resql) $error++;
956
957
                if (! empty($this->linkedObjectsIds) && empty($this->linked_objects))	// To use new linkedObjectsIds instead of old linked_objects
958
                {
959
                    $this->linked_objects = $this->linkedObjectsIds;	// TODO Replace linked_objects with linkedObjectsIds
960
                }
961
962
                // Add object linked
963
                if (! $error && $this->id && is_array($this->linked_objects) && ! empty($this->linked_objects))
964
                {
965
                    foreach($this->linked_objects as $origin => $tmp_origin_id)
966
                    {
967
                        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, ...))
968
                        {
969
                            foreach($tmp_origin_id as $origin_id)
970
                            {
971
                                $ret = $this->add_object_linked($origin, $origin_id);
972
                                if (! $ret)
973
                                {
974
                                    dol_print_error($this->db);
975
                                    $error++;
976
                                }
977
                            }
978
                        }
979
                    }
980
                }
981
982
                /*
983
                 *  Insertion du detail des produits dans la base
984
                 */
985
                if (! $error)
986
                {
987
                    $fk_parent_line=0;
988
                    $num=count($this->lines);
989
990
                    for ($i=0;$i<$num;$i++)
991
                    {
992
                        // Reset fk_parent_line for no child products and special product
993
                        if (($this->lines[$i]->product_type != 9 && empty($this->lines[$i]->fk_parent_line)) || $this->lines[$i]->product_type == 9) {
994
                            $fk_parent_line = 0;
995
                        }
996
997
                        $result = $this->addline(
998
                            $this->lines[$i]->desc,
999
                            $this->lines[$i]->subprice,
1000
                            $this->lines[$i]->qty,
1001
                            $this->lines[$i]->tva_tx,
1002
                            $this->lines[$i]->localtax1_tx,
1003
                            $this->lines[$i]->localtax2_tx,
1004
                            $this->lines[$i]->fk_product,
1005
                            $this->lines[$i]->remise_percent,
1006
                            'HT',
1007
                            0,
1008
                            0,
1009
                            $this->lines[$i]->product_type,
1010
                            $this->lines[$i]->rang,
1011
                            $this->lines[$i]->special_code,
1012
                            $fk_parent_line,
1013
                            $this->lines[$i]->fk_fournprice,
1014
                            $this->lines[$i]->pa_ht,
1015
                            $this->lines[$i]->label,
1016
                            $this->lines[$i]->array_options,
1017
                            $this->lines[$i]->ref_fourn,
1018
                            $this->lines[$i]->fk_unit,
1019
                            'supplier_proposal',
1020
                            $this->lines[$i]->rowid
1021
                        );
1022
1023
                        if ($result < 0)
1024
                        {
1025
                            $error++;
1026
                            $this->error=$this->db->error;
1027
                            dol_print_error($this->db);
1028
                            break;
1029
                        }
1030
                        // Defined the new fk_parent_line
1031
                        if ($result > 0 && $this->lines[$i]->product_type == 9) {
1032
                            $fk_parent_line = $result;
1033
                        }
1034
                    }
1035
                }
1036
1037
                if (! $error)
1038
                {
1039
                    // Mise a jour infos denormalisees
1040
                    $resql=$this->update_price(1);
1041
                    if ($resql)
1042
                    {
1043
                        $action='update';
1044
1045
                        // Actions on extra fields
1046
                        if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))
1047
                        {
1048
                            $result=$this->insertExtraFields();
1049
                            if ($result < 0)
1050
                            {
1051
                                $error++;
1052
                            }
1053
                        }
1054
1055
                        if (! $error && ! $notrigger)
1056
                        {
1057
                            // Call trigger
1058
                            $result=$this->call_trigger('PROPAL_SUPPLIER_CREATE', $user);
1059
                            if ($result < 0) { $error++; }
1060
                            // End call triggers
1061
                        }
1062
                    }
1063
                    else
1064
                    {
1065
                        $this->error=$this->db->lasterror();
1066
                        $error++;
1067
                    }
1068
                }
1069
            }
1070
            else
1071
            {
1072
                $this->error=$this->db->lasterror();
1073
                $error++;
1074
            }
1075
1076
            if (! $error)
1077
            {
1078
                $this->db->commit();
1079
                dol_syslog(get_class($this)."::create done id=".$this->id);
1080
                return $this->id;
1081
            }
1082
            else
1083
            {
1084
                $this->db->rollback();
1085
                return -2;
1086
            }
1087
        }
1088
        else
1089
        {
1090
            $this->error=$this->db->lasterror();
1091
            $this->db->rollback();
1092
            return -1;
1093
        }
1094
    }
1095
1096
1097
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1098
    /**
1099
     *	Insert into DB a supplier_proposal object completely defined by its data members (ex, results from copy).
1100
     *
1101
     *	@param 		User	$user	User that create
1102
     *	@return    	int				Id of the new object if ok, <0 if ko
1103
     *	@see       	create()
1104
     */
1105
    public function create_from($user)
1106
    {
1107
        // phpcs:enable
1108
        $this->products=$this->lines;
1109
1110
        return $this->create($user);
1111
    }
1112
1113
    /**
1114
     *		Load an object from its id and create a new one in database
1115
     *
1116
	 *      @param	    User	$user		    User making the clone
1117
     *		@param		int		$fromid			Id of thirdparty
1118
     * 	 	@return		int						New id of clone
1119
     */
1120
    public function createFromClone(User $user, $fromid = 0)
1121
    {
1122
        global $conf,$hookmanager;
1123
1124
        $error=0;
1125
        $now=dol_now();
1126
1127
        $this->db->begin();
1128
1129
        // get extrafields so they will be clone
1130
        foreach($this->lines as $line)
1131
            $line->fetch_optionals();
1132
1133
        // Load source object
1134
        $objFrom = clone $this;
1135
1136
        $objsoc=new Societe($this->db);
1137
1138
        // Change socid if needed
1139
        if (! empty($fromid) && $fromid != $this->socid)
1140
        {
1141
            if ($objsoc->fetch($fromid) > 0)
1142
            {
1143
                $this->socid 				= $objsoc->id;
1144
                $this->cond_reglement_id	= (! empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
1145
                $this->mode_reglement_id	= (! empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
1146
                $this->fk_project			= '';
1147
            }
1148
1149
            // TODO Change product price if multi-prices
1150
        }
1151
        else
1152
        {
1153
            $objsoc->fetch($this->socid);
1154
        }
1155
1156
        $this->id=0;
1157
        $this->statut=0;
1158
1159
        if (empty($conf->global->SUPPLIER_PROPOSAL_ADDON) || ! is_readable(DOL_DOCUMENT_ROOT ."/core/modules/supplier_proposal/".$conf->global->SUPPLIER_PROPOSAL_ADDON.".php"))
1160
        {
1161
            $this->error='ErrorSetupNotComplete';
1162
            return -1;
1163
        }
1164
1165
        // Clear fields
1166
        $this->user_author	= $user->id;
1167
        $this->user_valid	= '';
1168
        $this->date			= $now;
1169
1170
        // Set ref
1171
        require_once DOL_DOCUMENT_ROOT ."/core/modules/supplier_proposal/".$conf->global->SUPPLIER_PROPOSAL_ADDON.'.php';
1172
        $obj = $conf->global->SUPPLIER_PROPOSAL_ADDON;
1173
        $modSupplierProposal = new $obj;
1174
        $this->ref = $modSupplierProposal->getNextValue($objsoc, $this);
1175
1176
        // Create clone
1177
        $this->context['createfromclone'] = 'createfromclone';
1178
        $result=$this->create($user);
1179
        if ($result < 0) $error++;
1180
1181
        if (! $error)
1182
        {
1183
            // Hook of thirdparty module
1184
            if (is_object($hookmanager))
1185
            {
1186
                $parameters=array('objFrom'=>$objFrom);
1187
                $action='';
1188
                $reshook=$hookmanager->executeHooks('createFrom', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
1189
                if ($reshook < 0) $error++;
1190
            }
1191
        }
1192
1193
        unset($this->context['createfromclone']);
1194
1195
        // End
1196
        if (! $error)
1197
        {
1198
            $this->db->commit();
1199
            return $this->id;
1200
        }
1201
        else
1202
        {
1203
            $this->db->rollback();
1204
            return -1;
1205
        }
1206
    }
1207
1208
    /**
1209
     *	Load a proposal from database and its ligne array
1210
     *
1211
     *	@param      int			$rowid		id of object to load
1212
     *	@param		string		$ref		Ref of proposal
1213
     *	@return     int         			>0 if OK, <0 if KO
1214
     */
1215
    public function fetch($rowid, $ref = '')
1216
    {
1217
        global $conf;
1218
1219
        $sql = "SELECT p.rowid, p.entity, p.ref, p.remise, p.remise_percent, p.remise_absolue, p.fk_soc";
1220
        $sql.= ", p.total, p.tva, p.localtax1, p.localtax2, p.total_ht";
1221
        $sql.= ", p.datec";
1222
        $sql.= ", p.date_valid as datev";
1223
        $sql.= ", p.date_livraison as date_livraison";
1224
        $sql.= ", p.model_pdf, p.extraparams";
1225
        $sql.= ", p.note_private, p.note_public";
1226
        $sql.= ", p.fk_projet as fk_project, p.fk_statut";
1227
        $sql.= ", p.fk_user_author, p.fk_user_valid, p.fk_user_cloture";
1228
        $sql.= ", p.fk_cond_reglement";
1229
        $sql.= ", p.fk_mode_reglement";
1230
        $sql.= ', p.fk_account';
1231
        $sql.= ", p.fk_shipping_method";
1232
        $sql.= ", p.fk_multicurrency, p.multicurrency_code, p.multicurrency_tx, p.multicurrency_total_ht, p.multicurrency_total_tva, p.multicurrency_total_ttc";
1233
        $sql.= ", c.label as statut_label";
1234
        $sql.= ", cr.code as cond_reglement_code, cr.libelle as cond_reglement, cr.libelle_facture as cond_reglement_libelle_doc";
1235
        $sql.= ", cp.code as mode_reglement_code, cp.libelle as mode_reglement";
1236
        $sql.= " FROM ".MAIN_DB_PREFIX."c_propalst as c, ".MAIN_DB_PREFIX."supplier_proposal as p";
1237
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as cp ON p.fk_mode_reglement = cp.id';
1238
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON p.fk_cond_reglement = cr.rowid';
1239
        $sql.= " WHERE p.fk_statut = c.id";
1240
        $sql.= " AND p.entity IN (".getEntity('supplier_proposal').")";
1241
        if ($ref) $sql.= " AND p.ref='".$ref."'";
1242
        else $sql.= " AND p.rowid=".$rowid;
1243
1244
        dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1245
        $resql=$this->db->query($sql);
1246
        if ($resql)
1247
        {
1248
            if ($this->db->num_rows($resql))
1249
            {
1250
                $obj = $this->db->fetch_object($resql);
1251
1252
                $this->id                   = $obj->rowid;
1253
                $this->entity               = $obj->entity;
1254
1255
                $this->ref                  = $obj->ref;
1256
                $this->remise               = $obj->remise;
1257
                $this->remise_percent       = $obj->remise_percent;
1258
                $this->remise_absolue       = $obj->remise_absolue;
1259
                $this->total                = $obj->total; // TODO deprecated
1260
                $this->total_ht             = $obj->total_ht;
1261
                $this->total_tva            = $obj->tva;
1262
                $this->total_localtax1		= $obj->localtax1;
1263
                $this->total_localtax2		= $obj->localtax2;
1264
                $this->total_ttc            = $obj->total;
1265
                $this->socid                = $obj->fk_soc;
1266
                $this->fk_project           = $obj->fk_project;
1267
                $this->modelpdf             = $obj->model_pdf;
1268
                $this->note                 = $obj->note_private; // TODO deprecated
1269
                $this->note_private         = $obj->note_private;
1270
                $this->note_public          = $obj->note_public;
1271
                $this->statut               = (int) $obj->fk_statut;
1272
                $this->statut_libelle       = $obj->statut_label;
1273
                $this->datec                = $this->db->jdate($obj->datec); // TODO deprecated
1274
                $this->datev                = $this->db->jdate($obj->datev); // TODO deprecated
1275
                $this->date_creation		= $this->db->jdate($obj->datec); //Creation date
1276
                $this->date_validation		= $this->db->jdate($obj->datev); //Validation date
1277
                $this->date_livraison       = $this->db->jdate($obj->date_livraison);
1278
                $this->shipping_method_id   = ($obj->fk_shipping_method>0)?$obj->fk_shipping_method:null;
1279
1280
                $this->mode_reglement_id    = $obj->fk_mode_reglement;
1281
                $this->mode_reglement_code  = $obj->mode_reglement_code;
1282
                $this->mode_reglement       = $obj->mode_reglement;
1283
                $this->fk_account           = ($obj->fk_account>0)?$obj->fk_account:null;
1284
                $this->cond_reglement_id    = $obj->fk_cond_reglement;
1285
                $this->cond_reglement_code  = $obj->cond_reglement_code;
1286
                $this->cond_reglement       = $obj->cond_reglement;
1287
                $this->cond_reglement_doc   = $obj->cond_reglement_libelle_doc;
1288
1289
                $this->extraparams			= (array) json_decode($obj->extraparams, true);
1290
1291
                $this->user_author_id = $obj->fk_user_author;
1292
                $this->user_valid_id  = $obj->fk_user_valid;
1293
                $this->user_close_id  = $obj->fk_user_cloture;
1294
1295
                // Multicurrency
1296
                $this->fk_multicurrency 		= $obj->fk_multicurrency;
1297
                $this->multicurrency_code 		= $obj->multicurrency_code;
1298
                $this->multicurrency_tx 		= $obj->multicurrency_tx;
1299
                $this->multicurrency_total_ht 	= $obj->multicurrency_total_ht;
1300
                $this->multicurrency_total_tva 	= $obj->multicurrency_total_tva;
1301
                $this->multicurrency_total_ttc 	= $obj->multicurrency_total_ttc;
1302
1303
                if ($obj->fk_statut == 0)
1304
                {
1305
                    $this->brouillon = 1;
1306
                }
1307
1308
                // Retreive all extrafield
1309
                // fetch optionals attributes and labels
1310
                $this->fetch_optionals();
1311
1312
                $this->db->free($resql);
1313
1314
                $this->lines = array();
1315
1316
                // Lines of supplier proposals
1317
                $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,";
1318
                $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,";
1319
                $sql.= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label,';
1320
                $sql.= ' d.ref_fourn as ref_produit_fourn,';
1321
                $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';
1322
                $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposaldet as d";
1323
                $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON d.fk_product = p.rowid";
1324
                $sql.= " WHERE d.fk_supplier_proposal = ".$this->id;
1325
                $sql.= " ORDER by d.rang";
1326
1327
                $result = $this->db->query($sql);
1328
                if ($result)
1329
                {
1330
                    $num = $this->db->num_rows($result);
1331
                    $i = 0;
1332
1333
                    while ($i < $num)
1334
                    {
1335
                        $objp                   = $this->db->fetch_object($result);
1336
1337
                        $line                   = new SupplierProposalLine($this->db);
1338
1339
                        $line->rowid			= $objp->rowid; // deprecated
1340
                        $line->id				= $objp->rowid;
1341
                        $line->fk_supplier_proposal		= $objp->fk_supplier_proposal;
1342
                        $line->fk_parent_line	= $objp->fk_parent_line;
1343
                        $line->product_type     = $objp->product_type;
1344
                        $line->label            = $objp->custom_label;
1345
                        $line->desc             = $objp->description;  // Description ligne
1346
                        $line->qty              = $objp->qty;
1347
                        $line->tva_tx           = $objp->tva_tx;
1348
                        $line->localtax1_tx		= $objp->localtax1_tx;
1349
                        $line->localtax2_tx		= $objp->localtax2_tx;
1350
                        $line->subprice         = $objp->subprice;
1351
                        $line->fk_remise_except = $objp->fk_remise_except;
1352
                        $line->remise_percent   = $objp->remise_percent;
1353
                        $line->price            = $objp->price;		// TODO deprecated
1354
1355
                        $line->info_bits        = $objp->info_bits;
1356
                        $line->total_ht         = $objp->total_ht;
1357
                        $line->total_tva        = $objp->total_tva;
1358
                        $line->total_localtax1	= $objp->total_localtax1;
1359
                        $line->total_localtax2	= $objp->total_localtax2;
1360
                        $line->total_ttc        = $objp->total_ttc;
1361
                          $line->fk_fournprice 	= $objp->fk_fournprice;
1362
                        $marginInfos			= getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
1363
                        $line->pa_ht 			= $marginInfos[0];
1364
                        $line->marge_tx			= $marginInfos[1];
1365
                        $line->marque_tx		= $marginInfos[2];
1366
                        $line->special_code     = $objp->special_code;
1367
                        $line->rang             = $objp->rang;
1368
1369
                        $line->fk_product       = $objp->fk_product;
1370
1371
                        $line->ref				= $objp->product_ref;		// TODO deprecated
1372
                        $line->product_ref		= $objp->product_ref;
1373
                        $line->libelle			= $objp->product_label;		// TODO deprecated
1374
                        $line->product_label	= $objp->product_label;
1375
                        $line->product_desc     = $objp->product_desc; 		// Description produit
1376
                        $line->fk_product_type  = $objp->fk_product_type;
1377
1378
                        $line->ref_fourn		= $objp->ref_produit_fourn;
1379
1380
                        // Multicurrency
1381
                        $line->fk_multicurrency 		= $objp->fk_multicurrency;
1382
                        $line->multicurrency_code 		= $objp->multicurrency_code;
1383
                        $line->multicurrency_subprice 	= $objp->multicurrency_subprice;
1384
                        $line->multicurrency_total_ht 	= $objp->multicurrency_total_ht;
1385
                        $line->multicurrency_total_tva 	= $objp->multicurrency_total_tva;
1386
                        $line->multicurrency_total_ttc 	= $objp->multicurrency_total_ttc;
1387
                        $line->fk_unit					= $objp->fk_unit;
1388
1389
                        $this->lines[$i]        = $line;
1390
1391
                        $i++;
1392
                    }
1393
                    $this->db->free($result);
1394
                }
1395
                else
1396
                {
1397
                    $this->error=$this->db->error();
1398
                    return -1;
1399
                }
1400
1401
                // Retreive all extrafield
1402
                // fetch optionals attributes and labels
1403
                $this->fetch_optionals();
1404
1405
                return 1;
1406
            }
1407
1408
            $this->error="Record Not Found";
1409
            return 0;
1410
        }
1411
        else
1412
        {
1413
            $this->error=$this->db->error();
1414
            return -1;
1415
        }
1416
    }
1417
1418
    /**
1419
     *  Set status to validated
1420
     *
1421
     *  @param	User	$user       Object user that validate
1422
     *  @param	int		$notrigger	1=Does not execute triggers, 0= execute triggers
1423
     *  @return int         		<0 if KO, >=0 if OK
1424
     */
1425
    public function valid($user, $notrigger = 0)
1426
    {
1427
        require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1428
1429
        global $conf,$langs;
1430
1431
        $error=0;
1432
        $now=dol_now();
1433
1434
        if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->supplier_proposal->creer))
1435
           || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->supplier_proposal->validate_advance)))
1436
        {
1437
            $this->db->begin();
1438
1439
            // Numbering module definition
1440
            $soc = new Societe($this->db);
1441
            $soc->fetch($this->socid);
1442
1443
            // Define new ref
1444
            if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life
1445
            {
1446
                $num = $this->getNextNumRef($soc);
1447
            }
1448
            else
1449
            {
1450
                $num = $this->ref;
1451
            }
1452
            $this->newref = $num;
1453
1454
            $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal";
1455
            $sql.= " SET ref = '".$this->db->escape($num)."',";
1456
            $sql.= " fk_statut = 1, date_valid='".$this->db->idate($now)."', fk_user_valid=".$user->id;
1457
            $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
1458
1459
            dol_syslog(get_class($this)."::valid", LOG_DEBUG);
1460
            $resql=$this->db->query($sql);
1461
            if (! $resql)
1462
            {
1463
                dol_print_error($this->db);
1464
                $error++;
1465
            }
1466
1467
               // Trigger calls
1468
            if (! $error && ! $notrigger)
1469
            {
1470
                // Call trigger
1471
                $result=$this->call_trigger('SUPPLIER_PROPOSAL_VALIDATE', $user);
1472
                if ($result < 0) { $error++; }
1473
                // End call triggers
1474
            }
1475
1476
            if (! $error)
1477
            {
1478
                $this->oldref = $this->ref;
1479
1480
                // Rename directory if dir was a temporary ref
1481
                if (preg_match('/^[\(]?PROV/i', $this->ref))
1482
                {
1483
                	// Now we rename also files into index
1484
                	$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)."'";
1485
                	$sql.= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'supplier_proposal/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1486
                	$resql = $this->db->query($sql);
1487
                	if (! $resql) { $error++; $this->error = $this->db->lasterror(); }
1488
1489
                	// We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1490
                	$oldref = dol_sanitizeFileName($this->ref);
1491
                    $newref = dol_sanitizeFileName($num);
1492
                    $dirsource = $conf->supplier_proposal->dir_output.'/'.$oldref;
1493
                    $dirdest = $conf->supplier_proposal->dir_output.'/'.$newref;
1494
                    if (! $error && file_exists($dirsource))
1495
                    {
1496
                        dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
1497
                        if (@rename($dirsource, $dirdest))
1498
                        {
1499
                            dol_syslog("Rename ok");
1500
                            // Rename docs starting with $oldref with $newref
1501
                            $listoffiles=dol_dir_list($conf->supplier_proposal->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
1502
                            foreach($listoffiles as $fileentry)
1503
                            {
1504
                                $dirsource=$fileentry['name'];
1505
                                $dirdest=preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1506
                                $dirsource=$fileentry['path'].'/'.$dirsource;
1507
                                $dirdest=$fileentry['path'].'/'.$dirdest;
1508
                                @rename($dirsource, $dirdest);
1509
                            }
1510
                        }
1511
                    }
1512
                }
1513
1514
                $this->ref=$num;
1515
                $this->brouillon=0;
1516
                $this->statut = 1;
1517
                $this->user_valid_id=$user->id;
1518
                $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

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

1828
        $sql = 'UPDATE '.MAIN_DB_PREFIX.'product_fournisseur_price SET '.(!empty($product->ref_fourn) ? 'ref_fourn = "'./** @scrutinizer ignore-deprecated */ $product->ref_fourn.'", ' : '').' price ='.$price.', unitprice ='.$unitPrice.' WHERE rowid = '.$idProductFournPrice;
Loading history...
1829
1830
        $resql = $this->db->query($sql);
1831
        if (!$resql) {
1832
            $this->error=$this->db->error();
1833
            $this->db->rollback();
1834
            return -1;
1835
        }
1836
    }
1837
1838
     /**
1839
     *	Create ProductFournisseur
1840
     *
1841
     *	@param		Product 	$product	Object Product
1842
     *	@param      User		$user		Object user
1843
     *	@return     int         			<0 if KO, >0 if OK
1844
     */
1845
    public function createPriceFournisseur($product, $user)
1846
    {
1847
        $price=price2num($product->subprice*$product->qty, 'MU');
1848
        $qty=price2num($product->qty);
1849
        $unitPrice = price2num($product->subprice, 'MU');
1850
        $now=dol_now();
1851
1852
        $values = array(
1853
            "'".$this->db->idate($now)."'",
1854
            $product->fk_product,
1855
            $this->thirdparty->id,
1856
            "'".$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

1856
            "'"./** @scrutinizer ignore-deprecated */ $product->ref_fourn."'",
Loading history...
1857
            $price,
1858
            $qty,
1859
            $unitPrice,
1860
            $product->tva_tx,
1861
            $user->id
1862
        );
1863
1864
        $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'product_fournisseur_price ';
1865
        $sql .= '(datec, fk_product, fk_soc, ref_fourn, price, quantity, unitprice, tva_tx, fk_user) VALUES ('.implode(',', $values).')';
1866
1867
        $resql = $this->db->query($sql);
1868
        if (!$resql) {
1869
            $this->error=$this->db->error();
1870
            $this->db->rollback();
1871
            return -1;
1872
        }
1873
    }
1874
1875
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1876
    /**
1877
     *  Set draft status
1878
     *
1879
     *	@param		User	$user		Object user that modify
1880
     *	@return		int					<0 if KO, >0 if OK
1881
     */
1882
    public function setDraft($user)
1883
    {
1884
        // phpcs:enable
1885
        global $conf,$langs;
1886
1887
        $error = 0;
1888
1889
        if ($this->statut == self::STATUS_DRAFT)
1890
        {
1891
            dol_syslog(get_class($this)."::setDraft already draft status", LOG_WARNING);
1892
            return 0;
1893
        }
1894
1895
        $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal";
1896
        $sql.= " SET fk_statut = ".self::STATUS_DRAFT;
1897
        $sql.= " WHERE rowid = ".$this->id;
1898
1899
        if ($this->db->query($sql))
1900
        {
1901
            if (!$error) {
1902
                $this->oldcopy = clone $this;
1903
            }
1904
1905
            if (!$error) {
1906
                // Call trigger
1907
                $result=$this->call_trigger('SUPPLIER_PROPOSAL_UNVALIDATE', $user);
1908
                if ($result < 0) $error++;
1909
            }
1910
1911
            if (!$error) {
1912
                $this->statut=self::STATUS_DRAFT;
1913
                $this->brouillon = 1;
1914
                $this->db->commit();
1915
                return 1;
1916
            } else {
1917
                $this->db->rollback();
1918
                return -1;
1919
            }
1920
        }
1921
        else
1922
        {
1923
            return -1;
1924
        }
1925
    }
1926
1927
1928
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1929
    /**
1930
     *    Return list of askprice (eventually filtered on user) into an array
1931
     *
1932
     *    @param	int		$shortlist			0=Return array[id]=ref, 1=Return array[](id=>id,ref=>ref,name=>name)
1933
     *    @param	int		$draft				0=not draft, 1=draft
1934
     *    @param	int		$notcurrentuser		0=all user, 1=not current user
1935
     *    @param    int		$socid				Id third pary
1936
     *    @param    int		$limit				For pagination
1937
     *    @param    int		$offset				For pagination
1938
     *    @param    string	$sortfield			Sort criteria
1939
     *    @param    string	$sortorder			Sort order
1940
     *    @return	int		       				-1 if KO, array with result if OK
1941
     */
1942
    public function liste_array($shortlist = 0, $draft = 0, $notcurrentuser = 0, $socid = 0, $limit = 0, $offset = 0, $sortfield = 'p.datec', $sortorder = 'DESC')
1943
    {
1944
        // phpcs:enable
1945
        global $conf,$user;
1946
1947
        $ga = array();
1948
1949
        $sql = "SELECT s.rowid, s.nom as name, s.client,";
1950
        $sql.= " p.rowid as supplier_proposalid, p.fk_statut, p.total_ht, p.ref, p.remise, ";
1951
        $sql.= " p.datep as dp, p.fin_validite as datelimite";
1952
        if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", sc.fk_soc, sc.fk_user";
1953
        $sql.= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."supplier_proposal as p, ".MAIN_DB_PREFIX."c_propalst as c";
1954
        if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
1955
        $sql.= " WHERE p.entity IN (".getEntity('supplier_proposal').")";
1956
        $sql.= " AND p.fk_soc = s.rowid";
1957
        $sql.= " AND p.fk_statut = c.id";
1958
        if (! $user->rights->societe->client->voir && ! $socid) //restriction
1959
        {
1960
            $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id;
1961
        }
1962
        if ($socid) $sql.= " AND s.rowid = ".$socid;
1963
        if ($draft)	$sql.= " AND p.fk_statut = 0";
1964
        if ($notcurrentuser > 0) $sql.= " AND p.fk_user_author <> ".$user->id;
1965
        $sql.= $this->db->order($sortfield, $sortorder);
1966
        $sql.= $this->db->plimit($limit, $offset);
1967
1968
        $result=$this->db->query($sql);
1969
        if ($result)
1970
        {
1971
            $num = $this->db->num_rows($result);
1972
            if ($num)
1973
            {
1974
                $i = 0;
1975
                while ($i < $num)
1976
                {
1977
                    $obj = $this->db->fetch_object($result);
1978
1979
                    if ($shortlist == 1)
1980
                    {
1981
                        $ga[$obj->supplier_proposalid] = $obj->ref;
1982
                    }
1983
                    elseif ($shortlist == 2)
1984
                    {
1985
                        $ga[$obj->supplier_proposalid] = $obj->ref.' ('.$obj->name.')';
1986
                    }
1987
                    else
1988
                    {
1989
                        $ga[$i]['id']	= $obj->supplier_proposalid;
1990
                        $ga[$i]['ref'] 	= $obj->ref;
1991
                        $ga[$i]['name'] = $obj->name;
1992
                    }
1993
1994
                    $i++;
1995
                }
1996
            }
1997
            return $ga;
1998
        }
1999
        else
2000
        {
2001
            dol_print_error($this->db);
2002
            return -1;
2003
        }
2004
    }
2005
2006
    /**
2007
     *	Delete askprice
2008
     *
2009
     *	@param	User	$user        	Object user that delete
2010
     *	@param	int		$notrigger		1=Does not execute triggers, 0= execute triggers
2011
     *	@return	int						1 if ok, otherwise if error
2012
     */
2013
    public function delete($user, $notrigger = 0)
2014
    {
2015
        global $conf,$langs;
2016
        require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2017
2018
        $error=0;
2019
2020
        $this->db->begin();
2021
2022
        if (! $notrigger)
2023
        {
2024
            // Call trigger
2025
            $result=$this->call_trigger('SUPPLIER_PROPOSAL_DELETE', $user);
2026
            if ($result < 0) { $error++; }
2027
            // End call triggers
2028
        }
2029
2030
        if (! $error)
2031
        {
2032
            $sql = "DELETE FROM ".MAIN_DB_PREFIX."supplier_proposaldet WHERE fk_supplier_proposal = ".$this->id;
2033
            if ($this->db->query($sql))
2034
            {
2035
                $sql = "DELETE FROM ".MAIN_DB_PREFIX."supplier_proposal WHERE rowid = ".$this->id;
2036
                if ($this->db->query($sql))
2037
                {
2038
                    // Delete linked object
2039
                    $res = $this->deleteObjectLinked();
2040
                    if ($res < 0) $error++;
2041
2042
                    if (! $error)
2043
                    {
2044
                        // We remove directory
2045
                        $ref = dol_sanitizeFileName($this->ref);
2046
                        if ($conf->supplier_proposal->dir_output && !empty($this->ref))
2047
                        {
2048
                            $dir = $conf->supplier_proposal->dir_output . "/" . $ref ;
2049
                            $file = $dir . "/" . $ref . ".pdf";
2050
                            if (file_exists($file))
2051
                            {
2052
                                dol_delete_preview($this);
2053
2054
                                if (! dol_delete_file($file, 0, 0, 0, $this)) // For triggers
2055
                                {
2056
                                    $this->error='ErrorFailToDeleteFile';
2057
                                    $this->errors=array('ErrorFailToDeleteFile');
2058
                                    $this->db->rollback();
2059
                                    return 0;
2060
                                }
2061
                            }
2062
                            if (file_exists($dir))
2063
                            {
2064
                                $res=@dol_delete_dir_recursive($dir);
2065
                                if (! $res)
2066
                                {
2067
                                    $this->error='ErrorFailToDeleteDir';
2068
                                    $this->errors=array('ErrorFailToDeleteDir');
2069
                                    $this->db->rollback();
2070
                                    return 0;
2071
                                }
2072
                            }
2073
                        }
2074
                    }
2075
2076
                    // Removed extrafields
2077
                    if (! $error)
2078
                    {
2079
                        if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
2080
                        {
2081
                            $result=$this->deleteExtraFields();
2082
                            if ($result < 0)
2083
                            {
2084
                                $error++;
2085
                                $errorflag=-4;
2086
                                dol_syslog(get_class($this)."::delete erreur ".$errorflag." ".$this->error, LOG_ERR);
2087
                            }
2088
                        }
2089
                    }
2090
2091
                    if (! $error)
2092
                    {
2093
                        dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
2094
                        $this->db->commit();
2095
                        return 1;
2096
                    }
2097
                    else
2098
                    {
2099
                        $this->error=$this->db->lasterror();
2100
                        $this->db->rollback();
2101
                        return 0;
2102
                    }
2103
                }
2104
                else
2105
                {
2106
                    $this->error=$this->db->lasterror();
2107
                    $this->db->rollback();
2108
                    return -3;
2109
                }
2110
            }
2111
            else
2112
            {
2113
                $this->error=$this->db->lasterror();
2114
                $this->db->rollback();
2115
                return -2;
2116
            }
2117
        }
2118
        else
2119
        {
2120
            $this->db->rollback();
2121
            return -1;
2122
        }
2123
    }
2124
2125
    /**
2126
     *	Object SupplierProposal Information
2127
     *
2128
     * 	@param	int		$id		Proposal id
2129
     *  @return	void
2130
     */
2131
    public function info($id)
2132
    {
2133
        $sql = "SELECT c.rowid, ";
2134
        $sql.= " c.datec, c.date_valid as datev, c.date_cloture as dateo,";
2135
        $sql.= " c.fk_user_author, c.fk_user_valid, c.fk_user_cloture";
2136
        $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposal as c";
2137
        $sql.= " WHERE c.rowid = ".$id;
2138
2139
        $result = $this->db->query($sql);
2140
2141
        if ($result)
2142
        {
2143
            if ($this->db->num_rows($result))
2144
            {
2145
                $obj = $this->db->fetch_object($result);
2146
2147
                $this->id                = $obj->rowid;
2148
2149
                $this->date_creation     = $this->db->jdate($obj->datec);
2150
                $this->date_validation   = $this->db->jdate($obj->datev);
2151
                $this->date_cloture      = $this->db->jdate($obj->dateo);
2152
2153
                $cuser = new User($this->db);
2154
                $cuser->fetch($obj->fk_user_author);
2155
                $this->user_creation     = $cuser;
2156
2157
                if ($obj->fk_user_valid)
2158
                {
2159
                    $vuser = new User($this->db);
2160
                    $vuser->fetch($obj->fk_user_valid);
2161
                    $this->user_validation     = $vuser;
2162
                }
2163
2164
                if ($obj->fk_user_cloture)
2165
                {
2166
                    $cluser = new User($this->db);
2167
                    $cluser->fetch($obj->fk_user_cloture);
2168
                    $this->user_cloture     = $cluser;
2169
                }
2170
            }
2171
            $this->db->free($result);
2172
        }
2173
        else
2174
        {
2175
            dol_print_error($this->db);
2176
        }
2177
    }
2178
2179
2180
    /**
2181
     *    	Return label of status of proposal (draft, validated, ...)
2182
     *
2183
     *    	@param      int			$mode        0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
2184
     *    	@return     string		Label
2185
     */
2186
    public function getLibStatut($mode = 0)
2187
    {
2188
        return $this->LibStatut($this->statut, $mode);
2189
    }
2190
2191
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2192
    /**
2193
     *  Return label of a status (draft, validated, ...)
2194
     *
2195
     *  @param      int			$statut		id statut
2196
     *  @param      int			$mode      	0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
2197
     *  @return     string      Label
2198
     */
2199
    public function LibStatut($statut, $mode = 1)
2200
    {
2201
        // phpcs:enable
2202
        // Init/load array of translation of status
2203
        if (empty($this->labelstatut) || empty($this->labelstatut_short))
2204
        {
2205
            global $langs;
2206
            $langs->load("supplier_proposal");
2207
            $this->labelstatut[0]=$langs->trans("SupplierProposalStatusDraft");
2208
            $this->labelstatut[1]=$langs->trans("SupplierProposalStatusValidated");
2209
            $this->labelstatut[2]=$langs->trans("SupplierProposalStatusSigned");
2210
            $this->labelstatut[3]=$langs->trans("SupplierProposalStatusNotSigned");
2211
            $this->labelstatut[4]=$langs->trans("SupplierProposalStatusClosed");
2212
            $this->labelstatut_short[0]=$langs->trans("SupplierProposalStatusDraftShort");
2213
            $this->labelstatut_short[1]=$langs->trans("Opened");
2214
            $this->labelstatut_short[2]=$langs->trans("SupplierProposalStatusSignedShort");
2215
            $this->labelstatut_short[3]=$langs->trans("SupplierProposalStatusNotSignedShort");
2216
            $this->labelstatut_short[4]=$langs->trans("SupplierProposalStatusClosedShort");
2217
        }
2218
2219
        $statuttrans='';
2220
        if ($statut==0) $statuttrans='statut0';
2221
        elseif ($statut==1) $statuttrans='statut1';
2222
        elseif ($statut==2) $statuttrans='statut3';
2223
        elseif ($statut==3) $statuttrans='statut5';
2224
        elseif ($statut==4) $statuttrans='statut6';
2225
2226
        if ($mode == 0)	return $this->labelstatut[$statut];
2227
        elseif ($mode == 1)	return $this->labelstatut_short[$statut];
2228
        elseif ($mode == 2)	return img_picto($this->labelstatut[$statut], $statuttrans).' '.$this->labelstatut_short[$statut];
2229
        elseif ($mode == 3)	return img_picto($this->labelstatut[$statut], $statuttrans);
2230
        elseif ($mode == 4)	return img_picto($this->labelstatut[$statut], $statuttrans).' '.$this->labelstatut[$statut];
2231
        elseif ($mode == 5)	return '<span class="hideonsmartphone">'.$this->labelstatut_short[$statut].' </span>'.img_picto($this->labelstatut[$statut], $statuttrans);
2232
        elseif ($mode == 6)	return '<span class="hideonsmartphone">'.$this->labelstatut[$statut].' </span>'.img_picto($this->labelstatut[$statut], $statuttrans);
2233
    }
2234
2235
2236
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2237
    /**
2238
     *      Load indicators for dashboard (this->nbtodo and this->nbtodolate)
2239
     *
2240
     *      @param          User	$user   Object user
2241
     *      @param          int		$mode   "opened" for askprice to close, "signed" for proposal to invoice
2242
     *      @return         int             <0 if KO, >0 if OK
2243
     */
2244
    public function load_board($user, $mode)
2245
    {
2246
        // phpcs:enable
2247
        global $conf, $user, $langs;
2248
2249
        $now=dol_now();
2250
2251
        $this->nbtodo=$this->nbtodolate=0;
2252
        $clause = " WHERE";
2253
2254
        $sql = "SELECT p.rowid, p.ref, p.datec as datec";
2255
        $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposal as p";
2256
        if (!$user->rights->societe->client->voir && !$user->socid)
2257
        {
2258
            $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc";
2259
            $sql.= " WHERE sc.fk_user = " .$user->id;
2260
            $clause = " AND";
2261
        }
2262
        $sql.= $clause." p.entity IN (".getEntity('supplier_proposal').")";
2263
        if ($mode == 'opened') $sql.= " AND p.fk_statut = 1";
2264
        if ($mode == 'signed') $sql.= " AND p.fk_statut = 2";
2265
        if ($user->socid) $sql.= " AND p.fk_soc = ".$user->socid;
2266
2267
        $resql=$this->db->query($sql);
2268
        if ($resql)
2269
        {
2270
			$label = $labelShort = '';
2271
            if ($mode == 'opened') {
2272
                $delay_warning=$conf->supplier_proposal->cloture->warning_delay;
2273
                $statut = self::STATUS_VALIDATED;
2274
                $label = $langs->trans("SupplierProposalsToClose");
2275
                $labelShort = $langs->trans("ToAcceptRefuse");
2276
            }
2277
            if ($mode == 'signed') {
2278
                $delay_warning=$conf->supplier_proposal->facturation->warning_delay;
2279
                $statut = self::STATUS_SIGNED;
2280
                $label = $langs->trans("SupplierProposalsToProcess");      // May be billed or ordered
2281
				$labelShort = $langs->trans("ToClose");
2282
            }
2283
2284
            $response = new WorkboardResponse();
2285
            $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...
2286
            $response->label = $label;
2287
            $response->labelShort = $labelShort;
2288
            $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...
2289
            $response->img = img_object('', "propal");
2290
2291
            // This assignment in condition is not a bug. It allows walking the results.
2292
            while ($obj=$this->db->fetch_object($resql))
2293
            {
2294
                $response->nbtodo++;
2295
                if ($mode == 'opened')
2296
                {
2297
                    $datelimit = $this->db->jdate($obj->datefin);
2298
                    if ($datelimit < ($now - $delay_warning))
2299
                    {
2300
                        $response->nbtodolate++;
2301
                    }
2302
                }
2303
                // TODO Definir regle des propales a facturer en retard
2304
                // if ($mode == 'signed' && ! count($this->FactureListeArray($obj->rowid))) $this->nbtodolate++;
2305
            }
2306
            return $response;
2307
        }
2308
        else
2309
        {
2310
            $this->error=$this->db->lasterror();
2311
            return -1;
2312
        }
2313
    }
2314
2315
2316
    /**
2317
     *  Initialise an instance with random values.
2318
     *  Used to build previews or test instances.
2319
     *	id must be 0 if object instance is a specimen.
2320
     *
2321
     *  @return	void
2322
     */
2323
    public function initAsSpecimen()
2324
    {
2325
        global $user,$langs,$conf;
2326
2327
        // Load array of products prodids
2328
        $num_prods = 0;
2329
        $prodids = array();
2330
        $sql = "SELECT rowid";
2331
        $sql.= " FROM ".MAIN_DB_PREFIX."product";
2332
        $sql.= " WHERE entity IN (".getEntity('product').")";
2333
        $resql = $this->db->query($sql);
2334
        if ($resql)
2335
        {
2336
            $num_prods = $this->db->num_rows($resql);
2337
            $i = 0;
2338
            while ($i < $num_prods)
2339
            {
2340
                $i++;
2341
                $row = $this->db->fetch_row($resql);
2342
                $prodids[$i] = $row[0];
2343
            }
2344
        }
2345
2346
        // Initialise parametres
2347
        $this->id=0;
2348
        $this->ref = 'SPECIMEN';
2349
        $this->specimen=1;
2350
        $this->socid = 1;
2351
        $this->date = time();
2352
        $this->cond_reglement_id   = 1;
2353
        $this->cond_reglement_code = 'RECEP';
2354
        $this->mode_reglement_id   = 7;
2355
        $this->mode_reglement_code = 'CHQ';
2356
        $this->note_public='This is a comment (public)';
2357
        $this->note_private='This is a comment (private)';
2358
        // Lines
2359
        $nbp = 5;
2360
        $xnbp = 0;
2361
        while ($xnbp < $nbp)
2362
        {
2363
            $line=new SupplierProposalLine($this->db);
2364
            $line->desc=$langs->trans("Description")." ".$xnbp;
2365
            $line->qty=1;
2366
            $line->subprice=100;
2367
            $line->price=100;
0 ignored issues
show
Bug introduced by
The property price does not exist on SupplierProposalLine. Did you mean price_level?
Loading history...
2368
            $line->tva_tx=19.6;
2369
            $line->localtax1_tx=0;
2370
            $line->localtax2_tx=0;
2371
            if ($xnbp == 2)
2372
            {
2373
                $line->total_ht=50;
2374
                $line->total_ttc=59.8;
2375
                $line->total_tva=9.8;
2376
                $line->remise_percent=50;
2377
            }
2378
            else
2379
            {
2380
                $line->total_ht=100;
2381
                $line->total_ttc=119.6;
2382
                $line->total_tva=19.6;
2383
                $line->remise_percent=00;
2384
            }
2385
2386
            if ($num_prods > 0)
2387
            {
2388
                $prodid = mt_rand(1, $num_prods);
2389
                $line->fk_product=$prodids[$prodid];
2390
            }
2391
2392
            $this->lines[$xnbp]=$line;
2393
2394
            $this->total_ht       += $line->total_ht;
2395
            $this->total_tva      += $line->total_tva;
2396
            $this->total_ttc      += $line->total_ttc;
2397
2398
            $xnbp++;
2399
        }
2400
    }
2401
2402
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2403
    /**
2404
     *      Charge indicateurs this->nb de tableau de bord
2405
     *
2406
     *      @return     int         <0 if ko, >0 if ok
2407
     */
2408
    public function load_state_board()
2409
    {
2410
        // phpcs:enable
2411
        global $conf, $user;
2412
2413
        $this->nb=array();
2414
        $clause = "WHERE";
2415
2416
        $sql = "SELECT count(p.rowid) as nb";
2417
        $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposal as p";
2418
        $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
2419
        if (!$user->rights->societe->client->voir && !$user->socid)
2420
        {
2421
            $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
2422
            $sql.= " WHERE sc.fk_user = " .$user->id;
2423
            $clause = "AND";
2424
        }
2425
        $sql.= " ".$clause." p.entity IN (".getEntity('supplier_proposal').")";
2426
2427
        $resql=$this->db->query($sql);
2428
        if ($resql)
2429
        {
2430
            // This assignment in condition is not a bug. It allows walking the results.
2431
            while ($obj=$this->db->fetch_object($resql))
2432
            {
2433
                $this->nb["askprice"]=$obj->nb;
2434
            }
2435
            $this->db->free($resql);
2436
            return 1;
2437
        }
2438
        else
2439
        {
2440
            dol_print_error($this->db);
2441
            $this->error=$this->db->lasterror();
2442
            return -1;
2443
        }
2444
    }
2445
2446
2447
    /**
2448
     *  Returns the reference to the following non used Proposal used depending on the active numbering module
2449
     *  defined into SUPPLIER_PROPOSAL_ADDON
2450
     *
2451
     *  @param	Societe		$soc  	Object thirdparty
2452
     *  @return string      		Reference libre pour la propale
2453
     */
2454
    public function getNextNumRef($soc)
2455
    {
2456
        global $conf, $db, $langs;
2457
        $langs->load("supplier_proposal");
2458
2459
        if (! empty($conf->global->SUPPLIER_PROPOSAL_ADDON))
2460
        {
2461
            $mybool=false;
2462
2463
            $file = $conf->global->SUPPLIER_PROPOSAL_ADDON.".php";
2464
            $classname = $conf->global->SUPPLIER_PROPOSAL_ADDON;
2465
2466
            // Include file with class
2467
            $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2468
            foreach ($dirmodels as $reldir) {
2469
2470
                $dir = dol_buildpath($reldir."core/modules/supplier_proposal/");
2471
2472
                // Load file with numbering class (if found)
2473
                $mybool|=@include_once $dir.$file;
2474
            }
2475
2476
            if (! $mybool)
2477
            {
2478
                dol_print_error('', "Failed to include file ".$file);
2479
                return '';
2480
            }
2481
2482
            $obj = new $classname();
2483
            $numref = "";
2484
            $numref = $obj->getNextValue($soc, $this);
2485
2486
            if ($numref != "")
2487
            {
2488
                return $numref;
2489
            }
2490
            else
2491
            {
2492
                $this->error=$obj->error;
2493
                return "";
2494
            }
2495
        }
2496
        else
2497
        {
2498
            $langs->load("errors");
2499
            print $langs->trans("Error")." ".$langs->trans("ErrorModuleSetupNotComplete", $langs->transnoentitiesnoconv("SupplierProposal"));
2500
            return "";
2501
        }
2502
    }
2503
2504
    /**
2505
     *	Return clicable link of object (with eventually picto)
2506
     *
2507
     *	@param      int		$withpicto					Add picto into link
2508
     *	@param      string	$option						Where point the link ('compta', 'expedition', 'document', ...)
2509
     *	@param      string	$get_params    				Parametres added to url
2510
     *  @param	    int   	$notooltip					1=Disable tooltip
2511
     *  @param      int     $save_lastsearch_value		-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
2512
     *	@return     string          					String with URL
2513
     */
2514
    public function getNomUrl($withpicto = 0, $option = '', $get_params = '', $notooltip = 0, $save_lastsearch_value = -1)
2515
    {
2516
        global $langs, $conf, $user;
2517
2518
        if (! empty($conf->dol_no_mouse_hover)) $notooltip=1;   // Force disable tooltips
2519
2520
        $url='';
2521
        $result='';
2522
2523
        $label='<u>'.$langs->trans("ShowSupplierProposal").'</u>';
2524
        if (! empty($this->ref))
2525
        $label.= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
2526
        if (! empty($this->ref_fourn))
2527
            $label.= '<br><b>'.$langs->trans('RefSupplier').':</b> '.$this->ref_fourn;
2528
        if (! empty($this->total_ht))
2529
            $label.= '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
2530
        if (! empty($this->total_tva))
2531
            $label.= '<br><b>' . $langs->trans('VAT') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
2532
        if (! empty($this->total_ttc))
2533
            $label.= '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
2534
        if ($option == '') {
2535
            $url = DOL_URL_ROOT.'/supplier_proposal/card.php?id='.$this->id. $get_params;
2536
        }
2537
        if ($option == 'document') {
2538
            $url = DOL_URL_ROOT.'/supplier_proposal/document.php?id='.$this->id. $get_params;
2539
        }
2540
2541
        if ($option !== 'nolink')
2542
        {
2543
            // Add param to save lastsearch_values or not
2544
            $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
2545
            if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
2546
            if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
2547
        }
2548
2549
        $linkclose='';
2550
        if (empty($notooltip) && $user->rights->propal->lire)
2551
        {
2552
            if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
2553
            {
2554
                $label=$langs->trans("ShowSupplierProposal");
2555
                $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
2556
            }
2557
            $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
2558
            $linkclose.=' class="classfortooltip"';
2559
        }
2560
2561
        $linkstart = '<a href="'.$url.'"';
2562
        $linkstart.=$linkclose.'>';
2563
        $linkend='</a>';
2564
2565
        $picto='supplier_proposal';
2566
2567
        $result .= $linkstart;
2568
        if ($withpicto) $result.=img_object(($notooltip?'':$label), $this->picto, ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
2569
        if ($withpicto != 2) $result.= $this->ref;
2570
        $result .= $linkend;
2571
2572
        return $result;
2573
    }
2574
2575
    /**
2576
     * 	Retrieve an array of supplier proposal lines
2577
     *
2578
     * 	@return int		>0 if OK, <0 if KO
2579
     */
2580
    public function getLinesArray()
2581
    {
2582
        // For other object, here we call fetch_lines. But fetch_lines does not exists on supplier proposal
2583
2584
        $sql = 'SELECT pt.rowid, pt.label as custom_label, pt.description, pt.fk_product, pt.fk_remise_except,';
2585
        $sql.= ' pt.qty, pt.tva_tx, pt.remise_percent, pt.subprice, pt.info_bits,';
2586
        $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,';
2587
        $sql.= ' pt.product_type, pt.rang, pt.fk_parent_line,';
2588
        $sql.= ' p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid,';
2589
        $sql.= ' p.description as product_desc, pt.ref_fourn as ref_supplier,';
2590
        $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';
2591
        $sql.= ' FROM '.MAIN_DB_PREFIX.'supplier_proposaldet as pt';
2592
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pt.fk_product=p.rowid';
2593
        $sql.= ' WHERE pt.fk_supplier_proposal = '.$this->id;
2594
        $sql.= ' ORDER BY pt.rang ASC, pt.rowid';
2595
2596
        dol_syslog(get_class($this).'::getLinesArray', LOG_DEBUG);
2597
        $resql = $this->db->query($sql);
2598
        if ($resql)
2599
        {
2600
            $num = $this->db->num_rows($resql);
2601
            $i = 0;
2602
2603
            while ($i < $num)
2604
            {
2605
                $obj = $this->db->fetch_object($resql);
2606
2607
                $this->lines[$i]					= new SupplierProposalLine($this->db);
2608
                $this->lines[$i]->id				= $obj->rowid; // for backward compatibility
2609
                $this->lines[$i]->rowid				= $obj->rowid;
2610
                $this->lines[$i]->label 			= $obj->custom_label;
2611
                $this->lines[$i]->description 		= $obj->description;
2612
                $this->lines[$i]->fk_product		= $obj->fk_product;
2613
                $this->lines[$i]->ref				= $obj->ref;
2614
                $this->lines[$i]->product_label		= $obj->product_label;
2615
                $this->lines[$i]->product_desc		= $obj->product_desc;
2616
                $this->lines[$i]->fk_product_type	= $obj->fk_product_type;  // deprecated
2617
                $this->lines[$i]->product_type		= $obj->product_type;
2618
                $this->lines[$i]->qty				= $obj->qty;
2619
                $this->lines[$i]->subprice			= $obj->subprice;
2620
                $this->lines[$i]->fk_remise_except 	= $obj->fk_remise_except;
2621
                $this->lines[$i]->remise_percent	= $obj->remise_percent;
2622
                $this->lines[$i]->tva_tx			= $obj->tva_tx;
2623
                $this->lines[$i]->info_bits			= $obj->info_bits;
2624
                $this->lines[$i]->total_ht			= $obj->total_ht;
2625
                $this->lines[$i]->total_tva			= $obj->total_tva;
2626
                $this->lines[$i]->total_ttc			= $obj->total_ttc;
2627
                $this->lines[$i]->fk_fournprice		= $obj->fk_fournprice;
2628
                $marginInfos						= getMarginInfos($obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, $this->lines[$i]->fk_fournprice, $obj->pa_ht);
2629
                $this->lines[$i]->pa_ht				= $marginInfos[0];
2630
                $this->lines[$i]->marge_tx			= $marginInfos[1];
2631
                $this->lines[$i]->marque_tx			= $marginInfos[2];
2632
                $this->lines[$i]->fk_parent_line	= $obj->fk_parent_line;
2633
                $this->lines[$i]->special_code		= $obj->special_code;
2634
                $this->lines[$i]->rang				= $obj->rang;
2635
2636
                $this->lines[$i]->ref_fourn				= $obj->ref_supplier;	// deprecated
2637
                $this->lines[$i]->ref_supplier			= $obj->ref_supplier;
2638
2639
                // Multicurrency
2640
                $this->lines[$i]->fk_multicurrency 			= $obj->fk_multicurrency;
2641
                $this->lines[$i]->multicurrency_code 		= $obj->multicurrency_code;
2642
                $this->lines[$i]->multicurrency_subprice 	= $obj->multicurrency_subprice;
2643
                $this->lines[$i]->multicurrency_total_ht 	= $obj->multicurrency_total_ht;
2644
                $this->lines[$i]->multicurrency_total_tva 	= $obj->multicurrency_total_tva;
2645
                $this->lines[$i]->multicurrency_total_ttc 	= $obj->multicurrency_total_ttc;
2646
                $this->lines[$i]->fk_unit				 	= $obj->fk_unit;
2647
2648
                $i++;
2649
            }
2650
            $this->db->free($resql);
2651
2652
            return 1;
2653
        }
2654
        else
2655
        {
2656
            $this->error=$this->db->error();
2657
            return -1;
2658
        }
2659
    }
2660
2661
    /**
2662
     *  Create a document onto disk according to template module.
2663
     *
2664
     * 	@param	    string		$modele			Force model to use ('' to not force)
2665
     * 	@param		Translate	$outputlangs	Object langs to use for output
2666
     *  @param      int			$hidedetails    Hide details of lines
2667
     *  @param      int			$hidedesc       Hide description
2668
     *  @param      int			$hideref        Hide ref
2669
         *  @param   null|array  $moreparams     Array to provide more information
2670
     * 	@return     int         				0 if KO, 1 if OK
2671
     */
2672
    public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
2673
    {
2674
        global $conf, $langs;
2675
2676
        $langs->load("supplier_proposal");
2677
2678
        if (! dol_strlen($modele)) {
2679
2680
            $modele = 'aurore';
2681
2682
            if ($this->modelpdf) {
2683
                $modele = $this->modelpdf;
2684
            } elseif (! empty($conf->global->SUPPLIER_PROPOSAL_ADDON_PDF)) {
2685
                $modele = $conf->global->SUPPLIER_PROPOSAL_ADDON_PDF;
2686
            }
2687
        }
2688
2689
        $modelpath = "core/modules/supplier_proposal/doc/";
2690
2691
        return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2692
    }
2693
2694
2695
    /**
2696
     * Function used to replace a thirdparty id with another one.
2697
     *
2698
     * @param DoliDB $db Database handler
2699
     * @param int $origin_id Old thirdparty id
2700
     * @param int $dest_id New thirdparty id
2701
     * @return bool
2702
     */
2703
    public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
2704
    {
2705
        $tables = array(
2706
            'supplier_proposal'
2707
        );
2708
2709
        return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
2710
    }
2711
}
2712
2713
2714
/**
2715
 *	Class to manage supplier_proposal lines
2716
 */
2717
class SupplierProposalLine extends CommonObjectLine
2718
{
2719
    /**
2720
     * @var DoliDB Database handler.
2721
     */
2722
    public $db;
2723
2724
    /**
2725
     * @var string Error code (or message)
2726
     */
2727
    public $error='';
2728
2729
    /**
2730
     * @var string ID to identify managed object
2731
     */
2732
    public $element='supplier_proposaldet';
2733
2734
    /**
2735
     * @var string Name of table without prefix where object is stored
2736
     */
2737
    public $table_element='supplier_proposaldet';
2738
2739
    public $oldline;
2740
2741
    /**
2742
     * @var int ID
2743
     */
2744
    public $id;
2745
2746
    /**
2747
     * @var int ID
2748
     */
2749
    public $fk_supplier_proposal;
2750
2751
    /**
2752
     * @var int ID
2753
     */
2754
    public $fk_parent_line;
2755
2756
    public $desc;          	// Description ligne
2757
2758
    /**
2759
     * @var int ID
2760
     */
2761
    public $fk_product;		// Id produit predefini
2762
2763
    /**
2764
     * @deprecated
2765
     * @see $product_type
2766
     */
2767
    public $fk_product_type;
2768
    /**
2769
     * Product type
2770
     * @var int
2771
     * @see Product::TYPE_PRODUCT, Product::TYPE_SERVICE
2772
     */
2773
    public $product_type = Product::TYPE_PRODUCT;
2774
2775
    public $qty;
2776
    public $tva_tx;
2777
    public $subprice;
2778
    public $remise_percent;
2779
2780
    /**
2781
     * @var int ID
2782
     */
2783
    public $fk_remise_except;
2784
2785
    public $rang = 0;
2786
2787
    /**
2788
     * @var int ID
2789
     */
2790
    public $fk_fournprice;
2791
2792
    public $pa_ht;
2793
    public $marge_tx;
2794
    public $marque_tx;
2795
2796
    public $special_code;	// Tag for special lines (exlusive tags)
2797
    // 1: frais de port
2798
    // 2: ecotaxe
2799
    // 3: option line (when qty = 0)
2800
2801
    public $info_bits = 0;	// Liste d'options cumulables:
2802
    // Bit 0: 	0 si TVA normal - 1 si TVA NPR
2803
    // Bit 1:	0 ligne normale - 1 si ligne de remise fixe
2804
2805
    public $total_ht;			// Total HT  de la ligne toute quantite et incluant la remise ligne
2806
    public $total_tva;			// Total TVA de la ligne toute quantite et incluant la remise ligne
2807
    public $total_ttc;			// Total TTC de la ligne toute quantite et incluant la remise ligne
2808
2809
    public $date_start;
2810
    public $date_end;
2811
2812
    // From llx_product
2813
    /**
2814
     * @deprecated
2815
     * @see product_ref
2816
     */
2817
    public $ref;
2818
2819
    /**
2820
     * Product reference
2821
     * @var string
2822
     */
2823
    public $product_ref;
2824
2825
    /**
2826
     * @deprecated
2827
     * @see $product_label
2828
     */
2829
    public $libelle;
2830
2831
    /**
2832
     *  Product label
2833
     * @var string
2834
     */
2835
    public $product_label;
2836
2837
    /**
2838
     * Product description
2839
     * @var string
2840
     */
2841
    public $product_desc;
2842
2843
    public $localtax1_tx;		// Local tax 1
2844
    public $localtax2_tx;		// Local tax 2
2845
    public $localtax1_type;	// Local tax 1 type
2846
    public $localtax2_type;	// Local tax 2 type
2847
    public $total_localtax1;  	// Line total local tax 1
2848
    public $total_localtax2;	// Line total local tax 2
2849
2850
    public $skip_update_total; // Skip update price total for special lines
2851
2852
    public $ref_fourn;
2853
    public $ref_supplier;
2854
2855
    // Multicurrency
2856
    /**
2857
     * @var int ID
2858
     */
2859
    public $fk_multicurrency;
2860
2861
    public $multicurrency_code;
2862
    public $multicurrency_subprice;
2863
    public $multicurrency_total_ht;
2864
    public $multicurrency_total_tva;
2865
    public $multicurrency_total_ttc;
2866
2867
    /**
2868
     * 	Class line Contructor
2869
     *
2870
     * 	@param	DoliDB	$db	Database handler
2871
     */
2872
    public function __construct($db)
2873
    {
2874
        $this->db= $db;
2875
    }
2876
2877
    /**
2878
     *	Retrieve the propal line object
2879
     *
2880
     *	@param	int		$rowid		Propal line id
2881
     *	@return	int					<0 if KO, >0 if OK
2882
     */
2883
    public function fetch($rowid)
2884
    {
2885
        $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,';
2886
        $sql.= ' pd.date_start, pd.date_end,';
2887
        $sql.= ' pd.remise, pd.remise_percent, pd.fk_remise_except, pd.subprice,';
2888
        $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,';
2889
        $sql.= ' pd.localtax1_tx, pd.localtax2_tx, pd.total_localtax1, pd.total_localtax2,';
2890
        $sql.= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,';
2891
        $sql.= ' pd.product_type, pd.ref_fourn as ref_produit_fourn,';
2892
        $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';
2893
        $sql.= ' FROM '.MAIN_DB_PREFIX.'supplier_proposaldet as pd';
2894
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pd.fk_product = p.rowid';
2895
        $sql.= ' WHERE pd.rowid = '.$rowid;
2896
2897
        $result = $this->db->query($sql);
2898
        if ($result)
2899
        {
2900
            $objp = $this->db->fetch_object($result);
2901
2902
            $this->id				= $objp->rowid;
2903
            $this->fk_supplier_proposal		= $objp->fk_supplier_proposal;
2904
            $this->fk_parent_line	= $objp->fk_parent_line;
2905
            $this->label			= $objp->custom_label;
2906
            $this->desc				= $objp->description;
2907
            $this->qty				= $objp->qty;
2908
            $this->subprice			= $objp->subprice;
2909
            $this->tva_tx			= $objp->tva_tx;
2910
            $this->remise_percent	= $objp->remise_percent;
2911
            $this->fk_remise_except = $objp->fk_remise_except;
2912
            $this->fk_product		= $objp->fk_product;
2913
            $this->info_bits		= $objp->info_bits;
2914
            $this->date_start		= $this->db->jdate($objp->date_start);
2915
            $this->date_end			= $this->db->jdate($objp->date_end);
2916
2917
            $this->total_ht			= $objp->total_ht;
2918
            $this->total_tva		= $objp->total_tva;
2919
            $this->total_ttc		= $objp->total_ttc;
2920
2921
            $this->fk_fournprice	= $objp->fk_fournprice;
2922
2923
            $marginInfos			= getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht);
2924
            $this->pa_ht			= $marginInfos[0];
2925
            $this->marge_tx			= $marginInfos[1];
2926
            $this->marque_tx		= $marginInfos[2];
2927
2928
            $this->special_code		= $objp->special_code;
2929
            $this->product_type		= $objp->product_type;
2930
            $this->rang				= $objp->rang;
2931
2932
            $this->ref				= $objp->product_ref;      // deprecated
2933
            $this->product_ref		= $objp->product_ref;
2934
            $this->libelle			= $objp->product_label;  // deprecated
2935
            $this->product_label	= $objp->product_label;
2936
            $this->product_desc		= $objp->product_desc;
2937
2938
            $this->ref_fourn		= $objp->ref_produit_forun;
2939
2940
            // Multicurrency
2941
            $this->fk_multicurrency 		= $objp->fk_multicurrency;
2942
            $this->multicurrency_code 		= $objp->multicurrency_code;
2943
            $this->multicurrency_subprice 	= $objp->multicurrency_subprice;
2944
            $this->multicurrency_total_ht 	= $objp->multicurrency_total_ht;
2945
            $this->multicurrency_total_tva 	= $objp->multicurrency_total_tva;
2946
            $this->multicurrency_total_ttc 	= $objp->multicurrency_total_ttc;
2947
            $this->fk_unit				 	= $objp->fk_unit;
2948
2949
            $this->db->free($result);
2950
        }
2951
        else
2952
        {
2953
            dol_print_error($this->db);
2954
        }
2955
    }
2956
2957
    /**
2958
     *  Insert object line propal in database
2959
     *
2960
     *	@param		int		$notrigger		1=Does not execute triggers, 0= execute triggers
2961
     *	@return		int						<0 if KO, >0 if OK
2962
     */
2963
    public function insert($notrigger = 0)
2964
    {
2965
        global $conf,$langs,$user;
2966
2967
        $error=0;
2968
2969
        dol_syslog(get_class($this)."::insert rang=".$this->rang);
2970
2971
        // Clean parameters
2972
        if (empty($this->tva_tx)) $this->tva_tx=0;
2973
        if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
2974
        if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
2975
        if (empty($this->localtax1_type)) $this->localtax1_type=0;
2976
        if (empty($this->localtax2_type)) $this->localtax2_type=0;
2977
        if (empty($this->total_localtax1)) $this->total_localtax1=0;
2978
        if (empty($this->total_localtax2)) $this->total_localtax2=0;
2979
        if (empty($this->rang)) $this->rang=0;
2980
        if (empty($this->remise)) $this->remise=0;
2981
        if (empty($this->remise_percent)) $this->remise_percent=0;
2982
        if (empty($this->info_bits)) $this->info_bits=0;
2983
        if (empty($this->special_code)) $this->special_code=0;
2984
        if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
2985
        if (empty($this->fk_fournprice)) $this->fk_fournprice=0;
2986
        if (empty($this->fk_unit)) $this->fk_unit=0;
2987
        if (empty($this->subprice)) $this->subprice=0;
2988
2989
        if (empty($this->pa_ht)) $this->pa_ht=0;
2990
2991
        // if buy price not defined, define buyprice as configured in margin admin
2992
        if ($this->pa_ht == 0)
2993
        {
2994
            if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0)
2995
            {
2996
                return $result;
2997
            }
2998
            else
2999
            {
3000
                $this->pa_ht = $result;
3001
            }
3002
        }
3003
3004
        // Check parameters
3005
        if ($this->product_type < 0) return -1;
3006
3007
        $this->db->begin();
3008
3009
        // Insert line into database
3010
        $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'supplier_proposaldet';
3011
        $sql.= ' (fk_supplier_proposal, fk_parent_line, label, description, fk_product, product_type,';
3012
        $sql.= ' date_start, date_end,';
3013
        $sql.= ' fk_remise_except, qty, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3014
        $sql.= ' subprice, remise_percent, ';
3015
        $sql.= ' info_bits, ';
3016
        $sql.= ' total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, fk_product_fournisseur_price, buy_price_ht, special_code, rang,';
3017
        $sql.= ' ref_fourn,';
3018
        $sql.= ' fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc, fk_unit)';
3019
        $sql.= " VALUES (".$this->fk_supplier_proposal.",";
3020
        $sql.= " ".($this->fk_parent_line>0?"'".$this->db->escape($this->fk_parent_line)."'":"null").",";
3021
        $sql.= " ".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null").",";
3022
        $sql.= " '".$this->db->escape($this->desc)."',";
3023
        $sql.= " ".($this->fk_product?"'".$this->db->escape($this->fk_product)."'":"null").",";
3024
        $sql.= " '".$this->db->escape($this->product_type)."',";
3025
        $sql.= " ".($this->date_start ? "'".$this->db->idate($this->date_start)."'" : "null").",";
3026
        $sql.= " ".($this->date_end ? "'".$this->db->idate($this->date_end)."'" : "null").",";
3027
        $sql.= " ".($this->fk_remise_except?"'".$this->db->escape($this->fk_remise_except)."'":"null").",";
3028
        $sql.= " ".price2num($this->qty).",";
3029
        $sql.= " ".price2num($this->tva_tx).",";
3030
        $sql.= " ".price2num($this->localtax1_tx).",";
3031
        $sql.= " ".price2num($this->localtax2_tx).",";
3032
        $sql.= " '".$this->db->escape($this->localtax1_type)."',";
3033
        $sql.= " '".$this->db->escape($this->localtax2_type)."',";
3034
        $sql.= " ".(!empty($this->subprice)?price2num($this->subprice):"null").",";
3035
        $sql.= " ".price2num($this->remise_percent).",";
3036
        $sql.= " ".(isset($this->info_bits)?"'".$this->db->escape($this->info_bits)."'":"null").",";
3037
        $sql.= " ".price2num($this->total_ht).",";
3038
        $sql.= " ".price2num($this->total_tva).",";
3039
        $sql.= " ".price2num($this->total_localtax1).",";
3040
        $sql.= " ".price2num($this->total_localtax2).",";
3041
        $sql.= " ".price2num($this->total_ttc).",";
3042
        $sql.= " ".(!empty($this->fk_fournprice)?"'".$this->db->escape($this->fk_fournprice)."'":"null").",";
3043
        $sql.= " ".(isset($this->pa_ht)?"'".price2num($this->pa_ht)."'":"null").",";
3044
        $sql.= ' '.$this->special_code.',';
3045
        $sql.= ' '.$this->rang.',';
3046
        $sql.= " '".$this->db->escape($this->ref_fourn)."'";
3047
        $sql.= ", ".($this->fk_multicurrency > 0?$this->fk_multicurrency:'null');
3048
        $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
3049
        $sql.= ", ".$this->multicurrency_subprice;
3050
        $sql.= ", ".$this->multicurrency_total_ht;
3051
        $sql.= ", ".$this->multicurrency_total_tva;
3052
        $sql.= ", ".$this->multicurrency_total_ttc;
3053
        $sql.= ", ".($this->fk_unit?$this->fk_unit:'null');
3054
        $sql.= ')';
3055
3056
        dol_syslog(get_class($this).'::insert', LOG_DEBUG);
3057
        $resql=$this->db->query($sql);
3058
        if ($resql)
3059
        {
3060
            $this->id=$this->db->last_insert_id(MAIN_DB_PREFIX.'supplier_proposaldet');
3061
3062
            if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
3063
            {
3064
                $result=$this->insertExtraFields();
3065
                if ($result < 0)
3066
                {
3067
                    $error++;
3068
                }
3069
            }
3070
3071
            if (! $error && ! $notrigger)
3072
            {
3073
                // Call trigger
3074
                $result=$this->call_trigger('LINESUPPLIER_PROPOSAL_INSERT', $user);
3075
                if ($result < 0)
3076
                {
3077
                    $this->db->rollback();
3078
                    return -1;
3079
                }
3080
                // End call triggers
3081
            }
3082
3083
            $this->db->commit();
3084
            return 1;
3085
        }
3086
        else
3087
        {
3088
            $this->error=$this->db->error()." sql=".$sql;
3089
            $this->db->rollback();
3090
            return -1;
3091
        }
3092
    }
3093
3094
    /**
3095
     * 	Delete line in database
3096
     *
3097
     *	@return	 int  <0 if ko, >0 if ok
3098
     */
3099
    public function delete()
3100
    {
3101
        global $conf,$langs,$user;
3102
3103
        $error=0;
3104
        $this->db->begin();
3105
3106
        $sql = "DELETE FROM ".MAIN_DB_PREFIX."supplier_proposaldet WHERE rowid = ".$this->id;
3107
        dol_syslog("SupplierProposalLine::delete", LOG_DEBUG);
3108
        if ($this->db->query($sql) )
3109
        {
3110
3111
            // Remove extrafields
3112
            if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used
3113
            {
3114
                $result=$this->deleteExtraFields();
3115
                if ($result < 0)
3116
                {
3117
                    $error++;
3118
                    dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
3119
                }
3120
            }
3121
3122
            // Call trigger
3123
            $result=$this->call_trigger('LINESUPPLIER_PROPOSAL_DELETE', $user);
3124
            if ($result < 0)
3125
            {
3126
                $this->db->rollback();
3127
                return -1;
3128
            }
3129
            // End call triggers
3130
3131
            $this->db->commit();
3132
3133
            return 1;
3134
        }
3135
        else
3136
        {
3137
            $this->error=$this->db->error()." sql=".$sql;
3138
            $this->db->rollback();
3139
            return -1;
3140
        }
3141
    }
3142
3143
    /**
3144
     *	Update propal line object into DB
3145
     *
3146
     *	@param 	int		$notrigger	1=Does not execute triggers, 0= execute triggers
3147
     *	@return	int					<0 if ko, >0 if ok
3148
     */
3149
    public function update($notrigger = 0)
3150
    {
3151
        global $conf,$langs,$user;
3152
3153
        $error=0;
3154
3155
        // Clean parameters
3156
        if (empty($this->tva_tx)) $this->tva_tx=0;
3157
        if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
3158
        if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
3159
        if (empty($this->total_localtax1)) $this->total_localtax1=0;
3160
        if (empty($this->total_localtax2)) $this->total_localtax2=0;
3161
        if (empty($this->localtax1_type)) $this->localtax1_type=0;
3162
        if (empty($this->localtax2_type)) $this->localtax2_type=0;
3163
        if (empty($this->marque_tx)) $this->marque_tx=0;
3164
        if (empty($this->marge_tx)) $this->marge_tx=0;
3165
        if (empty($this->remise_percent)) $this->remise_percent=0;
3166
        if (empty($this->info_bits)) $this->info_bits=0;
3167
        if (empty($this->special_code)) $this->special_code=0;
3168
        if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
3169
        if (empty($this->fk_fournprice)) $this->fk_fournprice=0;
3170
        if (empty($this->fk_unit)) $this->fk_unit=0;
3171
        if (empty($this->subprice)) $this->subprice=0;
3172
3173
        if (empty($this->pa_ht)) $this->pa_ht=0;
3174
3175
        // if buy price not defined, define buyprice as configured in margin admin
3176
        if ($this->pa_ht == 0)
3177
        {
3178
            if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0)
3179
            {
3180
                return $result;
3181
            }
3182
            else
3183
            {
3184
                $this->pa_ht = $result;
3185
            }
3186
        }
3187
3188
        $this->db->begin();
3189
3190
        // Mise a jour ligne en base
3191
        $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposaldet SET";
3192
        $sql.= " description='".$this->db->escape($this->desc)."'";
3193
        $sql.= " , label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null");
3194
        $sql.= " , product_type=".$this->product_type;
3195
        $sql.= " , date_start=".($this->date_start ? "'".$this->db->idate($this->date_start)."'" : "null");
3196
        $sql.= " , date_end=".($this->date_end ? "'".$this->db->idate($this->date_end)."'" : "null");
3197
        $sql.= " , tva_tx='".price2num($this->tva_tx)."'";
3198
        $sql.= " , localtax1_tx=".price2num($this->localtax1_tx);
3199
        $sql.= " , localtax2_tx=".price2num($this->localtax2_tx);
3200
        $sql.= " , localtax1_type='".$this->db->escape($this->localtax1_type)."'";
3201
        $sql.= " , localtax2_type='".$this->db->escape($this->localtax2_type)."'";
3202
        $sql.= " , qty='".price2num($this->qty)."'";
3203
        $sql.= " , subprice=".price2num($this->subprice)."";
3204
        $sql.= " , remise_percent=".price2num($this->remise_percent)."";
3205
        $sql.= " , info_bits='".$this->db->escape($this->info_bits)."'";
3206
        if (empty($this->skip_update_total))
3207
        {
3208
            $sql.= " , total_ht=".price2num($this->total_ht)."";
3209
            $sql.= " , total_tva=".price2num($this->total_tva)."";
3210
            $sql.= " , total_ttc=".price2num($this->total_ttc)."";
3211
            $sql.= " , total_localtax1=".price2num($this->total_localtax1)."";
3212
            $sql.= " , total_localtax2=".price2num($this->total_localtax2)."";
3213
        }
3214
        $sql.= " , fk_product_fournisseur_price=".(! empty($this->fk_fournprice)?"'".$this->db->escape($this->fk_fournprice)."'":"null");
3215
        $sql.= " , buy_price_ht=".price2num($this->pa_ht);
3216
        if (strlen($this->special_code)) $sql.= " , special_code=".$this->special_code;
3217
        $sql.= " , fk_parent_line=".($this->fk_parent_line>0?$this->fk_parent_line:"null");
3218
        if (! empty($this->rang)) $sql.= ", rang=".$this->rang;
3219
        $sql.= " , ref_fourn=".(! empty($this->ref_fourn)?"'".$this->db->escape($this->ref_fourn)."'":"null");
3220
        $sql.= " , fk_unit=".($this->fk_unit?$this->fk_unit:'null');
3221
3222
        // Multicurrency
3223
        $sql.= " , multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
3224
        $sql.= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
3225
        $sql.= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
3226
        $sql.= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
3227
3228
        $sql.= " WHERE rowid = ".$this->id;
3229
3230
        dol_syslog(get_class($this)."::update", LOG_DEBUG);
3231
        $resql=$this->db->query($sql);
3232
        if ($resql)
3233
        {
3234
            if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
3235
            {
3236
                $result=$this->insertExtraFields();
3237
                if ($result < 0)
3238
                {
3239
                    $error++;
3240
                }
3241
            }
3242
3243
            if (! $error && ! $notrigger)
3244
            {
3245
                // Call trigger
3246
                $result=$this->call_trigger('LINESUPPLIER_PROPOSAL_UPDATE', $user);
3247
                if ($result < 0)
3248
                {
3249
                    $this->db->rollback();
3250
                    return -1;
3251
                }
3252
                // End call triggers
3253
            }
3254
3255
            $this->db->commit();
3256
            return 1;
3257
        }
3258
        else
3259
        {
3260
            $this->error=$this->db->error();
3261
            $this->db->rollback();
3262
            return -2;
3263
        }
3264
    }
3265
3266
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3267
    /**
3268
     *	Update DB line fields total_xxx
3269
     *	Used by migration
3270
     *
3271
     *	@return		int		<0 if ko, >0 if ok
3272
     */
3273
    public function update_total()
3274
    {
3275
        // phpcs:enable
3276
        $this->db->begin();
3277
3278
        // Mise a jour ligne en base
3279
        $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposaldet SET";
3280
        $sql.= " total_ht=".price2num($this->total_ht, 'MT');
3281
        $sql.= ",total_tva=".price2num($this->total_tva, 'MT');
3282
        $sql.= ",total_ttc=".price2num($this->total_ttc, 'MT');
3283
        $sql.= " WHERE rowid = ".$this->id;
3284
3285
        dol_syslog("SupplierProposalLine::update_total", LOG_DEBUG);
3286
3287
        $resql=$this->db->query($sql);
3288
        if ($resql)
3289
        {
3290
            $this->db->commit();
3291
            return 1;
3292
        }
3293
        else
3294
        {
3295
            $this->error=$this->db->error();
3296
            $this->db->rollback();
3297
            return -2;
3298
        }
3299
    }
3300
}
3301