SupplierProposal::fetch()   C
last analyzed

Complexity

Conditions 8
Paths 28

Size

Total Lines 186
Code Lines 147

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 147
nc 28
nop 2
dl 0
loc 186
rs 6.7555
c 0
b 0
f 0

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
3
/* Copyright (C) 2002-2004  Rodolphe Quiedeville        <[email protected]>
4
 * Copyright (C) 2004       Eric Seigne				    <[email protected]>
5
 * Copyright (C) 2004-2011  Laurent Destailleur		    <[email protected]>
6
 * Copyright (C) 2005       Marc Barilley			    <[email protected]>
7
 * Copyright (C) 2005-2013  Regis Houssin			    <[email protected]>
8
 * Copyright (C) 2006       Andre Cianfarani			<[email protected]>
9
 * Copyright (C) 2008       Raphael Bertrand			<[email protected]>
10
 * Copyright (C) 2010-2020  Juanjo Menent			    <[email protected]>
11
 * Copyright (C) 2010-2018  Philippe Grand			    <[email protected]>
12
 * Copyright (C) 2012-2014  Christophe Battarel  	    <[email protected]>
13
 * Copyright (C) 2013       Florian Henry		  	    <[email protected]>
14
 * Copyright (C) 2014       Marcos García               <[email protected]>
15
 * Copyright (C) 2016       Ferran Marcet               <[email protected]>
16
 * Copyright (C) 2018       Nicolas ZABOURI			    <[email protected]>
17
 * Copyright (C) 2019-2024  Frédéric France             <[email protected]>
18
 * Copyright (C) 2020		Tobias Sekan			    <[email protected]>
19
 * Copyright (C) 2022       Gauthier VERDOL     		<[email protected]>
20
 * Copyright (C) 2024		MDW							<[email protected]>
21
 * Copyright (C) 2024       Rafael San José             <[email protected]>
22
 *
23
 * This program is free software; you can redistribute it and/or modify
24
 * it under the terms of the GNU General Public License as published by
25
 * the Free Software Foundation; either version 3 of the License, or
26
 * (at your option) any later version.
27
 *
28
 * This program is distributed in the hope that it will be useful,
29
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31
 * GNU General Public License for more details.
32
 *
33
 * You should have received a copy of the GNU General Public License
34
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
35
 */
36
37
namespace Dolibarr\Code\SupplierProposal\Classes;
38
39
use Dolibarr\Code\Core\Classes\WorkboardResponse;
40
use Dolibarr\Code\Core\Traits\CommonIncoterm;
41
use Dolibarr\Core\Base\CommonObject;
42
use DoliDB;
43
44
/**
45
 *  \file       htdocs/supplier_proposal/class/supplier_proposal.class.php
46
 *  \brief      File of class to manage supplier proposals
47
 */
48
49
require_once constant('DOL_DOCUMENT_ROOT') . '/margin/lib/margins.lib.php';
50
51
/**
52
 *  Class to manage price ask supplier
53
 */
54
class SupplierProposal extends CommonObject
55
{
56
    use CommonIncoterm;
0 ignored issues
show
Bug introduced by
The trait Dolibarr\Code\Core\Traits\CommonIncoterm requires the property $code which is not provided by Dolibarr\Code\SupplierPr...lasses\SupplierProposal.
Loading history...
57
58
    /**
59
     * @var string ID to identify managed object
60
     */
61
    public $element = 'supplier_proposal';
62
63
    /**
64
     * @var string Name of table without prefix where object is stored
65
     */
66
    public $table_element = 'supplier_proposal';
67
68
    /**
69
     * @var string    Name of subtable line
70
     */
71
    public $table_element_line = 'supplier_proposaldet';
72
73
    /**
74
     * @var string Name of class line
75
     */
76
    public $class_element_line = 'SupplierProposalLine';
77
    /**
78
     * @var string Field with ID of parent key if this field has a parent
79
     */
80
    public $fk_element = 'fk_supplier_proposal';
81
82
    /**
83
     * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
84
     */
85
    public $picto = 'supplier_proposal';
86
87
    /**
88
     * 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
89
     * @var integer
90
     */
91
    public $restrictiononfksoc = 1;
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    protected $table_ref_field = 'ref';
97
98
    public $socid; // Id client
99
100
    /**
101
     * @deprecated
102
     * @see $user_author_id
103
     */
104
    public $author;
105
106
    public $ref_fourn; //Reference saisie lors de l'ajout d'une ligne à la demande
107
    public $ref_supplier; //Reference saisie lors de l'ajout d'une ligne à la demande
108
109
    /**
110
     * @deprecated
111
     */
112
    public $statut; // 0 (draft), 1 (validated), 2 (signed), 3 (not signed), 4 (processed/billed)
113
114
    /**
115
     * @var integer|string Date of proposal
116
     */
117
    public $date;
118
119
    /**
120
     * @var integer|string date_livraison
121
     */
122
    public $delivery_date;
123
124
    /**
125
     * @deprecated
126
     * @see $date_creation
127
     */
128
    public $datec;
129
130
    /**
131
     * @var integer|string date_creation
132
     */
133
    public $date_creation;
134
135
    /**
136
     * @deprecated
137
     * @see $date_validation
138
     */
139
    public $datev;
140
141
    /**
142
     * @var integer|string date_validation
143
     */
144
    public $date_validation;
145
146
147
    public $user_author_id;
148
149
    /**
150
     * @deprecated
151
     * @see $price_ht
152
     */
153
    public $price;
154
155
    /**
156
     * @deprecated
157
     * @see $total_tva
158
     */
159
    public $tva;
160
161
    /**
162
     * @deprecated
163
     * @see $total_ttc
164
     */
165
    public $total;
166
167
    public $cond_reglement_code;
168
    public $cond_reglement_doc;     // label doc
169
170
    public $mode_reglement_code;
171
    /**
172
     * @deprecated
173
     * @var string  Mode reglement
174
     */
175
    public $mode_reglement;
176
177
    public $extraparams = array();
178
    public $lines = array();
179
    public $line;
180
181
    public $labelStatus = array();
182
    public $labelStatusShort = array();
183
184
    public $nbtodo;
185
    public $nbtodolate;
186
187
    // Multicurrency
188
    /**
189
     * @var int ID
190
     */
191
    public $fk_multicurrency;
192
193
    public $multicurrency_code;
194
    public $multicurrency_tx;
195
    public $multicurrency_total_ht;
196
    public $multicurrency_total_tva;
197
    public $multicurrency_total_ttc;
198
199
    /**
200
     * Draft status
201
     */
202
    const STATUS_DRAFT = 0;
203
204
    /**
205
     * Validated status
206
     */
207
    const STATUS_VALIDATED = 1;
208
209
    /**
210
     * Signed quote
211
     */
212
    const STATUS_SIGNED = 2;
213
214
    /**
215
     * Not signed quote, canceled
216
     */
217
    const STATUS_NOTSIGNED = 3;
218
219
    /**
220
     * Billed or closed/processed quote
221
     */
222
    const STATUS_CLOSE = 4;
223
224
    /**
225
     *  Constructor
226
     *
227
     *  @param      DoliDB  $db         Database handler
228
     *  @param      int     $socid      Id third party
229
     *  @param      int     $supplier_proposalid   Id supplier_proposal
230
     */
231
    public function __construct($db, $socid = 0, $supplier_proposalid = 0)
232
    {
233
        global $conf, $langs;
234
235
        $this->db = $db;
236
237
        $this->ismultientitymanaged = 1;
238
        $this->socid = $socid;
239
        $this->id = $supplier_proposalid;
240
    }
241
242
243
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
244
    /**
245
     *  Add line into array ->lines
246
     *
247
     *  @param  int     $idproduct          Product Id to add
248
     *  @param  float   $qty                Quantity
249
     *  @param  int     $remise_percent     Discount effected on Product
250
     *  @return int                         Return integer <0 if KO, >0 if OK
251
     *
252
     *  TODO    Remplacer les appels a cette fonction par generation object Ligne
253
     */
254
    public function add_product($idproduct, $qty, $remise_percent = 0)
255
    {
256
		// phpcs:enable
257
        global $conf, $mysoc;
258
259
        if (!$qty) {
260
            $qty = 1;
261
        }
262
263
        dol_syslog(get_only_class($this) . "::add_product $idproduct, $qty, $remise_percent");
264
        if ($idproduct > 0) {
265
            $prod = new Product($this->db);
266
            $prod->fetch($idproduct);
267
268
            $productdesc = $prod->description;
269
270
            $tva_tx = get_default_tva($mysoc, $this->thirdparty, $prod->id);
271
            $tva_npr = get_default_npr($mysoc, $this->thirdparty, $prod->id);
272
            if (empty($tva_tx)) {
273
                $tva_npr = 0;
274
            }
275
            $localtax1_tx = get_localtax($tva_tx, 1, $mysoc, $this->thirdparty, $tva_npr);
276
            $localtax2_tx = get_localtax($tva_tx, 2, $mysoc, $this->thirdparty, $tva_npr);
277
278
            // multiprix
279
            if ($conf->global->PRODUIT_MULTIPRICES && $this->thirdparty->price_level) {
280
                $price = $prod->multiprices[$this->thirdparty->price_level];
281
            } else {
282
                $price = $prod->price;
283
            }
284
285
            $line = new SupplierProposalLine($this->db);
286
287
            $line->fk_product = $idproduct;
288
            $line->desc = $productdesc;
289
            $line->qty = $qty;
290
            $line->subprice = $price;
291
            $line->remise_percent = $remise_percent;
292
            $line->tva_tx = $tva_tx;
293
294
            $this->lines[] = $line;
295
            return 1;
296
        }
297
        return -1;
298
    }
299
300
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
301
    /**
302
     *  Adding line of fixed discount in the proposal in DB
303
     *
304
     *  @param     int      $idremise           Id of fixed discount
305
     *  @return    int                          >0 if OK, <0 if KO
306
     */
307
    public function insert_discount($idremise)
308
    {
309
		// phpcs:enable
310
        global $langs;
311
312
        include_once DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php';
313
        include_once DOL_DOCUMENT_ROOT . '/core/class/discount.class.php';
314
315
        $this->db->begin();
316
317
        $remise = new DiscountAbsolute($this->db);
318
        $result = $remise->fetch($idremise);
319
320
        if ($result > 0) {
321
            if ($remise->fk_facture) {  // Protection against multiple submission
322
                $this->error = $langs->trans("ErrorDiscountAlreadyUsed");
323
                $this->db->rollback();
324
                return -5;
325
            }
326
327
            $supplier_proposalligne = new SupplierProposalLine($this->db);
328
            $supplier_proposalligne->fk_supplier_proposal = $this->id;
329
            $supplier_proposalligne->fk_remise_except = $remise->id;
330
            $supplier_proposalligne->desc = $remise->description; // Description ligne
331
            $supplier_proposalligne->tva_tx = $remise->tva_tx;
332
            $supplier_proposalligne->subprice = -$remise->amount_ht;
333
            $supplier_proposalligne->fk_product = 0; // Id produit predefini
334
            $supplier_proposalligne->qty = 1;
335
            $supplier_proposalligne->remise_percent = 0;
336
            $supplier_proposalligne->rang = -1;
337
            $supplier_proposalligne->info_bits = 2;
338
339
            $supplier_proposalligne->total_ht  = -$remise->amount_ht;
340
            $supplier_proposalligne->total_tva = -$remise->amount_tva;
341
            $supplier_proposalligne->total_ttc = -$remise->amount_ttc;
342
343
            $result = $supplier_proposalligne->insert();
344
            if ($result > 0) {
345
                $result = $this->update_price(1);
346
                if ($result > 0) {
347
                    $this->db->commit();
348
                    return 1;
349
                } else {
350
                    $this->db->rollback();
351
                    return -1;
352
                }
353
            } else {
354
                $this->error = $supplier_proposalligne->error;
355
                $this->db->rollback();
356
                return -2;
357
            }
358
        } else {
359
            $this->db->rollback();
360
            return -2;
361
        }
362
    }
363
364
    /**
365
     *      Add a proposal line into database (linked to product/service or not)
366
     *      Les parameters sont deja cense etre juste et avec valeurs finales a l'appel
367
     *      de cette methode. Aussi, pour le taux tva, il doit deja avoir ete defini
368
     *      par l'appelant par la methode get_default_tva(societe_vendeuse,societe_acheteuse,'',produit)
369
     *      et le desc doit deja avoir la bonne valeur (a l'appelant de gerer le multilangue)
370
     *
371
     *      @param      string      $desc               Description de la ligne
372
     *      @param      double      $pu_ht              Prix unitaire
373
     *      @param      double      $qty                Quantite
374
     *      @param      double      $txtva              Taux de tva
375
     *      @param      double      $txlocaltax1        Local tax 1 rate
376
     *      @param      double      $txlocaltax2        Local tax 2 rate
377
     *      @param      int         $fk_product         Product/Service ID predefined
378
     *      @param      double      $remise_percent     Percentage discount of the line
379
     *      @param      string      $price_base_type    HT or TTC
380
     *      @param      double      $pu_ttc             Prix unitaire TTC
381
     *      @param      int         $info_bits          Bits of type of lines
382
     *      @param      int         $type               Type of line (product, service)
383
     *      @param      int         $rang               Position of line
384
     *      @param      int         $special_code       Special code (also used by externals modules!)
385
     *      @param      int         $fk_parent_line     Id of parent line
386
     *      @param      int         $fk_fournprice      Id supplier price. If 0, we will take best price. If -1 we keep it empty.
387
     *      @param      int         $pa_ht              Buying price without tax
388
     *      @param      string      $label              ???
389
     *      @param      array       $array_options      extrafields array
390
     *      @param      string      $ref_supplier           Supplier price reference
391
     *      @param      int         $fk_unit            Id of the unit to use.
392
     *      @param      string      $origin             'order', 'supplier_proposal', ...
393
     *      @param      int         $origin_id          Id of origin line
394
     *      @param      double      $pu_ht_devise       Amount in currency
395
     *      @param      int         $date_start         Date start
396
     *      @param      int         $date_end           Date end
397
     *      @return     int                             >0 if OK, <0 if KO
398
     *
399
     *      @see        add_product()
400
     */
401
    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_options = [], $ref_supplier = '', $fk_unit = 0, $origin = '', $origin_id = 0, $pu_ht_devise = 0, $date_start = 0, $date_end = 0)
402
    {
403
        global $mysoc, $conf, $langs;
404
405
        dol_syslog(get_only_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");
406
        include_once DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php';
407
408
        // Clean parameters
409
        if (empty($remise_percent)) {
410
            $remise_percent = 0;
411
        }
412
        if (empty($qty)) {
413
            $qty = 0;
414
        }
415
        if (empty($info_bits)) {
416
            $info_bits = 0;
417
        }
418
        if (empty($rang)) {
419
            $rang = 0;
420
        }
421
        if (empty($fk_parent_line) || $fk_parent_line < 0) {
422
            $fk_parent_line = 0;
423
        }
424
        if (empty($pu_ht)) {
425
            $pu_ht = 0;
426
        }
427
428
        $remise_percent = price2num($remise_percent);
429
        $qty = (float) price2num($qty);
430
        $pu_ht = price2num($pu_ht);
431
        $pu_ttc = price2num($pu_ttc);
432
        if (!preg_match('/\((.*)\)/', (string) $txtva)) {
433
            $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
434
        }
435
        $txlocaltax1 = price2num($txlocaltax1);
436
        $txlocaltax2 = price2num($txlocaltax2);
437
        $pa_ht = price2num($pa_ht);
438
        if ($price_base_type == 'HT') {
439
            $pu = $pu_ht;
440
        } else {
441
            $pu = $pu_ttc;
442
        }
443
444
        // Check parameters
445
        if ($type < 0) {
446
            return -1;
447
        }
448
449
        if ($this->statut == self::STATUS_DRAFT) {
450
            $this->db->begin();
451
452
            if ($fk_product > 0) {
453
                if (getDolGlobalString('SUPPLIER_PROPOSAL_WITH_PREDEFINED_PRICES_ONLY')) {
454
                    // Check quantity is enough
455
                    dol_syslog(get_only_class($this) . "::addline we check supplier prices fk_product=" . $fk_product . " fk_fournprice=" . $fk_fournprice . " qty=" . $qty . " ref_supplier=" . $ref_supplier);
456
                    $productsupplier = new ProductFournisseur($this->db);
457
                    if ($productsupplier->fetch($fk_product) > 0) {
458
                        $product_type = $productsupplier->type;
459
                        $label = $productsupplier->label;
460
                        $fk_prod_fourn_price = $fk_fournprice;
461
462
                        // We use 'none' instead of $ref_supplier, because fourn_ref may not exists anymore. So we will take the first supplier price ok.
463
                        // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
464
                        // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
465
                        $result = $productsupplier->get_buyprice($fk_prod_fourn_price, $qty, $fk_product, 'none', $this->socid); // Search on couple $fk_prod_fourn_price/$qty first, then on triplet $qty/$fk_product/$ref_supplier/$this->socid
466
                        if ($result > 0) {
467
                            $pu = $productsupplier->fourn_pu; // Unit price supplier price set by get_buyprice
468
                            $ref_supplier = $productsupplier->ref_supplier; // Ref supplier price set by get_buyprice
469
                            // is remise percent not keyed but present for the product we add it
470
                            if ($remise_percent == 0 && $productsupplier->remise_percent != 0) {
471
                                $remise_percent = $productsupplier->remise_percent;
472
                            }
473
                        }
474
                        if ($result == 0) {                   // If result == 0, we failed to found the supplier reference price
475
                            $langs->load("errors");
476
                            $this->error = "Ref " . $productsupplier->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier");
477
                            $this->db->rollback();
478
                            dol_syslog(get_only_class($this) . "::addline we did not found supplier price, so we can't guess unit price");
479
                            //$pu    = $productsupplier->fourn_pu;     // We do not overwrite unit price
480
                            //$ref   = $productsupplier_fourn;    // We do not overwrite ref supplier price
481
                            return -1;
482
                        }
483
                        if ($result == -1) {
484
                            $langs->load("errors");
485
                            $this->error = "Ref " . $productsupplier->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier");
486
                            $this->db->rollback();
487
                            dol_syslog(get_only_class($this) . "::addline result=" . $result . " - " . $this->error, LOG_DEBUG);
488
                            return -1;
489
                        }
490
                        if ($result < -1) {
491
                            $this->error = $productsupplier->error;
492
                            $this->errors = $productsupplier->errors;
493
                            $this->db->rollback();
494
                            dol_syslog(get_only_class($this) . "::addline result=" . $result . " - " . $this->error, LOG_ERR);
495
                            return -1;
496
                        }
497
                    } else {
498
                        $this->error = $productsupplier->error;
499
                        $this->errors = $productsupplier->errors;
500
                        $this->db->rollback();
501
                        return -1;
502
                    }
503
                }
504
            } else {
505
                $product_type = $type;
506
            }
507
508
            // Calcul du total TTC et de la TVA pour la ligne a partir de
509
            // qty, pu, remise_percent et txtva
510
            // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
511
            // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
512
513
            $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
514
515
            // Clean vat code
516
            $reg = array();
517
            $vat_src_code = '';
518
            if (preg_match('/\((.*)\)/', $txtva, $reg)) {
519
                $vat_src_code = $reg[1];
520
                $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
521
            }
522
523
            if (isModEnabled("multicurrency") && $pu_ht_devise > 0) {
524
                $pu = 0;
525
            }
526
527
            $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);
528
            $total_ht  = $tabprice[0];
529
            $total_tva = $tabprice[1];
530
            $total_ttc = $tabprice[2];
531
            $total_localtax1 = $tabprice[9];
532
            $total_localtax2 = $tabprice[10];
533
            $pu = $pu_ht = $tabprice[3];
534
535
            // MultiCurrency
536
            $multicurrency_total_ht  = $tabprice[16];
537
            $multicurrency_total_tva = $tabprice[17];
538
            $multicurrency_total_ttc = $tabprice[18];
539
            $pu_ht_devise = $tabprice[19];
540
541
            // Rang to use
542
            $ranktouse = $rang;
543
            if ($ranktouse == -1) {
544
                $rangmax = $this->line_max($fk_parent_line);
545
                $ranktouse = $rangmax + 1;
546
            }
547
548
            // TODO A virer
549
            // Anciens indicateurs: $price, $remise (a ne plus utiliser)
550
            $price = $pu;
551
            $remise = 0;
552
            if ($remise_percent > 0) {
553
                $remise = round(($pu * (float) $remise_percent / 100), 2);
554
                $price = $pu - $remise;
555
            }
556
557
            // Insert line
558
            $this->line = new SupplierProposalLine($this->db);
559
560
            $this->line->fk_supplier_proposal = $this->id;
561
            $this->line->label = $label;
562
            $this->line->desc = $desc;
563
            $this->line->qty = $qty;
564
565
            $this->line->vat_src_code = $vat_src_code;
566
            $this->line->tva_tx = $txtva;
567
            $this->line->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
568
            $this->line->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
569
            $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
570
            $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
571
            $this->line->fk_product = $fk_product;
572
            $this->line->remise_percent = $remise_percent;
573
            $this->line->subprice = $pu_ht;
574
            $this->line->rang = $ranktouse;
575
            $this->line->info_bits = $info_bits;
576
            $this->line->total_ht = $total_ht;
577
            $this->line->total_tva = $total_tva;
578
            $this->line->total_localtax1 = $total_localtax1;
579
            $this->line->total_localtax2 = $total_localtax2;
580
            $this->line->total_ttc = $total_ttc;
581
            $this->line->product_type = $type;
582
            $this->line->special_code = $special_code;
583
            $this->line->fk_parent_line = $fk_parent_line;
584
            $this->line->fk_unit = $fk_unit;
585
            $this->line->origin = $origin;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$origin has been deprecated: Use $origin_type and $origin_id instead. ( Ignorable by Annotation )

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

585
            /** @scrutinizer ignore-deprecated */ $this->line->origin = $origin;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
586
            $this->line->origin_id = $origin_id;
587
            $this->line->ref_fourn = $this->db->escape($ref_supplier);
588
            $this->line->date_start = $date_start;
589
            $this->line->date_end = $date_end;
590
591
            // infos merge
592
            if (!empty($fk_product) && $fk_product > 0 && empty($fk_fournprice) && empty($pa_ht)) {
593
                // When fk_fournprice is 0, we take the lowest buying price
594
                include_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php';
595
                $productFournisseur = new ProductFournisseur($this->db);
596
                $productFournisseur->find_min_price_product_fournisseur($fk_product);
597
                $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id;
598
            } else {
599
                $this->line->fk_fournprice = ($fk_fournprice > 0 ? $fk_fournprice : 0); // If fk_fournprice is -1, we will not use fk_fournprice
600
            }
601
            $this->line->pa_ht = $pa_ht;
602
            //var_dump($this->line->fk_fournprice);exit;
603
604
            // Multicurrency
605
            $this->line->fk_multicurrency = $this->fk_multicurrency;
606
            $this->line->multicurrency_code = $this->multicurrency_code;
607
            $this->line->multicurrency_subprice     = $pu_ht_devise;
608
            $this->line->multicurrency_total_ht     = $multicurrency_total_ht;
609
            $this->line->multicurrency_total_tva    = $multicurrency_total_tva;
610
            $this->line->multicurrency_total_ttc    = $multicurrency_total_ttc;
611
612
            // Mise en option de la ligne
613
            if (empty($qty) && empty($special_code)) {
614
                $this->line->special_code = 3;
615
            }
616
617
            if (is_array($array_options) && count($array_options) > 0) {
618
                $this->line->array_options = $array_options;
619
            }
620
621
            $result = $this->line->insert();
622
            if ($result > 0) {
623
                // Reorder if child line
624
                if (!empty($fk_parent_line)) {
625
                    $this->line_order(true, 'DESC');
626
                } elseif ($ranktouse > 0 && $ranktouse <= count($this->lines)) { // Update all rank of all other lines
627
                    $linecount = count($this->lines);
628
                    for ($ii = $ranktouse; $ii <= $linecount; $ii++) {
629
                        $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1);
630
                    }
631
                }
632
633
                // Mise a jour information denormalisees au niveau de la propale meme
634
                $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.
635
                if ($result > 0) {
636
                    $this->db->commit();
637
                    return $this->line->id;
638
                } else {
639
                    $this->db->rollback();
640
                    return -1;
641
                }
642
            } else {
643
                $this->error = $this->line->error;
644
                $this->errors = $this->line->errors;
645
                $this->db->rollback();
646
                return -2;
647
            }
648
        } else {
649
            $this->error = 'BadStatusOfObjectToAddLine';
650
            return -5;
651
        }
652
    }
653
654
655
    /**
656
     *  Update a proposal line
657
     *
658
     *  @param      int         $rowid              Id de la ligne
659
     *  @param      double      $pu                 Unit price (HT or TTC depending on price_base_type)
660
     *  @param      double      $qty                Quantity
661
     *  @param      double      $remise_percent     Discount on line
662
     *  @param      double      $txtva              VAT rate
663
     *  @param      double      $txlocaltax1        Local tax 1 rate
664
     *  @param      double      $txlocaltax2        Local tax 2 rate
665
     *  @param      string      $desc               Description
666
     *  @param      string      $price_base_type    HT or TTC
667
     *  @param      int         $info_bits          Miscellaneous information
668
     *  @param      int         $special_code       Special code (also used by externals modules!)
669
     *  @param      int         $fk_parent_line     Id of parent line (0 in most cases, used by modules adding sublevels into lines).
670
     *  @param      int         $skip_update_total  Keep fields total_xxx to 0 (used for special lines by some modules)
671
     *  @param      int         $fk_fournprice      Id of origin supplier price
672
     *  @param      int         $pa_ht              Price (without tax) of product when it was bought
673
     *  @param      string      $label              ???
674
     *  @param      int         $type               0/1=Product/service
675
     *  @param      array       $array_options      extrafields array
676
     *  @param      string      $ref_supplier       Supplier price reference
677
     *  @param      int         $fk_unit            Id of the unit to use.
678
     *  @param      double      $pu_ht_devise       Unit price in currency
679
     *  @return     int                             0 if OK, <0 if KO
680
     */
681
    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_options = [], $ref_supplier = '', $fk_unit = 0, $pu_ht_devise = 0)
682
    {
683
        global $conf, $user, $langs, $mysoc;
684
685
        dol_syslog(get_only_class($this) . "::updateLine $rowid, $pu, $qty, $remise_percent, $txtva, $desc, $price_base_type, $info_bits");
686
        include_once DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php';
687
688
        // Clean parameters
689
        $remise_percent = price2num($remise_percent);
690
        $qty = (float) price2num($qty);
691
        $pu = price2num($pu);
692
        if (!preg_match('/\((.*)\)/', (string) $txtva)) {
693
            $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
694
        }
695
        $txlocaltax1 = price2num($txlocaltax1);
696
        $txlocaltax2 = price2num($txlocaltax2);
697
        $pa_ht = price2num($pa_ht);
698
        if (empty($qty) && empty($special_code)) {
699
            $special_code = 3; // Set option tag
700
        }
701
        if (!empty($qty) && $special_code == 3) {
702
            $special_code = 0; // Remove option tag
703
        }
704
705
        if ($this->status == 0) {
706
            $this->db->begin();
707
708
            // Calcul du total TTC et de la TVA pour la ligne a partir de
709
            // qty, pu, remise_percent et txtva
710
            // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
711
            // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
712
713
            $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $mysoc, $this->thirdparty);
714
715
            // Clean vat code
716
            $reg = array();
717
            $vat_src_code = '';
718
            if (preg_match('/\((.*)\)/', $txtva, $reg)) {
719
                $vat_src_code = $reg[1];
720
                $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
721
            }
722
723
            if (isModEnabled("multicurrency") && $pu_ht_devise > 0) {
724
                $pu = 0;
725
            }
726
727
            $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);
728
            $total_ht  = $tabprice[0];
729
            $total_tva = $tabprice[1];
730
            $total_ttc = $tabprice[2];
731
            $total_localtax1 = $tabprice[9];
732
            $total_localtax2 = $tabprice[10];
733
            $pu_ht = $tabprice[3];
734
            $pu_tva = $tabprice[4];
735
            $pu_ttc = $tabprice[5];
736
737
            // MultiCurrency
738
            $multicurrency_total_ht  = $tabprice[16];
739
            $multicurrency_total_tva = $tabprice[17];
740
            $multicurrency_total_ttc = $tabprice[18];
741
            $pu_ht_devise = $tabprice[19];
742
743
            $pu = $pu_ht;
744
            if ($price_base_type == 'TTC') {
745
                $pu = $pu_ttc;
746
            }
747
748
            //Fetch current line from the database and then clone the object and set it in $oldline property
749
            $line = new SupplierProposalLine($this->db);
750
            $line->fetch($rowid);
751
            $line->fetch_optionals();
752
753
            $fk_product = $line->fk_product;
754
755
            // Stock previous line records
756
            $staticline = clone $line;
757
758
            $line->oldline = $staticline;
759
            $this->line = $line;
760
            $this->line->context = $this->context;
761
762
            // Reorder if fk_parent_line change
763
            if (!empty($fk_parent_line) && !empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line) {
764
                $rangmax = $this->line_max($fk_parent_line);
765
                $this->line->rang = $rangmax + 1;
766
            }
767
768
            $this->line->id                 = $rowid;
769
            $this->line->label = $label;
770
            $this->line->desc = $desc;
771
            $this->line->qty                = $qty;
772
            $this->line->product_type = $type;
773
774
            $this->line->vat_src_code = $vat_src_code;
775
            $this->line->tva_tx = $txtva;
776
            $this->line->localtax1_tx       = $txlocaltax1;
777
            $this->line->localtax2_tx       = $txlocaltax2;
778
            $this->line->localtax1_type     = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
779
            $this->line->localtax2_type     = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
780
            $this->line->remise_percent     = $remise_percent;
781
            $this->line->subprice           = $pu;
782
            $this->line->info_bits          = $info_bits;
783
            $this->line->total_ht           = $total_ht;
784
            $this->line->total_tva          = $total_tva;
785
            $this->line->total_localtax1    = $total_localtax1;
786
            $this->line->total_localtax2    = $total_localtax2;
787
            $this->line->total_ttc          = $total_ttc;
788
            $this->line->special_code = $special_code;
789
            $this->line->fk_parent_line     = $fk_parent_line;
790
            $this->line->skip_update_total = $skip_update_total;
791
            $this->line->ref_fourn = $ref_supplier;
792
            $this->line->fk_unit = $fk_unit;
793
794
            // infos merge
795
            if (!empty($fk_product) && $fk_product > 0 && empty($fk_fournprice) && empty($pa_ht)) {
796
                // by external module, take lowest buying price
797
                include_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php';
798
                $productFournisseur = new ProductFournisseur($this->db);
799
                $productFournisseur->find_min_price_product_fournisseur($fk_product);
800
                $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id;
801
            } else {
802
                $this->line->fk_fournprice = $fk_fournprice;
803
            }
804
            $this->line->pa_ht = $pa_ht;
805
806
            if (is_array($array_options) && count($array_options) > 0) {
807
                // We replace values in this->line->array_options only for entries defined into $array_options
808
                foreach ($array_options as $key => $value) {
809
                    $this->line->array_options[$key] = $array_options[$key];
810
                }
811
            }
812
813
            // Multicurrency
814
            $this->line->multicurrency_subprice     = $pu_ht_devise;
815
            $this->line->multicurrency_total_ht     = $multicurrency_total_ht;
816
            $this->line->multicurrency_total_tva    = $multicurrency_total_tva;
817
            $this->line->multicurrency_total_ttc    = $multicurrency_total_ttc;
818
819
            $result = $this->line->update();
820
            if ($result > 0) {
821
                // Reorder if child line
822
                if (!empty($fk_parent_line)) {
823
                    $this->line_order(true, 'DESC');
824
                }
825
826
                $this->update_price(1);
827
828
                $this->db->commit();
829
                return $result;
830
            } else {
831
                $this->error = $this->db->error();
832
                $this->db->rollback();
833
                return -1;
834
            }
835
        } else {
836
            dol_syslog(get_only_class($this) . "::updateline Erreur -2 SupplierProposal en mode incompatible pour cette action");
837
            return -2;
838
        }
839
    }
840
841
842
    /**
843
     *  Delete detail line
844
     *
845
     *  @param      int     $lineid         Id of line to delete
846
     *  @return     int                     >0 if OK, <0 if KO
847
     */
848
    public function deleteLine($lineid)
849
    {
850
        global $user;
851
852
        if ($this->statut == 0) {
853
            $line = new SupplierProposalLine($this->db);
854
855
            // For triggers
856
            $line->fetch($lineid);
857
858
            if ($line->delete($user) > 0) {
859
                $this->update_price(1);
860
861
                return 1;
862
            } else {
863
                return -1;
864
            }
865
        } else {
866
            return -2;
867
        }
868
    }
869
870
871
    /**
872
     *  Create commercial proposal into database
873
     *  this->ref can be set or empty. If empty, we will use "(PROVid)"
874
     *
875
     *  @param      User    $user       User that create
876
     *  @param      int     $notrigger  1=Does not execute triggers, 0= execute triggers
877
     *  @return     int                 Return integer <0 if KO, >=0 if OK
878
     */
879
    public function create($user, $notrigger = 0)
880
    {
881
        global $langs, $conf, $mysoc, $hookmanager;
882
        $error = 0;
883
884
        $now = dol_now();
885
886
        dol_syslog(get_only_class($this) . "::create");
887
888
        // Check parameters
889
        $result = $this->fetch_thirdparty();
890
        if ($result < 0) {
891
            $this->error = "Failed to fetch company";
892
            dol_syslog(get_only_class($this) . "::create " . $this->error, LOG_ERR);
893
            return -3;
894
        }
895
        if (!empty($this->ref)) {   // We check that ref is not already used
896
            $result = self::isExistingObject($this->element, 0, $this->ref); // Check ref is not yet used
897
            if ($result > 0) {
898
                $this->error = 'ErrorRefAlreadyExists';
899
                dol_syslog(get_only_class($this) . "::create " . $this->error, LOG_WARNING);
900
                $this->db->rollback();
901
                return -1;
902
            }
903
        }
904
905
        // Set tmp vars
906
        $delivery_date = $this->delivery_date;
907
908
        // Multicurrency
909
        if (!empty($this->multicurrency_code)) {
910
            list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $now);
911
        }
912
        if (empty($this->fk_multicurrency)) {
913
            $this->multicurrency_code = $conf->currency;
914
            $this->fk_multicurrency = 0;
915
            $this->multicurrency_tx = 1;
916
        }
917
918
        $this->db->begin();
919
920
        // Insert into database
921
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "supplier_proposal (";
922
        $sql .= "fk_soc";
923
        $sql .= ", price";
924
        $sql .= ", total_tva";
925
        $sql .= ", total_ttc";
926
        $sql .= ", datec";
927
        $sql .= ", ref";
928
        $sql .= ", fk_user_author";
929
        $sql .= ", note_private";
930
        $sql .= ", note_public";
931
        $sql .= ", model_pdf";
932
        $sql .= ", fk_cond_reglement";
933
        $sql .= ", fk_mode_reglement";
934
        $sql .= ", fk_account";
935
        $sql .= ", date_livraison";
936
        $sql .= ", fk_shipping_method";
937
        $sql .= ", fk_projet";
938
        $sql .= ", entity";
939
        $sql .= ", fk_multicurrency";
940
        $sql .= ", multicurrency_code";
941
        $sql .= ", multicurrency_tx";
942
        $sql .= ") ";
943
        $sql .= " VALUES (";
944
        $sql .= ((int) $this->socid);
945
        $sql .= ", 0";
946
        $sql .= ", 0";
947
        $sql .= ", 0";
948
        $sql .= ", '" . $this->db->idate($now) . "'";
949
        $sql .= ", '(PROV)'";
950
        $sql .= ", " . ($user->id > 0 ? ((int) $user->id) : "null");
951
        $sql .= ", '" . $this->db->escape($this->note_private) . "'";
952
        $sql .= ", '" . $this->db->escape($this->note_public) . "'";
953
        $sql .= ", '" . $this->db->escape($this->model_pdf) . "'";
954
        $sql .= ", " . ($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : 'NULL');
955
        $sql .= ", " . ($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : 'NULL');
956
        $sql .= ", " . ($this->fk_account > 0 ? ((int) $this->fk_account) : 'NULL');
957
        $sql .= ", " . ($delivery_date ? "'" . $this->db->idate($delivery_date) . "'" : "null");
958
        $sql .= ", " . ($this->shipping_method_id > 0 ? ((int) $this->shipping_method_id) : 'NULL');
959
        $sql .= ", " . ($this->fk_project > 0 ? ((int) $this->fk_project) : "null");
960
        $sql .= ", " . ((int) $conf->entity);
961
        $sql .= ", " . ((int) $this->fk_multicurrency);
962
        $sql .= ", '" . $this->db->escape($this->multicurrency_code) . "'";
963
        $sql .= ", " . ((float) $this->multicurrency_tx);
964
        $sql .= ")";
965
966
        dol_syslog(get_only_class($this) . "::create", LOG_DEBUG);
967
        $resql = $this->db->query($sql);
968
        if ($resql) {
969
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "supplier_proposal");
970
971
            if ($this->id) {
972
                $this->ref = '(PROV' . $this->id . ')';
973
                $sql = 'UPDATE ' . MAIN_DB_PREFIX . "supplier_proposal SET ref='" . $this->db->escape($this->ref) . "' WHERE rowid=" . ((int) $this->id);
974
975
                dol_syslog(get_only_class($this) . "::create", LOG_DEBUG);
976
                $resql = $this->db->query($sql);
977
                if (!$resql) {
978
                    $error++;
979
                }
980
981
                if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) {  // To use new linkedObjectsIds instead of old linked_objects
982
                    $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
983
                }
984
985
                // Add object linked
986
                if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) {
987
                    foreach ($this->linked_objects as $origin => $tmp_origin_id) {
988
                        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, ...))
989
                            foreach ($tmp_origin_id as $origin_id) {
990
                                $ret = $this->add_object_linked($origin, $origin_id);
991
                                if (!$ret) {
992
                                    dol_print_error($this->db);
993
                                    $error++;
994
                                }
995
                            }
996
                        }
997
                    }
998
                }
999
1000
                /*
1001
                 *  Insertion du detail des produits dans la base
1002
                 */
1003
                if (!$error) {
1004
                    $fk_parent_line = 0;
1005
                    $num = count($this->lines);
1006
1007
                    for ($i = 0; $i < $num; $i++) {
1008
                        // Reset fk_parent_line for no child products and special product
1009
                        if (($this->lines[$i]->product_type != 9 && empty($this->lines[$i]->fk_parent_line)) || $this->lines[$i]->product_type == 9) {
1010
                            $fk_parent_line = 0;
1011
                        }
1012
1013
                        $result = $this->addline(
1014
                            $this->lines[$i]->desc,
1015
                            $this->lines[$i]->subprice,
1016
                            $this->lines[$i]->qty,
1017
                            $this->lines[$i]->tva_tx,
1018
                            $this->lines[$i]->localtax1_tx,
1019
                            $this->lines[$i]->localtax2_tx,
1020
                            $this->lines[$i]->fk_product,
1021
                            $this->lines[$i]->remise_percent,
1022
                            'HT',
1023
                            0,
1024
                            0,
1025
                            $this->lines[$i]->product_type,
1026
                            $this->lines[$i]->rang,
1027
                            $this->lines[$i]->special_code,
1028
                            $fk_parent_line,
1029
                            $this->lines[$i]->fk_fournprice,
1030
                            $this->lines[$i]->pa_ht,
1031
                            empty($this->lines[$i]->label) ? '' : $this->lines[$i]->label, // deprecated
1032
                            $this->lines[$i]->array_options,
1033
                            $this->lines[$i]->ref_fourn,
1034
                            $this->lines[$i]->fk_unit,
1035
                            'supplier_proposal',
1036
                            $this->lines[$i]->rowid
1037
                        );
1038
1039
                        if ($result < 0) {
1040
                            $error++;
1041
                            $this->error = $this->db->error;
1042
                            dol_print_error($this->db);
1043
                            break;
1044
                        }
1045
                        // Defined the new fk_parent_line
1046
                        if ($result > 0 && $this->lines[$i]->product_type == 9) {
1047
                            $fk_parent_line = $result;
1048
                        }
1049
                    }
1050
                }
1051
1052
                if (!$error) {
1053
                    // Mise a jour infos denormalisees
1054
                    $resql = $this->update_price(1);
1055
                    if ($resql) {
1056
                        $action = 'update';
1057
1058
                        // Actions on extra fields
1059
                        if (!$error) {
1060
                            $result = $this->insertExtraFields();
1061
                            if ($result < 0) {
1062
                                $error++;
1063
                            }
1064
                        }
1065
1066
                        if (!$error && !$notrigger) {
1067
                            // Call trigger
1068
                            $result = $this->call_trigger('PROPOSAL_SUPPLIER_CREATE', $user);
1069
                            if ($result < 0) {
1070
                                $error++;
1071
                            }
1072
                            // End call triggers
1073
                        }
1074
                    } else {
1075
                        $this->error = $this->db->lasterror();
1076
                        $error++;
1077
                    }
1078
                }
1079
            } else {
1080
                $this->error = $this->db->lasterror();
1081
                $error++;
1082
            }
1083
1084
            if (!$error) {
1085
                $this->db->commit();
1086
                dol_syslog(get_only_class($this) . "::create done id=" . $this->id);
1087
                return $this->id;
1088
            } else {
1089
                $this->db->rollback();
1090
                return -2;
1091
            }
1092
        } else {
1093
            $this->error = $this->db->lasterror();
1094
            $this->db->rollback();
1095
            return -1;
1096
        }
1097
    }
1098
1099
    /**
1100
     *      Load an object from its id and create a new one in database
1101
     *
1102
     *      @param      User    $user           User making the clone
1103
     *      @param      int     $fromid         Id of thirdparty
1104
     *      @return     int                     New id of clone
1105
     */
1106
    public function createFromClone(User $user, $fromid = 0)
1107
    {
1108
        global $conf, $hookmanager;
1109
1110
        $error = 0;
1111
        $now = dol_now();
1112
1113
        $this->db->begin();
1114
1115
        // get extrafields so they will be clone
1116
        foreach ($this->lines as $line) {
1117
            $line->fetch_optionals();
1118
        }
1119
1120
        // Load source object
1121
        $objFrom = clone $this;
1122
1123
        $objsoc = new Societe($this->db);
1124
1125
        // Change socid if needed
1126
        if (!empty($fromid) && $fromid != $this->socid) {
1127
            if ($objsoc->fetch($fromid) > 0) {
1128
                $this->socid = $objsoc->id;
1129
                $this->cond_reglement_id = (!empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
1130
                $this->mode_reglement_id = (!empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
1131
                unset($this->fk_project);
1132
            }
1133
1134
            // TODO Change product price if multi-prices
1135
        } else {
1136
            $objsoc->fetch($this->socid);
1137
        }
1138
1139
        $this->id = 0;
1140
        $this->statut = 0;
1141
1142
        if (!getDolGlobalString('SUPPLIER_PROPOSAL_ADDON') || !is_readable(DOL_DOCUMENT_ROOT . "/core/modules/supplier_proposal/" . getDolGlobalString('SUPPLIER_PROPOSAL_ADDON') . ".php")) {
1143
            $this->error = 'ErrorSetupNotComplete';
1144
            return -1;
1145
        }
1146
1147
        // Clear fields
1148
        $this->user_author_id = $user->id;
1149
        $this->user_validation_id = 0;
1150
        $this->date = $now;
1151
1152
        // Set ref
1153
        require_once DOL_DOCUMENT_ROOT . "/core/modules/supplier_proposal/" . getDolGlobalString('SUPPLIER_PROPOSAL_ADDON') . '.php';
1154
        $obj = getDolGlobalString('SUPPLIER_PROPOSAL_ADDON');
1155
        $modSupplierProposal = new $obj();
1156
        $this->ref = $modSupplierProposal->getNextValue($objsoc, $this);
1157
1158
        // Create clone
1159
        $this->context['createfromclone'] = 'createfromclone';
1160
        $result = $this->create($user);
1161
        if ($result < 0) {
1162
            $error++;
1163
        }
1164
1165
        if (!$error) {
1166
            // Hook of thirdparty module
1167
            if (is_object($hookmanager)) {
1168
                $parameters = array('objFrom' => $objFrom);
1169
                $action = '';
1170
                $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1171
                if ($reshook < 0) {
1172
                    $this->setErrorsFromObject($hookmanager);
1173
                    $error++;
1174
                }
1175
            }
1176
        }
1177
1178
        unset($this->context['createfromclone']);
1179
1180
        // End
1181
        if (!$error) {
1182
            $this->db->commit();
1183
            return $this->id;
1184
        } else {
1185
            $this->db->rollback();
1186
            return -1;
1187
        }
1188
    }
1189
1190
    /**
1191
     *  Load a proposal from database and its ligne array
1192
     *
1193
     *  @param      int         $rowid      id of object to load
1194
     *  @param      string      $ref        Ref of proposal
1195
     *  @return     int                     >0 if OK, <0 if KO
1196
     */
1197
    public function fetch($rowid, $ref = '')
1198
    {
1199
        global $conf;
1200
1201
        $sql = "SELECT p.rowid, p.entity, p.ref, p.fk_soc as socid";
1202
        $sql .= ", p.total_ttc, p.total_tva, p.localtax1, p.localtax2, p.total_ht";
1203
        $sql .= ", p.datec";
1204
        $sql .= ", p.date_valid as datev";
1205
        $sql .= ", p.date_livraison as delivery_date";
1206
        $sql .= ", p.model_pdf, p.extraparams";
1207
        $sql .= ", p.note_private, p.note_public";
1208
        $sql .= ", p.fk_projet as fk_project, p.fk_statut";
1209
        $sql .= ", p.fk_user_author, p.fk_user_valid, p.fk_user_cloture";
1210
        $sql .= ", p.fk_cond_reglement";
1211
        $sql .= ", p.fk_mode_reglement";
1212
        $sql .= ', p.fk_account';
1213
        $sql .= ", p.fk_shipping_method";
1214
        $sql .= ", p.fk_multicurrency, p.multicurrency_code, p.multicurrency_tx, p.multicurrency_total_ht, p.multicurrency_total_tva, p.multicurrency_total_ttc";
1215
        $sql .= ", c.label as statut_label";
1216
        $sql .= ", cr.code as cond_reglement_code, cr.libelle as cond_reglement, cr.libelle_facture as cond_reglement_libelle_doc";
1217
        $sql .= ", cp.code as mode_reglement_code, cp.libelle as mode_reglement";
1218
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_propalst as c, " . MAIN_DB_PREFIX . "supplier_proposal as p";
1219
        $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_paiement as cp ON p.fk_mode_reglement = cp.id';
1220
        $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_payment_term as cr ON p.fk_cond_reglement = cr.rowid';
1221
        $sql .= " WHERE p.fk_statut = c.id";
1222
        $sql .= " AND p.entity IN (" . getEntity('supplier_proposal') . ")";
1223
        if ($ref) {
1224
            $sql .= " AND p.ref = '" . $this->db->escape($ref) . "'";
1225
        } else {
1226
            $sql .= " AND p.rowid = " . ((int) $rowid);
1227
        }
1228
1229
        dol_syslog(get_only_class($this) . "::fetch", LOG_DEBUG);
1230
        $resql = $this->db->query($sql);
1231
        if ($resql) {
1232
            if ($this->db->num_rows($resql)) {
1233
                $obj = $this->db->fetch_object($resql);
1234
1235
                $this->id                   = $obj->rowid;
1236
                $this->entity               = $obj->entity;
1237
1238
                $this->ref                  = $obj->ref;
1239
                $this->total_ht             = $obj->total_ht;
1240
                $this->total_tva            = $obj->total_tva;
1241
                $this->total_localtax1      = $obj->localtax1;
1242
                $this->total_localtax2      = $obj->localtax2;
1243
                $this->total_ttc            = $obj->total_ttc;
1244
                $this->socid                = $obj->socid;
1245
                $this->fk_project           = $obj->fk_project;
1246
                $this->model_pdf            = $obj->model_pdf;
1247
                $this->note                 = $obj->note_private; // TODO deprecated
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$note has been deprecated: Use $note_private instead. ( Ignorable by Annotation )

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

1247
                /** @scrutinizer ignore-deprecated */ $this->note                 = $obj->note_private; // TODO deprecated

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1248
                $this->note_private         = $obj->note_private;
1249
                $this->note_public          = $obj->note_public;
1250
                $this->statut               = (int) $obj->fk_statut;
1251
                $this->status               = (int) $obj->fk_statut;
1252
                $this->datec                = $this->db->jdate($obj->datec); // TODO deprecated
1253
                $this->datev                = $this->db->jdate($obj->datev); // TODO deprecated
1254
                $this->date_creation = $this->db->jdate($obj->datec);   // Creation date
1255
                $this->date                 = $this->date_creation;
1256
                $this->date_validation = $this->db->jdate($obj->datev); // Validation date
1257
                $this->delivery_date        = $this->db->jdate($obj->delivery_date);
1258
                $this->shipping_method_id   = ($obj->fk_shipping_method > 0) ? $obj->fk_shipping_method : null;
1259
1260
                $this->mode_reglement_id    = $obj->fk_mode_reglement;
1261
                $this->mode_reglement_code  = $obj->mode_reglement_code;
1262
                $this->mode_reglement       = $obj->mode_reglement;
1263
                $this->fk_account           = ($obj->fk_account > 0) ? $obj->fk_account : null;
1264
                $this->cond_reglement_id    = $obj->fk_cond_reglement;
1265
                $this->cond_reglement_code  = $obj->cond_reglement_code;
1266
                $this->cond_reglement       = $obj->cond_reglement;
0 ignored issues
show
Bug Best Practice introduced by
The property $cond_reglement is declared private in Dolibarr\Core\Base\CommonObject. Since you implement __set, consider adding a @property or @property-write.
Loading history...
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$cond_reglement has been deprecated: Use $cond_reglement_id instead - Kept for compatibility ( Ignorable by Annotation )

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

1266
                /** @scrutinizer ignore-deprecated */ $this->cond_reglement       = $obj->cond_reglement;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1267
                $this->cond_reglement_doc   = $obj->cond_reglement_libelle_doc;
1268
1269
                $this->extraparams = (array) json_decode($obj->extraparams, true);
1270
1271
                $this->user_author_id = $obj->fk_user_author;
1272
                $this->user_validation_id = $obj->fk_user_valid;
1273
                $this->user_closing_id = $obj->fk_user_cloture;
1274
1275
                // Multicurrency
1276
                $this->fk_multicurrency         = $obj->fk_multicurrency;
1277
                $this->multicurrency_code = $obj->multicurrency_code;
1278
                $this->multicurrency_tx         = $obj->multicurrency_tx;
1279
                $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
1280
                $this->multicurrency_total_tva  = $obj->multicurrency_total_tva;
1281
                $this->multicurrency_total_ttc  = $obj->multicurrency_total_ttc;
1282
1283
                // Retrieve all extrafield
1284
                // fetch optionals attributes and labels
1285
                $this->fetch_optionals();
1286
1287
                $this->db->free($resql);
1288
1289
                $this->lines = array();
1290
1291
                // Lines of supplier proposals
1292
                $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,";
1293
                $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,";
1294
                $sql .= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label,';
1295
                $sql .= ' d.ref_fourn as ref_produit_fourn,';
1296
                $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';
1297
                $sql .= " FROM " . MAIN_DB_PREFIX . "supplier_proposaldet as d";
1298
                $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON d.fk_product = p.rowid";
1299
                $sql .= " WHERE d.fk_supplier_proposal = " . ((int) $this->id);
1300
                $sql .= " ORDER by d.rang";
1301
1302
                $result = $this->db->query($sql);
1303
                if ($result) {
1304
                    $num = $this->db->num_rows($result);
1305
                    $i = 0;
1306
1307
                    while ($i < $num) {
1308
                        $objp                   = $this->db->fetch_object($result);
1309
1310
                        $line                   = new SupplierProposalLine($this->db);
1311
1312
                        $line->rowid = $objp->rowid; // deprecated
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObjectLine::$rowid has been deprecated: Try to use id property as possible (even if field into database is still rowid) ( Ignorable by Annotation )

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

1312
                        /** @scrutinizer ignore-deprecated */ $line->rowid = $objp->rowid; // deprecated

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1313
                        $line->id = $objp->rowid;
1314
                        $line->fk_supplier_proposal = $objp->fk_supplier_proposal;
1315
                        $line->fk_parent_line = $objp->fk_parent_line;
1316
                        $line->product_type     = $objp->product_type;
1317
                        $line->label            = $objp->custom_label;
1318
                        $line->desc             = $objp->description; // Description ligne
1319
                        $line->qty              = $objp->qty;
1320
                        $line->tva_tx           = $objp->tva_tx;
1321
                        $line->localtax1_tx     = $objp->localtax1_tx;
1322
                        $line->localtax2_tx     = $objp->localtax2_tx;
1323
                        $line->subprice         = $objp->subprice;
1324
                        $line->fk_remise_except = $objp->fk_remise_except;
1325
                        $line->remise_percent   = $objp->remise_percent;
1326
1327
                        $line->info_bits        = $objp->info_bits;
1328
                        $line->total_ht         = $objp->total_ht;
1329
                        $line->total_tva        = $objp->total_tva;
1330
                        $line->total_localtax1  = $objp->total_localtax1;
1331
                        $line->total_localtax2  = $objp->total_localtax2;
1332
                        $line->total_ttc        = $objp->total_ttc;
1333
                        $line->fk_fournprice    = $objp->fk_fournprice;
1334
                        $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
1335
                        $line->pa_ht = $marginInfos[0];
1336
                        $line->marge_tx         = $marginInfos[1];
1337
                        $line->marque_tx        = $marginInfos[2];
1338
                        $line->special_code     = $objp->special_code;
1339
                        $line->rang             = $objp->rang;
1340
1341
                        $line->fk_product       = $objp->fk_product;
1342
1343
                        $line->ref = $objp->product_ref; // deprecated
1344
                        $line->product_ref = $objp->product_ref;
1345
                        $line->libelle = $objp->product_label; // deprecated
1346
                        $line->product_label = $objp->product_label;
1347
                        $line->product_desc     = $objp->product_desc; // Description produit
1348
                        $line->fk_product_type  = $objp->fk_product_type;
1349
1350
                        $line->ref_fourn = $objp->ref_produit_fourn;
1351
1352
                        // Multicurrency
1353
                        $line->fk_multicurrency = $objp->fk_multicurrency;
1354
                        $line->multicurrency_code = $objp->multicurrency_code;
1355
                        $line->multicurrency_subprice   = $objp->multicurrency_subprice;
1356
                        $line->multicurrency_total_ht   = $objp->multicurrency_total_ht;
1357
                        $line->multicurrency_total_tva  = $objp->multicurrency_total_tva;
1358
                        $line->multicurrency_total_ttc  = $objp->multicurrency_total_ttc;
1359
                        $line->fk_unit = $objp->fk_unit;
1360
1361
                        $this->lines[$i] = $line;
1362
1363
                        $i++;
1364
                    }
1365
                    $this->db->free($result);
1366
                } else {
1367
                    $this->error = $this->db->error();
1368
                    return -1;
1369
                }
1370
1371
                // Retrieve all extrafield
1372
                // fetch optionals attributes and labels
1373
                $this->fetch_optionals();
1374
1375
                return 1;
1376
            }
1377
1378
            $this->error = "Record Not Found";
1379
            return 0;
1380
        } else {
1381
            $this->error = $this->db->error();
1382
            return -1;
1383
        }
1384
    }
1385
1386
    /**
1387
     *  Set status to validated
1388
     *
1389
     *  @param  User    $user       Object user that validate
1390
     *  @param  int     $notrigger  1=Does not execute triggers, 0= execute triggers
1391
     *  @return int                 Return integer <0 if KO, >=0 if OK
1392
     */
1393
    public function valid($user, $notrigger = 0)
1394
    {
1395
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
1396
1397
        global $conf, $langs;
1398
1399
        $error = 0;
1400
        $now = dol_now();
1401
1402
        if (
1403
            (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('supplier_proposal', 'creer'))
1404
            || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('supplier_proposal', 'validate_advance'))
1405
        ) {
1406
            $this->db->begin();
1407
1408
            // Numbering module definition
1409
            $soc = new Societe($this->db);
1410
            $result = $soc->fetch($this->socid);
1411
1412
            if ($result < 0) {
1413
                return -1;
1414
            }
1415
1416
            // Define new ref
1417
            if (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
1418
                $num = $this->getNextNumRef($soc);
1419
            } else {
1420
                $num = $this->ref;
1421
            }
1422
            $this->newref = dol_sanitizeFileName($num);
1423
1424
            $sql = "UPDATE " . MAIN_DB_PREFIX . "supplier_proposal";
1425
            $sql .= " SET ref = '" . $this->db->escape($num) . "',";
1426
            $sql .= " fk_statut = 1, date_valid='" . $this->db->idate($now) . "', fk_user_valid=" . ((int) $user->id);
1427
            $sql .= " WHERE rowid = " . ((int) $this->id) . " AND fk_statut = 0";
1428
1429
            dol_syslog(get_only_class($this) . "::valid", LOG_DEBUG);
1430
            $resql = $this->db->query($sql);
1431
            if (!$resql) {
1432
                dol_print_error($this->db);
1433
                $error++;
1434
            }
1435
1436
            // Trigger calls
1437
            if (!$error && !$notrigger) {
1438
                // Call trigger
1439
                $result = $this->call_trigger('PROPOSAL_SUPPLIER_VALIDATE', $user);
1440
                if ($result < 0) {
1441
                    $error++;
1442
                }
1443
                // End call triggers
1444
            }
1445
1446
            if (!$error) {
1447
                $this->oldref = $this->ref;
1448
1449
                // Rename directory if dir was a temporary ref
1450
                if (preg_match('/^[\(]?PROV/i', $this->ref)) {
1451
                    // Now we rename also files into index
1452
                    $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) . "'";
1453
                    $sql .= " WHERE filename LIKE '" . $this->db->escape($this->ref) . "%' AND filepath = 'supplier_proposal/" . $this->db->escape($this->ref) . "' and entity = " . $conf->entity;
1454
                    $resql = $this->db->query($sql);
1455
                    if (!$resql) {
1456
                        $error++;
1457
                        $this->error = $this->db->lasterror();
1458
                    }
1459
                    $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filepath = 'supplier_proposal/" . $this->db->escape($this->newref) . "'";
1460
                    $sql .= " WHERE filepath = 'supplier_proposal/" . $this->db->escape($this->ref) . "' and entity = " . $conf->entity;
1461
                    $resql = $this->db->query($sql);
1462
                    if (!$resql) {
1463
                        $error++;
1464
                        $this->error = $this->db->lasterror();
1465
                    }
1466
1467
                    // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1468
                    $oldref = dol_sanitizeFileName($this->ref);
1469
                    $newref = dol_sanitizeFileName($num);
1470
                    $dirsource = $conf->supplier_proposal->dir_output . '/' . $oldref;
1471
                    $dirdest = $conf->supplier_proposal->dir_output . '/' . $newref;
1472
                    if (!$error && file_exists($dirsource)) {
1473
                        dol_syslog(get_only_class($this) . "::valid rename dir " . $dirsource . " into " . $dirdest);
1474
                        if (@rename($dirsource, $dirdest)) {
1475
                            dol_syslog("Rename ok");
1476
                            // Rename docs starting with $oldref with $newref
1477
                            $listoffiles = dol_dir_list($conf->supplier_proposal->dir_output . '/' . $newref, 'files', 1, '^' . preg_quote($oldref, '/'));
1478
                            foreach ($listoffiles as $fileentry) {
1479
                                $dirsource = $fileentry['name'];
1480
                                $dirdest = preg_replace('/^' . preg_quote($oldref, '/') . '/', $newref, $dirsource);
1481
                                $dirsource = $fileentry['path'] . '/' . $dirsource;
1482
                                $dirdest = $fileentry['path'] . '/' . $dirdest;
1483
                                @rename($dirsource, $dirdest);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rename(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

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

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1484
                            }
1485
                        }
1486
                    }
1487
                }
1488
1489
                $this->ref = $num;
1490
                $this->statut = self::STATUS_VALIDATED;
1491
                $this->status = self::STATUS_VALIDATED;
1492
                $this->user_validation_id = $user->id;
1493
                $this->datev = $now;
1494
                $this->date_validation = $now;
1495
1496
                $this->db->commit();
1497
                return 1;
1498
            } else {
1499
                $this->db->rollback();
1500
                return -1;
1501
            }
1502
        } else {
1503
            dol_syslog("You don't have permission to validate supplier proposal", LOG_WARNING);
1504
            return -2;
1505
        }
1506
    }
1507
1508
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1509
    /**
1510
     *  Set delivery date
1511
     *
1512
     *  @param      User    $user               Object user that modify
1513
     *  @param      int     $delivery_date      Delivery date
1514
     *  @return     int                         Return integer <0 if ko, >0 if ok
1515
     *  @deprecated Use  setDeliveryDate
1516
     */
1517
    public function set_date_livraison($user, $delivery_date)
1518
    {
1519
		// phpcs:enable
1520
        return $this->setDeliveryDate($user, $delivery_date);
1521
    }
1522
1523
    /**
1524
     *  Set delivery date
1525
     *
1526
     *  @param      User        $user               Object user that modify
1527
     *  @param      int         $delivery_date     Delivery date
1528
     *  @return     int                             Return integer <0 if ko, >0 if ok
1529
     */
1530
    public function setDeliveryDate($user, $delivery_date)
1531
    {
1532
        if ($user->hasRight('supplier_proposal', 'creer')) {
1533
            $sql = "UPDATE " . MAIN_DB_PREFIX . "supplier_proposal ";
1534
            $sql .= " SET date_livraison = " . ($delivery_date != '' ? "'" . $this->db->idate($delivery_date) . "'" : 'null');
1535
            $sql .= " WHERE rowid = " . ((int) $this->id);
1536
1537
            if ($this->db->query($sql)) {
1538
                $this->delivery_date = $delivery_date;
1539
                return 1;
1540
            } else {
1541
                $this->error = $this->db->error();
1542
                dol_syslog(get_only_class($this) . "::setDeliveryDate Erreur SQL");
1543
                return -1;
1544
            }
1545
        }
1546
        return 0;
1547
    }
1548
1549
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1550
    /**
1551
     *  Set an overall discount on the proposal
1552
     *
1553
     *  @param      User    $user       Object user that modify
1554
     *  @param      double  $remise      Amount discount
1555
     *  @return     int                 Return integer <0 if ko, >0 if ok
1556
     */
1557
    /*
1558
    public function set_remise_percent($user, $remise)
1559
    {
1560
		// phpcs:enable
1561
        $remise = trim($remise) ?trim($remise) : 0;
1562
1563
        if ($user->hasRight('supplier_proposal', 'creer')) {
1564
            $remise = price2num($remise, 2);
1565
1566
            $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal SET remise_percent = ".((float) $remise);
1567
            $sql .= " WHERE rowid = ".((int) $this->id)." AND fk_statut = 0";
1568
1569
            if ($this->db->query($sql)) {
1570
                $this->remise_percent = ((float) $remise);
1571
                $this->update_price(1);
1572
                return 1;
1573
            } else {
1574
                $this->error = $this->db->error();
1575
                return -1;
1576
            }
1577
        }
1578
        return 0;
1579
    }
1580
    */
1581
1582
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1583
    /**
1584
     *  Set an absolute overall discount on the proposal
1585
     *
1586
     *  @param      User    $user        Object user that modify
1587
     *  @param      double  $remise      Amount discount
1588
     *  @return     int                 Return integer <0 if ko, >0 if ok
1589
     */
1590
    /*
1591
    public function set_remise_absolue($user, $remise)
1592
    {
1593
		// phpcs:enable
1594
        if (empty($remise)) {
1595
            $remise = 0;
1596
        }
1597
1598
        $remise = price2num($remise);
1599
1600
        if ($user->hasRight('supplier_proposal', 'creer')) {
1601
            $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal ";
1602
            $sql .= " SET remise_absolue = ".((float) $remise);
1603
            $sql .= " WHERE rowid = ".((int) $this->id)." AND fk_statut = 0";
1604
1605
            if ($this->db->query($sql)) {
1606
                $this->remise_absolue = $remise;
1607
                $this->update_price(1);
1608
                return 1;
1609
            } else {
1610
                $this->error = $this->db->error();
1611
                return -1;
1612
            }
1613
        }
1614
        return 0;
1615
    }
1616
    */
1617
1618
1619
    /**
1620
     *  Reopen the commercial proposal
1621
     *
1622
     *  @param      User    $user       Object user that close
1623
     *  @param      int     $statut     Statut
1624
     *  @param      string  $note       Comment
1625
     *  @param      int     $notrigger  1=Does not execute triggers, 0= execute triggers
1626
     *  @return     int                 Return integer <0 if KO, >0 if OK
1627
     */
1628
    public function reopen($user, $statut, $note = '', $notrigger = 0)
1629
    {
1630
        global $langs, $conf;
1631
1632
        $this->statut = $statut;
1633
        $error = 0;
1634
1635
        $sql = "UPDATE " . MAIN_DB_PREFIX . "supplier_proposal";
1636
        $sql .= " SET fk_statut = " . ((int) $this->statut) . ",";
1637
        if (!empty($note)) {
1638
            $sql .= " note_private = '" . $this->db->escape($note) . "',";
1639
        }
1640
        $sql .= " date_cloture = NULL, fk_user_cloture = NULL";
1641
        $sql .= " WHERE rowid = " . ((int) $this->id);
1642
1643
        $this->db->begin();
1644
1645
        dol_syslog(get_only_class($this) . "::reopen", LOG_DEBUG);
1646
        $resql = $this->db->query($sql);
1647
        if (!$resql) {
1648
            $error++;
1649
            $this->errors[] = "Error " . $this->db->lasterror();
1650
        }
1651
        if (!$error) {
1652
            if (!$notrigger) {
1653
                // Call trigger
1654
                $result = $this->call_trigger('PROPOSAL_SUPPLIER_REOPEN', $user);
1655
                if ($result < 0) {
1656
                    $error++;
1657
                }
1658
                // End call triggers
1659
            }
1660
        }
1661
1662
        // Commit or rollback
1663
        if ($error) {
1664
            if (!empty($this->errors)) {
1665
                foreach ($this->errors as $errmsg) {
1666
                    dol_syslog(get_only_class($this) . "::update " . $errmsg, LOG_ERR);
1667
                    $this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
1668
                }
1669
            }
1670
            $this->db->rollback();
1671
            return -1 * $error;
1672
        } else {
1673
            $this->db->commit();
1674
            return 1;
1675
        }
1676
    }
1677
1678
1679
    /**
1680
     *  Close the askprice
1681
     *
1682
     *  @param      User    $user       Object user that close
1683
     *  @param      int     $status     Status
1684
     *  @param      string  $note       Comment
1685
     *  @return     int                 Return integer <0 if KO, >0 if OK
1686
     */
1687
    public function cloture($user, $status, $note)
1688
    {
1689
        global $langs, $conf;
1690
        $hidedetails = 0;
1691
        $hidedesc = 0;
1692
        $hideref = 0;
1693
        $this->statut = $status;
1694
        $error = 0;
1695
        $now = dol_now();
1696
1697
        $this->db->begin();
1698
1699
        $sql = "UPDATE " . MAIN_DB_PREFIX . "supplier_proposal";
1700
        $sql .= " SET fk_statut = " . ((int) $status) . ", note_private = '" . $this->db->escape($note) . "', date_cloture='" . $this->db->idate($now) . "', fk_user_cloture=" . $user->id;
1701
        $sql .= " WHERE rowid = " . ((int) $this->id);
1702
1703
        $resql = $this->db->query($sql);
1704
        if ($resql) {
1705
            $modelpdf = $conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_CLOSED ? $conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_CLOSED : (empty($this->model_pdf) ? '' : $this->model_pdf);
1706
            $triggerName = 'PROPOSAL_SUPPLIER_CLOSE_REFUSED';
1707
1708
            if ($status == 2) {
1709
                $triggerName = 'PROPOSAL_SUPPLIER_CLOSE_SIGNED';
1710
                $modelpdf = $conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_TOBILL ? $conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_TOBILL : (empty($this->model_pdf) ? '' : $this->model_pdf);
1711
1712
                if (getDolGlobalString('SUPPLIER_PROPOSAL_UPDATE_PRICE_ON_SUPPlIER_PROPOSAL')) {     // TODO This option was not tested correctly. Error if product ref does not exists
1713
                    $result = $this->updateOrCreatePriceFournisseur($user);
1714
                }
1715
            }
1716
            if ($status == 4) {
1717
                $triggerName = 'PROPOSAL_SUPPLIER_CLASSIFY_BILLED';
1718
            }
1719
1720
            if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1721
                // Define output language
1722
                $outputlangs = $langs;
1723
                if (getDolGlobalInt('MAIN_MULTILANGS')) {
1724
                    $outputlangs = new Translate("", $conf);
1725
                    $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $this->thirdparty->default_lang);
1726
                    $outputlangs->setDefaultLang($newlang);
1727
                }
1728
                //$ret=$object->fetch($id);    // Reload to get new records
1729
                $this->generateDocument($modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1730
            }
1731
1732
            // Call trigger
1733
            $result = $this->call_trigger($triggerName, $user);
1734
            if ($result < 0) {
1735
                $error++;
1736
            }
1737
            // End call triggers
1738
1739
            if (!$error) {
1740
                $this->db->commit();
1741
                return 1;
1742
            } else {
1743
                $this->db->rollback();
1744
                return -1;
1745
            }
1746
        } else {
1747
            $this->error = $this->db->lasterror();
1748
            $this->errors[] = $this->db->lasterror();
1749
            $this->db->rollback();
1750
            return -1;
1751
        }
1752
    }
1753
1754
    /**
1755
     *  Add or update supplier price according to result of proposal
1756
     *
1757
     *  @param     User     $user       Object user
1758
     *  @return    int                  > 0 if OK
1759
     */
1760
    public function updateOrCreatePriceFournisseur($user)
1761
    {
1762
        global $conf;
1763
1764
        dol_syslog(get_only_class($this) . "::updateOrCreatePriceFournisseur", LOG_DEBUG);
1765
        foreach ($this->lines as $product) {
1766
            if ($product->subprice <= 0) {
1767
                continue;
1768
            }
1769
            $productsupplier = new ProductFournisseur($this->db);
1770
1771
            $multicurrency_tx = 1;
1772
            $fk_multicurrency = 0;
1773
1774
            if (empty($this->thirdparty)) {
1775
                $this->fetch_thirdparty();
1776
            }
1777
1778
            $ref_fourn = $product->ref_fourn;
1779
            if (empty($ref_fourn)) {
1780
                $ref_fourn = $product->ref_supplier;
1781
            }
1782
            if (isModEnabled("multicurrency") && !empty($product->multicurrency_code)) {
1783
                list($fk_multicurrency, $multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $product->multicurrency_code);
1784
            }
1785
            $productsupplier->id = $product->fk_product;
1786
1787
            $productsupplier->update_buyprice($product->qty, $product->total_ht, $user, 'HT', $this->thirdparty, '', $ref_fourn, $product->tva_tx, 0, 0, 0, $product->info_bits, '', '', array(), '', $product->multicurrency_total_ht, 'HT', $multicurrency_tx, $product->multicurrency_code, '', '', '');
1788
        }
1789
1790
        return 1;
1791
    }
1792
1793
    /**
1794
     *  Update ProductFournisseur
1795
     *
1796
     *  @param      int     $idProductFournPrice    id of llx_product_fournisseur_price
1797
     *  @param      Product $product                contain information to update
1798
     *  @param      User    $user                   Object user
1799
     *  @return     int                             Return integer <0 if KO, >0 if OK
1800
     */
1801
    public function updatePriceFournisseur($idProductFournPrice, $product, $user)
1802
    {
1803
        $price = price2num($product->subprice * $product->qty, 'MU');
1804
        $unitPrice = price2num($product->subprice, 'MU');
1805
1806
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'product_fournisseur_price SET ' . (!empty($product->ref_fourn) ? 'ref_fourn = "' . $this->db->escape($product->ref_fourn) . '", ' : '') . ' price =' . ((float) $price) . ', unitprice =' . ((float) $unitPrice) . ' WHERE rowid = ' . ((int) $idProductFournPrice);
1807
1808
        $resql = $this->db->query($sql);
1809
        if (!$resql) {
1810
            $this->error = $this->db->error();
1811
            $this->db->rollback();
1812
            return -1;
1813
        }
1814
        return 1;
1815
    }
1816
1817
    /**
1818
     *  Create ProductFournisseur
1819
     *
1820
     *  @param      Product     $product    Object Product
1821
     *  @param      User        $user       Object user
1822
     *  @return     int                     Return integer <0 if KO, >0 if OK
1823
     */
1824
    public function createPriceFournisseur($product, $user)
1825
    {
1826
        global $conf;
1827
1828
        $price = price2num($product->subprice * $product->qty, 'MU');
1829
        $qty = price2num($product->qty);
1830
        $unitPrice = price2num($product->subprice, 'MU');
1831
1832
        $now = dol_now();
1833
1834
        $values = array(
1835
            "'" . $this->db->idate($now) . "'",
1836
            $product->fk_product,
1837
            $this->thirdparty->id,
1838
            "'" . $product->ref_fourn . "'",
1839
            $price,
1840
            $qty,
1841
            $unitPrice,
1842
            $product->tva_tx,
1843
            $user->id
1844
        );
1845
        if (isModEnabled("multicurrency")) {
1846
            if (!empty($product->multicurrency_code)) {
1847
                $multicurrency = new MultiCurrency($this->db); //need to fetch because empty fk_multicurrency and rate
1848
                $multicurrency->fetch(0, $product->multicurrency_code);
1849
                if (!empty($multicurrency->id)) {
1850
                    $values[] = $multicurrency->id;
1851
                    $values[] = "'" . $product->multicurrency_code . "'";
1852
                    $values[] = $product->multicurrency_subprice;
1853
                    $values[] = $product->multicurrency_total_ht;
1854
                    $values[] = $multicurrency->rate->rate;
1855
                } else {
1856
                    for ($i = 0; $i < 5; $i++) {
1857
                        $values[] = 'NULL';
1858
                    }
1859
                }
1860
            }
1861
        }
1862
1863
        $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . 'product_fournisseur_price ';
1864
        $sql .= '(datec, fk_product, fk_soc, ref_fourn, price, quantity, unitprice, tva_tx, fk_user';
1865
        if (isModEnabled("multicurrency") && !empty($product->multicurrency_code)) {
1866
            $sql .= ',fk_multicurrency, multicurrency_code, multicurrency_unitprice, multicurrency_price, multicurrency_tx';
1867
        }
1868
        $sql .= ')  VALUES (' . implode(',', $values) . ')';
1869
1870
        $resql = $this->db->query($sql);
1871
        if (!$resql) {
1872
            $this->error = $this->db->error();
1873
            $this->db->rollback();
1874
            return -1;
1875
        }
1876
        return 1;
1877
    }
1878
1879
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1880
    /**
1881
     *  Set draft status
1882
     *
1883
     *  @param      User    $user       Object user that modify
1884
     *  @return     int                 Return integer <0 if KO, >0 if OK
1885
     */
1886
    public function setDraft($user)
1887
    {
1888
		// phpcs:enable
1889
        global $conf, $langs;
1890
1891
        $error = 0;
1892
1893
        if ($this->statut == self::STATUS_DRAFT) {
1894
            dol_syslog(get_only_class($this) . "::setDraft already draft status", LOG_WARNING);
1895
            return 0;
1896
        }
1897
1898
        $sql = "UPDATE " . MAIN_DB_PREFIX . "supplier_proposal";
1899
        $sql .= " SET fk_statut = " . self::STATUS_DRAFT;
1900
        $sql .= " WHERE rowid = " . ((int) $this->id);
1901
1902
        if ($this->db->query($sql)) {
1903
            if (!$error) {
1904
                $this->oldcopy = clone $this;
1905
            }
1906
1907
            if (!$error) {
1908
                // Call trigger
1909
                $result = $this->call_trigger('PROPOSAL_SUPPLIER_UNVALIDATE', $user);
1910
                if ($result < 0) {
1911
                    $error++;
1912
                }
1913
            }
1914
1915
            if (!$error) {
1916
                $this->status = self::STATUS_DRAFT;
1917
                $this->statut = self::STATUS_DRAFT; // deprecated
1918
                $this->db->commit();
1919
                return 1;
1920
            } else {
1921
                $this->db->rollback();
1922
                return -1;
1923
            }
1924
        } else {
1925
            return -1;
1926
        }
1927
    }
1928
1929
1930
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1931
    /**
1932
     *    Return list of askprice (eventually filtered on user) into an array
1933
     *
1934
     *    @param    int     $shortlist          0=Return array[id]=ref, 1=Return array[](id=>id,ref=>ref,name=>name)
1935
     *    @param    int     $draft              0=not draft, 1=draft
1936
     *    @param    int     $notcurrentuser     0=all user, 1=not current user
1937
     *    @param    int     $socid              Id third party
1938
     *    @param    int     $limit              For pagination
1939
     *    @param    int     $offset             For pagination
1940
     *    @param    string  $sortfield          Sort criteria
1941
     *    @param    string  $sortorder          Sort order
1942
     *    @return   array|int                           -1 if KO, array with result if OK
1943
     */
1944
    public function liste_array($shortlist = 0, $draft = 0, $notcurrentuser = 0, $socid = 0, $limit = 0, $offset = 0, $sortfield = 'p.datec', $sortorder = 'DESC')
1945
    {
1946
		// phpcs:enable
1947
        global $user;
1948
1949
        $ga = array();
1950
1951
        $search_sale = 0;
1952
        if (!$user->hasRight('societe', 'client', 'voir')) {
1953
            $search_sale = $user->id;
1954
        }
1955
1956
        $sql = "SELECT s.rowid, s.nom as name, s.client,";
1957
        $sql .= " p.rowid as supplier_proposalid, p.fk_statut, p.total_ht, p.ref, p.remise, ";
1958
        $sql .= " p.datep as dp, p.fin_validite as datelimite";
1959
        $sql .= " FROM " . MAIN_DB_PREFIX . "societe as s, " . MAIN_DB_PREFIX . "supplier_proposal as p, " . MAIN_DB_PREFIX . "c_propalst as c";
1960
        $sql .= " WHERE p.entity IN (" . getEntity('supplier_proposal') . ")";
1961
        $sql .= " AND p.fk_soc = s.rowid";
1962
        $sql .= " AND p.fk_statut = c.id";
1963
        if ($socid) {
1964
            $sql .= " AND s.rowid = " . ((int) $socid);
1965
        }
1966
        if ($draft) {
1967
            $sql .= " AND p.fk_statut = 0";
1968
        }
1969
        if ($notcurrentuser > 0) {
1970
            $sql .= " AND p.fk_user_author <> " . ((int) $user->id);
1971
        }
1972
        // Search on sale representative
1973
        if ($search_sale && $search_sale != '-1') {
1974
            if ($search_sale == -2) {
1975
                $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM " . MAIN_DB_PREFIX . "societe_commerciaux as sc WHERE sc.fk_soc = p.fk_soc)";
1976
            } elseif ($search_sale > 0) {
1977
                $sql .= " AND EXISTS (SELECT sc.fk_soc FROM " . MAIN_DB_PREFIX . "societe_commerciaux as sc WHERE sc.fk_soc = p.fk_soc AND sc.fk_user = " . ((int) $search_sale) . ")";
1978
            }
1979
        }
1980
        $sql .= $this->db->order($sortfield, $sortorder);
1981
        $sql .= $this->db->plimit($limit, $offset);
1982
1983
        $result = $this->db->query($sql);
1984
        if ($result) {
1985
            $num = $this->db->num_rows($result);
1986
            if ($num) {
1987
                $i = 0;
1988
                while ($i < $num) {
1989
                    $obj = $this->db->fetch_object($result);
1990
1991
                    if ($shortlist == 1) {
1992
                        $ga[$obj->supplier_proposalid] = $obj->ref;
1993
                    } elseif ($shortlist == 2) {
1994
                        $ga[$obj->supplier_proposalid] = $obj->ref . ' (' . $obj->name . ')';
1995
                    } else {
1996
                        $ga[$i]['id'] = $obj->supplier_proposalid;
1997
                        $ga[$i]['ref']  = $obj->ref;
1998
                        $ga[$i]['name'] = $obj->name;
1999
                    }
2000
2001
                    $i++;
2002
                }
2003
            }
2004
            return $ga;
2005
        } else {
2006
            dol_print_error($this->db);
2007
            return -1;
2008
        }
2009
    }
2010
2011
    /**
2012
     *  Delete askprice
2013
     *
2014
     *  @param  User    $user           Object user that delete
2015
     *  @param  int     $notrigger      1=Does not execute triggers, 0= execute triggers
2016
     *  @return int                     1 if ok, otherwise if error
2017
     */
2018
    public function delete($user, $notrigger = 0)
2019
    {
2020
        global $conf, $langs;
2021
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
2022
2023
        $error = 0;
2024
2025
        $this->db->begin();
2026
2027
        if (!$notrigger) {
2028
            // Call trigger
2029
            $result = $this->call_trigger('PROPOSAL_SUPPLIER_DELETE', $user);
2030
            if ($result < 0) {
2031
                $error++;
2032
            }
2033
            // End call triggers
2034
        }
2035
2036
        if (!$error) {
2037
            $main = MAIN_DB_PREFIX . 'supplier_proposaldet';
2038
            $ef = $main . "_extrafields";
2039
            $sqlef = "DELETE FROM $ef WHERE fk_object IN (SELECT rowid FROM $main WHERE fk_supplier_proposal = " . ((int) $this->id) . ")";
2040
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . "supplier_proposaldet WHERE fk_supplier_proposal = " . ((int) $this->id);
2041
            if ($this->db->query($sql)) {
2042
                $sql = "DELETE FROM " . MAIN_DB_PREFIX . "supplier_proposal WHERE rowid = " . ((int) $this->id);
2043
                if ($this->db->query($sqlef) && $this->db->query($sql)) {
2044
                    // Delete linked object
2045
                    $res = $this->deleteObjectLinked();
2046
                    if ($res < 0) {
2047
                        $error++;
2048
                    }
2049
2050
                    if (!$error) {
2051
                        // Delete record into ECM index (Note that delete is also done when deleting files with the dol_delete_dir_recursive
2052
                        $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
2053
                        $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive
2054
2055
                        // We remove directory
2056
                        $ref = dol_sanitizeFileName($this->ref);
2057
                        if ($conf->supplier_proposal->dir_output && !empty($this->ref)) {
2058
                            $dir = $conf->supplier_proposal->dir_output . "/" . $ref;
2059
                            $file = $dir . "/" . $ref . ".pdf";
2060
                            if (file_exists($file)) {
2061
                                dol_delete_preview($this);
2062
2063
                                if (!dol_delete_file($file, 0, 0, 0, $this)) { // For triggers
2064
                                    $this->error = 'ErrorFailToDeleteFile';
2065
                                    $this->errors = array('ErrorFailToDeleteFile');
2066
                                    $this->db->rollback();
2067
                                    return 0;
2068
                                }
2069
                            }
2070
                            if (file_exists($dir)) {
2071
                                $res = @dol_delete_dir_recursive($dir);
2072
                                if (!$res) {
2073
                                    $this->error = 'ErrorFailToDeleteDir';
2074
                                    $this->errors = array('ErrorFailToDeleteDir');
2075
                                    $this->db->rollback();
2076
                                    return 0;
2077
                                }
2078
                            }
2079
                        }
2080
                    }
2081
2082
                    // Removed extrafields
2083
                    if (!$error) {
2084
                        $result = $this->deleteExtraFields();
2085
                        if ($result < 0) {
2086
                            $error++;
2087
                            $errorflag = -4;
2088
                            dol_syslog(get_only_class($this) . "::delete erreur " . $errorflag . " " . $this->error, LOG_ERR);
2089
                        }
2090
                    }
2091
2092
                    if (!$error) {
2093
                        dol_syslog(get_only_class($this) . "::delete " . $this->id . " by " . $user->id, LOG_DEBUG);
2094
                        $this->db->commit();
2095
                        return 1;
2096
                    } else {
2097
                        $this->error = $this->db->lasterror();
2098
                        $this->db->rollback();
2099
                        return 0;
2100
                    }
2101
                } else {
2102
                    $this->error = $this->db->lasterror();
2103
                    $this->db->rollback();
2104
                    return -3;
2105
                }
2106
            } else {
2107
                $this->error = $this->db->lasterror();
2108
                $this->db->rollback();
2109
                return -2;
2110
            }
2111
        } else {
2112
            $this->db->rollback();
2113
            return -1;
2114
        }
2115
    }
2116
2117
    /**
2118
     *  Object SupplierProposal Information
2119
     *
2120
     *  @param  int     $id     Proposal id
2121
     *  @return void
2122
     */
2123
    public function info($id)
2124
    {
2125
        $sql = "SELECT c.rowid, ";
2126
        $sql .= " c.datec as date_creation, c.date_valid as date_validation, c.date_cloture as date_closure,";
2127
        $sql .= " c.fk_user_author, c.fk_user_valid, c.fk_user_cloture";
2128
        $sql .= " FROM " . MAIN_DB_PREFIX . "supplier_proposal as c";
2129
        $sql .= " WHERE c.rowid = " . ((int) $id);
2130
2131
        $result = $this->db->query($sql);
2132
2133
        if ($result) {
2134
            if ($this->db->num_rows($result)) {
2135
                $obj = $this->db->fetch_object($result);
2136
2137
                $this->id                = $obj->rowid;
2138
2139
                $this->date_creation     = $this->db->jdate($obj->date_creation);
2140
                $this->date_validation   = $this->db->jdate($obj->date_validation);
2141
                $this->date_cloture      = $this->db->jdate($obj->date_closure);
2142
2143
                $this->user_creation_id = $obj->fk_user_author;
2144
                $this->user_validation_id = $obj->fk_user_valid;
2145
                $this->user_closing_id = $obj->fk_user_cloture;
2146
            }
2147
            $this->db->free($result);
2148
        } else {
2149
            dol_print_error($this->db);
2150
        }
2151
    }
2152
2153
2154
    /**
2155
     *      Return label of status of proposal (draft, validated, ...)
2156
     *
2157
     *      @param      int         $mode        0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
2158
     *      @return     string      Label
2159
     */
2160
    public function getLibStatut($mode = 0)
2161
    {
2162
        return $this->LibStatut((isset($this->statut) ? $this->statut : $this->status), $mode);
2163
    }
2164
2165
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2166
    /**
2167
     *  Return label of a status (draft, validated, ...)
2168
     *
2169
     *  @param      int         $status     Id status
2170
     *  @param      int         $mode       0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
2171
     *  @return     string      Label
2172
     */
2173
    public function LibStatut($status, $mode = 1)
2174
    {
2175
		// phpcs:enable
2176
2177
        // Init/load array of translation of status
2178
        if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
2179
            global $langs;
2180
            $langs->load("supplier_proposal");
2181
            $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv("SupplierProposalStatusDraft");
2182
            $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv("SupplierProposalStatusValidated");
2183
            $this->labelStatus[self::STATUS_SIGNED] = $langs->transnoentitiesnoconv("SupplierProposalStatusSigned");
2184
            $this->labelStatus[self::STATUS_NOTSIGNED] = $langs->transnoentitiesnoconv("SupplierProposalStatusNotSigned");
2185
            $this->labelStatus[self::STATUS_CLOSE] = $langs->transnoentitiesnoconv("SupplierProposalStatusClosed");
2186
            $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv("SupplierProposalStatusDraftShort");
2187
            $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv("SupplierProposalStatusValidatedShort");
2188
            $this->labelStatusShort[self::STATUS_SIGNED] = $langs->transnoentitiesnoconv("SupplierProposalStatusSignedShort");
2189
            $this->labelStatusShort[self::STATUS_NOTSIGNED] = $langs->transnoentitiesnoconv("SupplierProposalStatusNotSignedShort");
2190
            $this->labelStatusShort[self::STATUS_CLOSE] = $langs->transnoentitiesnoconv("SupplierProposalStatusClosedShort");
2191
        }
2192
2193
        $statusnew = '';
2194
        if ($status == self::STATUS_DRAFT) {
2195
            $statusnew = 'status0';
2196
        } elseif ($status == self::STATUS_VALIDATED) {
2197
            $statusnew = 'status1';
2198
        } elseif ($status == self::STATUS_SIGNED) {
2199
            $statusnew = 'status4';
2200
        } elseif ($status == self::STATUS_NOTSIGNED) {
2201
            $statusnew = 'status9';
2202
        } elseif ($status == self::STATUS_CLOSE) {
2203
            $statusnew = 'status6';
2204
        }
2205
2206
        return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusnew, $mode);
2207
    }
2208
2209
2210
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2211
    /**
2212
     *      Load indicators for dashboard (this->nbtodo and this->nbtodolate)
2213
     *
2214
     *      @param          User    $user   Object user
2215
     *      @param          string  $mode   "opened" for askprice to close, "signed" for proposal to invoice
2216
     *      @return         WorkboardResponse|int   Return integer <0 if KO, WorkboardResponse if OK
2217
     */
2218
    public function load_board($user, $mode)
2219
    {
2220
		// phpcs:enable
2221
        global $conf, $user, $langs;
2222
2223
        $now = dol_now();
2224
2225
        $clause = " WHERE";
2226
2227
        $sql = "SELECT p.rowid, p.ref, p.datec as datec, p.date_cloture as datefin";
2228
        $sql .= " FROM " . MAIN_DB_PREFIX . "supplier_proposal as p";
2229
        if (!$user->hasRight('societe', 'client', 'voir')) {
2230
            $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON p.fk_soc = sc.fk_soc";
2231
            $sql .= " WHERE sc.fk_user = " . ((int) $user->id);
2232
            $clause = " AND";
2233
        }
2234
        $sql .= $clause . " p.entity IN (" . getEntity('supplier_proposal') . ")";
2235
        if ($mode == 'opened') {
2236
            $sql .= " AND p.fk_statut = 1";
2237
        }
2238
        if ($mode == 'signed') {
2239
            $sql .= " AND p.fk_statut = 2";
2240
        }
2241
        if ($user->socid) {
2242
            $sql .= " AND p.fk_soc = " . ((int) $user->socid);
2243
        }
2244
2245
        $resql = $this->db->query($sql);
2246
        if ($resql) {
2247
            $label = $labelShort = '';
2248
            $status = '';
2249
            if ($mode == 'opened') {
2250
                $delay_warning = !empty($conf->supplier_proposal->cloture->warning_delay) ? $conf->supplier_proposal->cloture->warning_delay : 0;
2251
                $status = self::STATUS_VALIDATED;
2252
                $label = $langs->trans("SupplierProposalsToClose");
2253
                $labelShort = $langs->trans("ToAcceptRefuse");
2254
            }
2255
            if ($mode == 'signed') {
2256
                $delay_warning = !empty($conf->supplier_proposal->facturation->warning_delay) ? $conf->supplier_proposal->facturation->warning_delay : 0;
2257
                $status = self::STATUS_SIGNED;
2258
                $label = $langs->trans("SupplierProposalsToProcess"); // May be billed or ordered
2259
                $labelShort = $langs->trans("ToClose");
2260
            }
2261
2262
            $response = new WorkboardResponse();
2263
            $response->warning_delay = $delay_warning / 60 / 60 / 24;
2264
            $response->label = $label;
2265
            $response->labelShort = $labelShort;
2266
            $response->url = constant('BASE_URL') . '/supplier_proposal/list.php?search_status=' . $status;
2267
            $response->img = img_object('', "propal");
2268
2269
            // This assignment in condition is not a bug. It allows walking the results.
2270
            while ($obj = $this->db->fetch_object($resql)) {
2271
                $response->nbtodo++;
2272
                if ($mode == 'opened') {
2273
                    $datelimit = $this->db->jdate($obj->datefin);
2274
                    if ($datelimit < ($now - $delay_warning)) {
2275
                        $response->nbtodolate++;
2276
                    }
2277
                }
2278
                // TODO Definir regle des propales a facturer en retard
2279
                // if ($mode == 'signed' && ! count($this->FactureListeArray($obj->rowid))) $this->nbtodolate++;
2280
            }
2281
            return $response;
2282
        } else {
2283
            $this->error = $this->db->lasterror();
2284
            return -1;
2285
        }
2286
    }
2287
2288
2289
    /**
2290
     *  Initialise an instance with random values.
2291
     *  Used to build previews or test instances.
2292
     *  id must be 0 if object instance is a specimen.
2293
     *
2294
     *  @return int
2295
     */
2296
    public function initAsSpecimen()
2297
    {
2298
        global $user, $langs, $conf;
2299
2300
        // Load array of products prodids
2301
        $num_prods = 0;
2302
        $prodids = array();
2303
        $sql = "SELECT rowid";
2304
        $sql .= " FROM " . MAIN_DB_PREFIX . "product";
2305
        $sql .= " WHERE entity IN (" . getEntity('product') . ")";
2306
        $sql .= $this->db->plimit(100);
2307
2308
        $resql = $this->db->query($sql);
2309
        if ($resql) {
2310
            $num_prods = $this->db->num_rows($resql);
2311
            $i = 0;
2312
            while ($i < $num_prods) {
2313
                $i++;
2314
                $row = $this->db->fetch_row($resql);
2315
                $prodids[$i] = $row[0];
2316
            }
2317
        }
2318
2319
        // Initialise parameters
2320
        $this->id = 0;
2321
        $this->ref = 'SPECIMEN';
2322
        $this->specimen = 1;
2323
        $this->socid = 1;
2324
        $this->date = time();
2325
        $this->cond_reglement_id   = 1;
2326
        $this->cond_reglement_code = 'RECEP';
2327
        $this->mode_reglement_id   = 7;
2328
        $this->mode_reglement_code = 'CHQ';
2329
        $this->note_public = 'This is a comment (public)';
2330
        $this->note_private = 'This is a comment (private)';
2331
        // Lines
2332
        $nbp = 5;
2333
        $xnbp = 0;
2334
        while ($xnbp < $nbp) {
2335
            $line = new SupplierProposalLine($this->db);
2336
            $line->desc = $langs->trans("Description") . " " . $xnbp;
2337
            $line->qty = 1;
2338
            $line->subprice = 100;
2339
            $line->tva_tx = 19.6;
2340
            $line->localtax1_tx = 0;
2341
            $line->localtax2_tx = 0;
2342
            if ($xnbp == 2) {
2343
                $line->total_ht = 50;
2344
                $line->total_ttc = 59.8;
2345
                $line->total_tva = 9.8;
2346
                $line->remise_percent = 50;
2347
            } else {
2348
                $line->total_ht = 100;
2349
                $line->total_ttc = 119.6;
2350
                $line->total_tva = 19.6;
2351
                $line->remise_percent = 0;
2352
            }
2353
2354
            if ($num_prods > 0) {
2355
                $prodid = mt_rand(1, $num_prods);
2356
                $line->fk_product = $prodids[$prodid];
2357
            }
2358
2359
            $this->lines[$xnbp] = $line;
2360
2361
            $this->total_ht       += $line->total_ht;
2362
            $this->total_tva      += $line->total_tva;
2363
            $this->total_ttc      += $line->total_ttc;
2364
2365
            $xnbp++;
2366
        }
2367
2368
        return 1;
2369
    }
2370
2371
    /**
2372
     *      Load indicator this->nb of global stats widget
2373
     *
2374
     *      @return     int         Return integer <0 if ko, >0 if ok
2375
     */
2376
    public function loadStateBoard()
2377
    {
2378
        global $conf, $user;
2379
2380
        $this->nb = array();
2381
        $clause = "WHERE";
2382
2383
        $sql = "SELECT count(p.rowid) as nb";
2384
        $sql .= " FROM " . MAIN_DB_PREFIX . "supplier_proposal as p";
2385
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON p.fk_soc = s.rowid";
2386
        if (!$user->hasRight('societe', 'client', 'voir')) {
2387
            $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON s.rowid = sc.fk_soc";
2388
            $sql .= " WHERE sc.fk_user = " . ((int) $user->id);
2389
            $clause = "AND";
2390
        }
2391
        $sql .= " " . $clause . " p.entity IN (" . getEntity('supplier_proposal') . ")";
2392
2393
        $resql = $this->db->query($sql);
2394
        if ($resql) {
2395
            // This assignment in condition is not a bug. It allows walking the results.
2396
            while ($obj = $this->db->fetch_object($resql)) {
2397
                $this->nb["supplier_proposals"] = $obj->nb;
2398
            }
2399
            $this->db->free($resql);
2400
            return 1;
2401
        } else {
2402
            dol_print_error($this->db);
2403
            $this->error = $this->db->lasterror();
2404
            return -1;
2405
        }
2406
    }
2407
2408
2409
    /**
2410
     *  Returns the reference to the following non used Proposal used depending on the active numbering module
2411
     *  defined into SUPPLIER_PROPOSAL_ADDON
2412
     *
2413
     *  @param  Societe     $soc    Object thirdparty
2414
     *  @return string              Reference libre pour la propale
2415
     */
2416
    public function getNextNumRef($soc)
2417
    {
2418
        global $conf, $db, $langs;
2419
        $langs->load("supplier_proposal");
2420
2421
        if (getDolGlobalString('SUPPLIER_PROPOSAL_ADDON')) {
2422
            $mybool = false;
2423
2424
            $file = getDolGlobalString('SUPPLIER_PROPOSAL_ADDON') . ".php";
2425
            $classname = getDolGlobalString('SUPPLIER_PROPOSAL_ADDON');
2426
2427
            // Include file with class
2428
            $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2429
            foreach ($dirmodels as $reldir) {
2430
                $dir = dol_buildpath($reldir . "core/modules/supplier_proposal/");
2431
2432
                // Load file with numbering class (if found)
2433
                $mybool = ((bool) @include_once $dir . $file) || $mybool;
2434
            }
2435
2436
            if (!$mybool) {
2437
                dol_print_error(null, "Failed to include file " . $file);
2438
                return '';
2439
            }
2440
2441
            $obj = new $classname();
2442
            $numref = "";
2443
            $numref = $obj->getNextValue($soc, $this);
2444
2445
            if ($numref != "") {
2446
                return $numref;
2447
            } else {
2448
                $this->error = $obj->error;
2449
                return "";
2450
            }
2451
        } else {
2452
            $langs->load("errors");
2453
            print $langs->trans("Error") . " " . $langs->trans("ErrorModuleSetupNotComplete", $langs->transnoentitiesnoconv("SupplierProposal"));
2454
            return "";
2455
        }
2456
    }
2457
2458
    /**
2459
     * getTooltipContentArray
2460
     *
2461
     * @param array $params ex option, infologin
2462
     * @since v18
2463
     * @return array
2464
     */
2465
    public function getTooltipContentArray($params)
2466
    {
2467
        global $conf, $langs, $menumanager;
2468
2469
        $langs->load('supplier_proposal');
2470
2471
        if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2472
            return ['optimize' => $langs->trans("ShowSupplierProposal")];
2473
        }
2474
2475
        $option = $params['option'] ?? '';
2476
        $datas = [];
2477
2478
        $datas['picto'] = img_picto('', $this->picto) . ' <u class="paddingrightonly">' . $langs->trans("SupplierProposal") . '</u>';
2479
        if (isset($this->status)) {
2480
            $datas['picto'] .= ' ' . $this->getLibStatut(5);
2481
        }
2482
        if (!empty($this->ref)) {
2483
            $datas['ref'] = '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
2484
        }
2485
        if (!empty($this->ref_fourn)) {
2486
            $datas['ref_supplier'] = '<br><b>' . $langs->trans('RefSupplier') . ':</b> ' . $this->ref_fourn;
2487
        }
2488
        if (!empty($this->total_ht)) {
2489
            $datas['amount_ht'] = '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
2490
        }
2491
        if (!empty($this->total_tva)) {
2492
            $datas['amount_vat'] = '<br><b>' . $langs->trans('VAT') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
2493
        }
2494
        if (!empty($this->total_ttc)) {
2495
            $datas['amount_ttc'] = '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
2496
        }
2497
2498
        return $datas;
2499
    }
2500
2501
    /**
2502
     *  Return clicable link of object (with eventually picto)
2503
     *
2504
     *  @param      int     $withpicto                  Add picto into link
2505
     *  @param      string  $option                     Where point the link ('compta', 'expedition', 'document', ...)
2506
     *  @param      string  $get_params                 Parameters added to url
2507
     *  @param      int     $notooltip                  1=Disable tooltip
2508
     *  @param      int     $save_lastsearch_value      -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
2509
     *  @param      int     $addlinktonotes             Add link to show notes
2510
     *  @return     string                              String with URL
2511
     */
2512
    public function getNomUrl($withpicto = 0, $option = '', $get_params = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
2513
    {
2514
        global $langs, $conf, $user, $hookmanager;
2515
2516
        if (!empty($conf->dol_no_mouse_hover)) {
2517
            $notooltip = 1; // Force disable tooltips
2518
        }
2519
2520
        $url = '';
2521
        $result = '';
2522
        $params = [
2523
            'id' => $this->id,
2524
            'objecttype' => $this->element,
2525
            'option' => $option,
2526
        ];
2527
        $classfortooltip = 'classfortooltip';
2528
        $dataparams = '';
2529
        if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
2530
            $classfortooltip = 'classforajaxtooltip';
2531
            $dataparams = ' data-params="' . dol_escape_htmltag(json_encode($params)) . '"';
2532
            $label = '';
2533
        } else {
2534
            $label = implode($this->getTooltipContentArray($params));
2535
        }
2536
2537
        if ($option == '') {
2538
            $url = constant('BASE_URL') . '/supplier_proposal/card.php?id=' . $this->id . $get_params;
2539
        }
2540
        if ($option == 'document') {
2541
            $url = constant('BASE_URL') . '/supplier_proposal/document.php?id=' . $this->id . $get_params;
2542
        }
2543
2544
        if ($option !== 'nolink') {
2545
            // Add param to save lastsearch_values or not
2546
            $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
2547
            if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
2548
                $add_save_lastsearch_values = 1;
2549
            }
2550
            if ($add_save_lastsearch_values) {
2551
                $url .= '&save_lastsearch_values=1';
2552
            }
2553
        }
2554
2555
        $linkclose = '';
2556
        if (empty($notooltip) && $user->hasRight('propal', 'lire')) {
2557
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2558
                $label = $langs->trans("ShowSupplierProposal");
2559
                $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
2560
            }
2561
            $linkclose .= ($label ? ' title="' . dol_escape_htmltag($label, 1) . '"' : ' title="tocomplete"');
2562
            $linkclose .= $dataparams . ' class="' . $classfortooltip . '"';
2563
        }
2564
2565
        $linkstart = '<a href="' . $url . '"';
2566
        $linkstart .= $linkclose . '>';
2567
        $linkend = '</a>';
2568
2569
        $result .= $linkstart;
2570
        if ($withpicto) {
2571
            $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
2572
        }
2573
        if ($withpicto != 2) {
2574
            $result .= $this->ref;
2575
        }
2576
        $result .= $linkend;
2577
2578
        if ($addlinktonotes) {
2579
            $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
2580
            if ($txttoshow) {
2581
                $notetoshow = $langs->trans("ViewPrivateNote") . ':<br>' . dol_string_nohtmltag($txttoshow, 1);
2582
                $result .= ' <span class="note inline-block">';
2583
                $result .= '<a href="' . constant('BASE_URL') . '/supplier_proposal/note.php?id=' . $this->id . '" class="classfortooltip" title="' . dol_escape_htmltag($notetoshow) . '">';
2584
                $result .= img_picto('', 'note');
2585
                $result .= '</a>';
2586
                //$result.=img_picto($langs->trans("ViewNote"),'object_generic');
2587
                //$result.='</a>';
2588
                $result .= '</span>';
2589
            }
2590
        }
2591
        global $action;
2592
        $hookmanager->initHooks(array($this->element . 'dao'));
2593
        $parameters = array('id' => $this->id, 'getnomurl' => &$result);
2594
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2595
        if ($reshook > 0) {
2596
            $result = $hookmanager->resPrint;
2597
        } else {
2598
            $result .= $hookmanager->resPrint;
2599
        }
2600
        return $result;
2601
    }
2602
2603
    /**
2604
     *  Retrieve an array of supplier proposal lines
2605
     *
2606
     *  @return int     >0 if OK, <0 if KO
2607
     */
2608
    public function getLinesArray()
2609
    {
2610
        // For other object, here we call fetch_lines. But fetch_lines does not exists on supplier proposal
2611
2612
        $sql = 'SELECT pt.rowid, pt.label as custom_label, pt.description, pt.fk_product, pt.fk_remise_except,';
2613
        $sql .= ' pt.qty, pt.tva_tx, pt.vat_src_code, pt.remise_percent, pt.subprice, pt.info_bits,';
2614
        $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,';
2615
        $sql .= ' pt.product_type, pt.rang, pt.fk_parent_line,';
2616
        $sql .= ' p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid,';
2617
        $sql .= ' p.description as product_desc, pt.ref_fourn as ref_supplier,';
2618
        $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';
2619
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'supplier_proposaldet as pt';
2620
        $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'product as p ON pt.fk_product=p.rowid';
2621
        $sql .= ' WHERE pt.fk_supplier_proposal = ' . ((int) $this->id);
2622
        $sql .= ' ORDER BY pt.rang ASC, pt.rowid';
2623
2624
        dol_syslog(get_only_class($this) . '::getLinesArray', LOG_DEBUG);
2625
        $resql = $this->db->query($sql);
2626
        if ($resql) {
2627
            $num = $this->db->num_rows($resql);
2628
            $i = 0;
2629
2630
            while ($i < $num) {
2631
                $obj = $this->db->fetch_object($resql);
2632
2633
                $this->lines[$i] = new SupplierProposalLine($this->db);
2634
                $this->lines[$i]->id = $obj->rowid; // for backward compatibility
2635
                $this->lines[$i]->rowid             = $obj->rowid;
2636
                $this->lines[$i]->label             = $obj->custom_label;
2637
                $this->lines[$i]->description = $obj->description;
2638
                $this->lines[$i]->fk_product = $obj->fk_product;
2639
                $this->lines[$i]->ref = $obj->ref;
2640
                $this->lines[$i]->product_label = $obj->product_label;
2641
                $this->lines[$i]->product_desc      = $obj->product_desc;
2642
                $this->lines[$i]->fk_product_type = $obj->fk_product_type; // deprecated
2643
                $this->lines[$i]->product_type      = $obj->product_type;
2644
                $this->lines[$i]->qty = $obj->qty;
2645
                $this->lines[$i]->subprice = $obj->subprice;
2646
                $this->lines[$i]->fk_remise_except = $obj->fk_remise_except;
2647
                $this->lines[$i]->remise_percent = $obj->remise_percent;
2648
                $this->lines[$i]->tva_tx = $obj->tva_tx;
2649
                $this->lines[$i]->vat_src_code = $obj->vat_src_code;
2650
                $this->lines[$i]->info_bits         = $obj->info_bits;
2651
                $this->lines[$i]->total_ht = $obj->total_ht;
2652
                $this->lines[$i]->total_tva         = $obj->total_tva;
2653
                $this->lines[$i]->total_ttc         = $obj->total_ttc;
2654
                $this->lines[$i]->fk_fournprice = $obj->fk_fournprice;
2655
                $marginInfos = getMarginInfos($obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, $this->lines[$i]->fk_fournprice, $obj->pa_ht);
2656
                $this->lines[$i]->pa_ht = $marginInfos[0];
2657
                $this->lines[$i]->marge_tx = $marginInfos[1];
2658
                $this->lines[$i]->marque_tx = $marginInfos[2];
2659
                $this->lines[$i]->fk_parent_line = $obj->fk_parent_line;
2660
                $this->lines[$i]->special_code = $obj->special_code;
2661
                $this->lines[$i]->rang = $obj->rang;
2662
2663
                $this->lines[$i]->ref_fourn = $obj->ref_supplier; // deprecated
2664
                $this->lines[$i]->ref_supplier = $obj->ref_supplier;
2665
2666
                // Multicurrency
2667
                $this->lines[$i]->fk_multicurrency = $obj->fk_multicurrency;
2668
                $this->lines[$i]->multicurrency_code = $obj->multicurrency_code;
2669
                $this->lines[$i]->multicurrency_subprice    = $obj->multicurrency_subprice;
2670
                $this->lines[$i]->multicurrency_total_ht    = $obj->multicurrency_total_ht;
2671
                $this->lines[$i]->multicurrency_total_tva   = $obj->multicurrency_total_tva;
2672
                $this->lines[$i]->multicurrency_total_ttc   = $obj->multicurrency_total_ttc;
2673
                $this->lines[$i]->fk_unit = $obj->fk_unit;
2674
2675
                $i++;
2676
            }
2677
            $this->db->free($resql);
2678
2679
            return 1;
2680
        } else {
2681
            $this->error = $this->db->error();
2682
            return -1;
2683
        }
2684
    }
2685
2686
    /**
2687
     *  Create a document onto disk according to template module.
2688
     *
2689
     *  @param      string      $modele         Force model to use ('' to not force)
2690
     *  @param      Translate   $outputlangs    Object langs to use for output
2691
     *  @param      int         $hidedetails    Hide details of lines
2692
     *  @param      int         $hidedesc       Hide description
2693
     *  @param      int         $hideref        Hide ref
2694
     *  @param   null|array  $moreparams     Array to provide more information
2695
     *  @return     int                         0 if KO, 1 if OK
2696
     */
2697
    public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
2698
    {
2699
        global $conf, $langs;
2700
2701
        $langs->load("supplier_proposal");
2702
        $outputlangs->load("products");
2703
2704
        if (!dol_strlen($modele)) {
2705
            $modele = 'aurore';
2706
2707
            if ($this->model_pdf) {
2708
                $modele = $this->model_pdf;
2709
            } elseif (getDolGlobalString('SUPPLIER_PROPOSAL_ADDON_PDF')) {
2710
                $modele = getDolGlobalString('SUPPLIER_PROPOSAL_ADDON_PDF');
2711
            }
2712
        }
2713
2714
        $modelpath = "core/modules/supplier_proposal/doc/";
2715
2716
        return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2717
    }
2718
2719
2720
    /**
2721
     * Function used to replace a thirdparty id with another one.
2722
     *
2723
     * @param   DoliDB  $dbs        Database handler, because function is static we name it $dbs not $db to avoid breaking coding test
2724
     * @param   int     $origin_id  Old thirdparty id
2725
     * @param   int     $dest_id    New thirdparty id
2726
     * @return  bool
2727
     */
2728
    public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
2729
    {
2730
        $tables = array(
2731
            'supplier_proposal'
2732
        );
2733
2734
        return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
2735
    }
2736
2737
    /**
2738
     * Function used to replace a product id with another one.
2739
     *
2740
     * @param DoliDB $db Database handler
2741
     * @param int $origin_id Old product id
2742
     * @param int $dest_id New product id
2743
     * @return bool
2744
     */
2745
    public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
2746
    {
2747
        $tables = array(
2748
            'supplier_proposaldet'
2749
        );
2750
2751
        return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
2752
    }
2753
2754
2755
    /**
2756
     *  Return clicable link of object (with eventually picto)
2757
     *
2758
     *  @param      string      $option                 Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link)
2759
     *  @param      array       $arraydata              Array of data
2760
     *  @return     string                              HTML Code for Kanban thumb.
2761
     */
2762
    public function getKanbanView($option = '', $arraydata = null)
2763
    {
2764
        global $langs;
2765
2766
        $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
2767
2768
        $return = '<div class="box-flex-item box-flex-grow-zero">';
2769
        $return .= '<div class="info-box info-box-sm">';
2770
        $return .= '<span class="info-box-icon bg-infobox-action">';
2771
        $return .= img_picto('', $this->picto);
2772
        //$return .= '<i class="fa fa-dol-action"></i>'; // Can be image
2773
        $return .= '</span>';
2774
        $return .= '<div class="info-box-content">';
2775
        $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . (method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref) . '</span>';
2776
        if ($selected >= 0) {
2777
            $return .= '<input id="cb' . $this->id . '" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="' . $this->id . '"' . ($selected ? ' checked="checked"' : '') . '>';
2778
        }
2779
        if (property_exists($this, 'socid')) {
2780
            $return .= '<span class="info-box-ref"> | ' . $this->socid . '</span>';
2781
        }
2782
        if (property_exists($this, 'delivery_date')) {
2783
            $return .= '<br><span class="opacitymedium">' . $langs->trans("DateEnd") . '</span> : <span class="info-box-label">' . dol_print_date($this->delivery_date) . '</span>';
2784
        }
2785
        if (property_exists($this, 'total_ttc')) {
2786
            $return .= '<br><span class="opacitymedium" >' . $langs->trans("AmountHT") . ' : </span><span class="info-box-label amount">' . price($this->total_ttc) . '</span>';
2787
        }
2788
        if (method_exists($this, 'getLibStatut')) {
2789
            $return .= '<br><div class="info-box-status">' . $this->getLibStatut(3) . '</div>';
2790
        }
2791
        $return .= '</div>';
2792
        $return .= '</div>';
2793
        $return .= '</div>';
2794
        return $return;
2795
    }
2796
}
2797