dolibarr  9.0.0
supplier_proposal.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2002-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
4  * Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net>
5  * Copyright (C) 2005 Marc Barilley <marc@ocebo.com>
6  * Copyright (C) 2005-2013 Regis Houssin <regis.houssin@inodbox.com>
7  * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
8  * Copyright (C) 2008 Raphael Bertrand <raphael.bertrand@resultic.fr>
9  * Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
10  * Copyright (C) 2010-2018 Philippe Grand <philippe.grand@atoo-net.com>
11  * Copyright (C) 2012-2014 Christophe Battarel <christophe.battarel@altairis.fr>
12  * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
13  * Copyright (C) 2014 Marcos García <marcosgdf@gmail.com>
14  * Copyright (C) 2016 Ferran Marcet <fmarcet@2byte.es>
15  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program. If not, see <http://www.gnu.org/licenses/>.
29  */
30 
36 require_once DOL_DOCUMENT_ROOT .'/fourn/class/fournisseur.product.class.php';
37 require_once DOL_DOCUMENT_ROOT .'/core/class/commonobject.class.php';
38 require_once DOL_DOCUMENT_ROOT .'/product/class/product.class.php';
39 require_once DOL_DOCUMENT_ROOT .'/contact/class/contact.class.php';
40 require_once DOL_DOCUMENT_ROOT .'/margin/lib/margins.lib.php';
41 require_once DOL_DOCUMENT_ROOT .'/multicurrency/class/multicurrency.class.php';
42 
47 {
51  public $element='supplier_proposal';
52 
56  public $table_element='supplier_proposal';
57 
61  public $table_element_line='supplier_proposaldet';
62 
66  public $fk_element='fk_supplier_proposal';
67 
68  public $picto='propal';
69 
74  public $ismultientitymanaged = 1;
75 
80  public $restrictiononfksoc = 1;
81 
85  protected $table_ref_field = 'ref';
86 
87  public $socid; // Id client
88 
93  public $author;
94 
95  public $ref_fourn; //Reference saisie lors de l'ajout d'une ligne à la demande
96  public $ref_supplier; //Reference saisie lors de l'ajout d'une ligne à la demande
97  public $statut; // 0 (draft), 1 (validated), 2 (signed), 3 (not signed), 4 (processed/billed)
98  public $date; // Date of proposal
99  public $date_livraison;
100 
105  public $datec;
106 
111  public $date_creation;
112 
117  public $datev;
118 
123  public $date_validation;
124 
125 
126  public $user_author_id;
127  public $user_valid_id;
128  public $user_close_id;
129 
134  public $price;
135 
140  public $tva;
141 
146  public $total;
147 
148  public $cond_reglement_code;
149  public $mode_reglement_code;
150  public $remise = 0;
151  public $remise_percent = 0;
152  public $remise_absolue = 0;
153 
154  public $products=array();
155  public $extraparams=array();
156 
157  public $lines = array();
158  public $line;
159 
160  public $labelstatut=array();
161  public $labelstatut_short=array();
162 
163  public $nbtodo;
164  public $nbtodolate;
165 
166  public $specimen;
167 
168  // Multicurrency
172  public $fk_multicurrency;
173 
174  public $multicurrency_code;
175  public $multicurrency_tx;
176  public $multicurrency_total_ht;
177  public $multicurrency_total_tva;
178  public $multicurrency_total_ttc;
179 
183  const STATUS_DRAFT = 0;
184 
188  const STATUS_VALIDATED = 1;
189 
193  const STATUS_SIGNED = 2;
194 
198  const STATUS_NOTSIGNED = 3;
199 
203  const STATUS_CLOSE = 4;
204 
205 
206 
214  function __construct($db, $socid="", $supplier_proposalid=0)
215  {
216  global $conf,$langs;
217 
218  $this->db = $db;
219 
220  $this->socid = $socid;
221  $this->id = $supplier_proposalid;
222 
223  $this->products = array();
224  }
225 
226 
227  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
240  function add_product($idproduct, $qty, $remise_percent=0)
241  {
242  // phpcs:enable
243  global $conf, $mysoc;
244 
245  if (! $qty) $qty = 1;
246 
247  dol_syslog(get_class($this)."::add_product $idproduct, $qty, $remise_percent");
248  if ($idproduct > 0)
249  {
250  $prod=new Product($this->db);
251  $prod->fetch($idproduct);
252 
253  $productdesc = $prod->description;
254 
255  $tva_tx = get_default_tva($mysoc,$this->thirdparty,$prod->id);
256  $tva_npr = get_default_npr($mysoc,$this->thirdparty,$prod->id);
257  if (empty($tva_tx)) $tva_npr=0;
258  $localtax1_tx = get_localtax($tva_tx,1,$mysoc,$this->thirdparty,$tva_npr);
259  $localtax2_tx = get_localtax($tva_tx,2,$mysoc,$this->thirdparty,$tva_npr);
260 
261  // multiprix
262  if($conf->global->PRODUIT_MULTIPRICES && $this->thirdparty->price_level)
263  {
264  $price = $prod->multiprices[$this->thirdparty->price_level];
265  }
266  else
267  {
268  $price = $prod->price;
269  }
270 
271  $line = new SupplierProposalLine($this->db);
272 
273  $line->fk_product=$idproduct;
274  $line->desc=$productdesc;
275  $line->qty=$qty;
276  $line->subprice=$price;
277  $line->remise_percent=$remise_percent;
278  $line->tva_tx=$tva_tx;
279 
280  $this->lines[]=$line;
281  }
282  }
283 
284  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
291  function insert_discount($idremise)
292  {
293  // phpcs:enable
294  global $langs;
295 
296  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
297  include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
298 
299  $this->db->begin();
300 
301  $remise=new DiscountAbsolute($this->db);
302  $result=$remise->fetch($idremise);
303 
304  if ($result > 0)
305  {
306  if ($remise->fk_facture) // Protection against multiple submission
307  {
308  $this->error=$langs->trans("ErrorDiscountAlreadyUsed");
309  $this->db->rollback();
310  return -5;
311  }
312 
313  $supplier_proposalligne=new SupplierProposalLine($this->db);
314  $supplier_proposalligne->fk_supplier_proposal=$this->id;
315  $supplier_proposalligne->fk_remise_except=$remise->id;
316  $supplier_proposalligne->desc=$remise->description; // Description ligne
317  $supplier_proposalligne->tva_tx=$remise->tva_tx;
318  $supplier_proposalligne->subprice=-$remise->amount_ht;
319  $supplier_proposalligne->fk_product=0; // Id produit predefini
320  $supplier_proposalligne->qty=1;
321  $supplier_proposalligne->remise=0;
322  $supplier_proposalligne->remise_percent=0;
323  $supplier_proposalligne->rang=-1;
324  $supplier_proposalligne->info_bits=2;
325 
326  // TODO deprecated
327  $supplier_proposalligne->price=-$remise->amount_ht;
328 
329  $supplier_proposalligne->total_ht = -$remise->amount_ht;
330  $supplier_proposalligne->total_tva = -$remise->amount_tva;
331  $supplier_proposalligne->total_ttc = -$remise->amount_ttc;
332 
333  $result=$supplier_proposalligne->insert();
334  if ($result > 0)
335  {
336  $result=$this->update_price(1);
337  if ($result > 0)
338  {
339  $this->db->commit();
340  return 1;
341  }
342  else
343  {
344  $this->db->rollback();
345  return -1;
346  }
347  }
348  else
349  {
350  $this->error=$supplier_proposalligne->error;
351  $this->db->rollback();
352  return -2;
353  }
354  }
355  else
356  {
357  $this->db->rollback();
358  return -2;
359  }
360  }
361 
397  function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $pu_ttc=0, $info_bits=0, $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=0, $pa_ht=0, $label='',$array_option=0, $ref_supplier='', $fk_unit='', $origin='', $origin_id=0, $pu_ht_devise=0)
398  {
399  global $mysoc, $conf;
400 
401  dol_syslog(get_class($this)."::addline supplier_proposalid=$this->id, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_except=$remise_percent, price_base_type=$price_base_type, pu_ttc=$pu_ttc, info_bits=$info_bits, type=$type");
402  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
403 
404  // Clean parameters
405  if (empty($remise_percent)) $remise_percent=0;
406  if (empty($qty)) $qty=0;
407  if (empty($info_bits)) $info_bits=0;
408  if (empty($rang)) $rang=0;
409  if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0;
410  if (empty($pu_ht)) $pu_ht=0;
411 
412  $remise_percent=price2num($remise_percent);
413  $qty=price2num($qty);
414  $pu_ht=price2num($pu_ht);
415  $pu_ttc=price2num($pu_ttc);
416  $txtva=price2num($txtva);
417  $txlocaltax1=price2num($txlocaltax1);
418  $txlocaltax2=price2num($txlocaltax2);
419  $pa_ht=price2num($pa_ht);
420  if ($price_base_type=='HT')
421  {
422  $pu=$pu_ht;
423  }
424  else
425  {
426  $pu=$pu_ttc;
427  }
428 
429  // Check parameters
430  if ($type < 0) return -1;
431 
432  if ($this->statut == self::STATUS_DRAFT)
433  {
434  $this->db->begin();
435 
436  if ($fk_product > 0)
437  {
438  if (! empty($conf->global->SUPPLIER_PROPOSAL_WITH_PREDEFINED_PRICES_ONLY))
439  {
440  // Check quantity is enough
441  dol_syslog(get_class($this)."::addline we check supplier prices fk_product=".$fk_product." fk_fournprice=".$fk_fournprice." qty=".$qty." ref_supplier=".$ref_supplier);
442  $prod = new Product($this->db, $fk_product);
443  if ($prod->fetch($fk_product) > 0)
444  {
445  $product_type = $prod->type;
446  $label = $prod->label;
447  $fk_prod_fourn_price = $fk_fournprice;
448 
449  // We use 'none' instead of $ref_supplier, because fourn_ref may not exists anymore. So we will take the first supplier price ok.
450  // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
451  $result=$prod->get_buyprice($fk_prod_fourn_price, $qty, $fk_product, 'none', ($this->fk_soc?$this->fk_soc:$this->socid)); // Search on couple $fk_prod_fourn_price/$qty first, then on triplet $qty/$fk_product/$ref_supplier/$this->fk_soc
452  if ($result > 0)
453  {
454  $pu = $prod->fourn_pu; // Unit price supplier price set by get_buyprice
455  $ref_supplier = $prod->ref_supplier; // Ref supplier price set by get_buyprice
456  // is remise percent not keyed but present for the product we add it
457  if ($remise_percent == 0 && $prod->remise_percent !=0)
458  $remise_percent =$prod->remise_percent;
459  }
460  if ($result == 0) // If result == 0, we failed to found the supplier reference price
461  {
462  $langs->load("errors");
463  $this->error = "Ref " . $prod->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier");
464  $this->db->rollback();
465  dol_syslog(get_class($this)."::addline we did not found supplier price, so we can't guess unit price");
466  //$pu = $prod->fourn_pu; // We do not overwrite unit price
467  //$ref = $prod->ref_fourn; // We do not overwrite ref supplier price
468  return -1;
469  }
470  if ($result == -1)
471  {
472  $langs->load("errors");
473  $this->error = "Ref " . $prod->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier");
474  $this->db->rollback();
475  dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_DEBUG);
476  return -1;
477  }
478  if ($result < -1)
479  {
480  $this->error=$prod->error;
481  $this->db->rollback();
482  dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_ERR);
483  return -1;
484  }
485  }
486  else
487  {
488  $this->error=$prod->error;
489  $this->db->rollback();
490  return -1;
491  }
492  }
493  }
494  else
495  {
496  $product_type = $type;
497  }
498 
499  // Calcul du total TTC et de la TVA pour la ligne a partir de
500  // qty, pu, remise_percent et txtva
501  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
502  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
503 
504  $localtaxes_type=getLocalTaxesFromRate($txtva,0,$this->thirdparty,$mysoc);
505  $txtva = preg_replace('/\s*\(.*\)/','',$txtva); // Remove code into vatrate.
506 
507  if ($conf->multicurrency->enabled && $pu_ht_devise > 0) {
508  $pu = 0;
509  }
510 
511  $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);
512  $total_ht = $tabprice[0];
513  $total_tva = $tabprice[1];
514  $total_ttc = $tabprice[2];
515  $total_localtax1 = $tabprice[9];
516  $total_localtax2 = $tabprice[10];
517  $pu = $pu_ht = $tabprice[3];
518 
519  // MultiCurrency
520  $multicurrency_total_ht = $tabprice[16];
521  $multicurrency_total_tva = $tabprice[17];
522  $multicurrency_total_ttc = $tabprice[18];
523  $pu_ht_devise = $tabprice[19];
524 
525  // Rang to use
526  $rangtouse = $rang;
527  if ($rangtouse == -1)
528  {
529  $rangmax = $this->line_max($fk_parent_line);
530  $rangtouse = $rangmax + 1;
531  }
532 
533  // TODO A virer
534  // Anciens indicateurs: $price, $remise (a ne plus utiliser)
535  $price = $pu;
536  $remise = 0;
537  if ($remise_percent > 0)
538  {
539  $remise = round(($pu * $remise_percent / 100), 2);
540  $price = $pu - $remise;
541  }
542 
543  // Insert line
544  $this->line=new SupplierProposalLine($this->db);
545 
546  $this->line->fk_supplier_proposal=$this->id;
547  $this->line->label=$label;
548  $this->line->desc=$desc;
549  $this->line->qty=$qty;
550  $this->line->tva_tx=$txtva;
551  $this->line->localtax1_tx=($total_localtax1?$localtaxes_type[1]:0);
552  $this->line->localtax2_tx=($total_localtax2?$localtaxes_type[3]:0);
553  $this->line->localtax1_type = $localtaxes_type[0];
554  $this->line->localtax2_type = $localtaxes_type[2];
555  $this->line->fk_product=$fk_product;
556  $this->line->remise_percent=$remise_percent;
557  $this->line->subprice=$pu_ht;
558  $this->line->rang=$rangtouse;
559  $this->line->info_bits=$info_bits;
560  $this->line->total_ht=$total_ht;
561  $this->line->total_tva=$total_tva;
562  $this->line->total_localtax1=$total_localtax1;
563  $this->line->total_localtax2=$total_localtax2;
564  $this->line->total_ttc=$total_ttc;
565  $this->line->product_type=$type;
566  $this->line->special_code=$special_code;
567  $this->line->fk_parent_line=$fk_parent_line;
568  $this->line->fk_unit=$fk_unit;
569  $this->line->origin=$origin;
570  $this->line->origin_id=$origin_id;
571  $this->line->ref_fourn = $this->db->escape($ref_supplier);
572 
573  // infos marge
574  if (!empty($fk_product) && empty($fk_fournprice) && empty($pa_ht)) {
575  // by external module, take lowest buying price
576  include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
577  $productFournisseur = new ProductFournisseur($this->db);
578  $productFournisseur->find_min_price_product_fournisseur($fk_product);
579  $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id;
580  } else {
581  $this->line->fk_fournprice = $fk_fournprice;
582  }
583  $this->line->pa_ht = $pa_ht;
584 
585  // Multicurrency
586  $this->line->fk_multicurrency = $this->fk_multicurrency;
587  $this->line->multicurrency_code = $this->multicurrency_code;
588  $this->line->multicurrency_subprice = $pu_ht_devise;
589  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
590  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
591  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
592 
593  // Mise en option de la ligne
594  if (empty($qty) && empty($special_code)) $this->line->special_code=3;
595 
596  // TODO deprecated
597  $this->line->price=$price;
598  $this->line->remise=$remise;
599 
600  if (is_array($array_option) && count($array_option)>0) {
601  $this->line->array_options=$array_option;
602  }
603 
604  $result=$this->line->insert();
605  if ($result > 0)
606  {
607  // Reorder if child line
608  if (! empty($fk_parent_line)) $this->line_order(true,'DESC');
609 
610  // Mise a jour informations denormalisees au niveau de la propale meme
611  $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.
612  if ($result > 0)
613  {
614  $this->db->commit();
615  return $this->line->rowid;
616  }
617  else
618  {
619  $this->error=$this->db->error();
620  $this->db->rollback();
621  return -1;
622  }
623  }
624  else
625  {
626  $this->error=$this->line->error;
627  $this->db->rollback();
628  return -2;
629  }
630  }
631  }
632 
633 
659  function updateline($rowid, $pu, $qty, $remise_percent, $txtva, $txlocaltax1=0, $txlocaltax2=0, $desc='', $price_base_type='HT', $info_bits=0, $special_code=0, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=0, $pa_ht=0, $label='', $type=0, $array_option=0, $ref_supplier='', $fk_unit='')
660  {
661  global $conf,$user,$langs, $mysoc;
662 
663  dol_syslog(get_class($this)."::updateLine $rowid, $pu, $qty, $remise_percent, $txtva, $desc, $price_base_type, $info_bits");
664  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
665 
666  // Clean parameters
667  $remise_percent=price2num($remise_percent);
668  $qty=price2num($qty);
669  $pu = price2num($pu);
670  $txtva = price2num($txtva);
671  $txlocaltax1=price2num($txlocaltax1);
672  $txlocaltax2=price2num($txlocaltax2);
673  $pa_ht=price2num($pa_ht);
674  if (empty($qty) && empty($special_code)) $special_code=3; // Set option tag
675  if (! empty($qty) && $special_code == 3) $special_code=0; // Remove option tag
676 
677  if ($this->statut == 0)
678  {
679  $this->db->begin();
680 
681  // Calcul du total TTC et de la TVA pour la ligne a partir de
682  // qty, pu, remise_percent et txtva
683  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
684  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
685 
686  $localtaxes_type=getLocalTaxesFromRate($txtva,0,$this->thirdparty,$mysoc);
687  $txtva = preg_replace('/\s*\(.*\)/','',$txtva); // Remove code into vatrate.
688 
689  $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);
690  $total_ht = $tabprice[0];
691  $total_tva = $tabprice[1];
692  $total_ttc = $tabprice[2];
693  $total_localtax1 = $tabprice[9];
694  $total_localtax2 = $tabprice[10];
695 
696  // MultiCurrency
697  $multicurrency_total_ht = $tabprice[16];
698  $multicurrency_total_tva = $tabprice[17];
699  $multicurrency_total_ttc = $tabprice[18];
700 
701  // Anciens indicateurs: $price, $remise (a ne plus utiliser)
702  $price = $pu;
703  if ($remise_percent > 0)
704  {
705  $remise = round(($pu * $remise_percent / 100), 2);
706  $price = $pu - $remise;
707  }
708 
709  // Update line
710  $this->line=new SupplierProposalLine($this->db);
711 
712  // Stock previous line records
713  $staticline=new SupplierProposalLine($this->db);
714  $staticline->fetch($rowid);
715  $this->line->oldline = $staticline;
716 
717  // Reorder if fk_parent_line change
718  if (! empty($fk_parent_line) && ! empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line)
719  {
720  $rangmax = $this->line_max($fk_parent_line);
721  $this->line->rang = $rangmax + 1;
722  }
723 
724  $this->line->rowid = $rowid;
725  $this->line->label = $label;
726  $this->line->desc = $desc;
727  $this->line->qty = $qty;
728  $this->line->product_type = $type;
729  $this->line->tva_tx = $txtva;
730  $this->line->localtax1_tx = $txlocaltax1;
731  $this->line->localtax2_tx = $txlocaltax2;
732  $this->line->localtax1_type = $localtaxes_type[0];
733  $this->line->localtax2_type = $localtaxes_type[2];
734  $this->line->remise_percent = $remise_percent;
735  $this->line->subprice = $pu;
736  $this->line->info_bits = $info_bits;
737  $this->line->total_ht = $total_ht;
738  $this->line->total_tva = $total_tva;
739  $this->line->total_localtax1 = $total_localtax1;
740  $this->line->total_localtax2 = $total_localtax2;
741  $this->line->total_ttc = $total_ttc;
742  $this->line->special_code = $special_code;
743  $this->line->fk_parent_line = $fk_parent_line;
744  $this->line->skip_update_total = $skip_update_total;
745  $this->line->ref_fourn = $ref_supplier;
746  $this->line->fk_unit = $fk_unit;
747 
748  // infos marge
749  if (!empty($fk_product) && empty($fk_fournprice) && empty($pa_ht)) {
750  // by external module, take lowest buying price
751  include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
752  $productFournisseur = new ProductFournisseur($this->db);
753  $productFournisseur->find_min_price_product_fournisseur($fk_product);
754  $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id;
755  } else {
756  $this->line->fk_fournprice = $fk_fournprice;
757  }
758  $this->line->pa_ht = $pa_ht;
759 
760  // TODO deprecated
761  $this->line->price=$price;
762  $this->line->remise=$remise;
763 
764  if (is_array($array_option) && count($array_option)>0) {
765  $this->line->array_options=$array_option;
766  }
767 
768  // Multicurrency
769  $this->line->multicurrency_subprice = price2num($pu * $this->multicurrency_tx);
770  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
771  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
772  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
773 
774  $result=$this->line->update();
775  if ($result > 0)
776  {
777  // Reorder if child line
778  if (! empty($fk_parent_line)) $this->line_order(true,'DESC');
779 
780  $this->update_price(1);
781 
782  $this->fk_supplier_proposal = $this->id;
783  $this->rowid = $rowid;
784 
785  $this->db->commit();
786  return $result;
787  }
788  else
789  {
790  $this->error=$this->db->error();
791  $this->db->rollback();
792  return -1;
793  }
794  }
795  else
796  {
797  dol_syslog(get_class($this)."::updateline Erreur -2 SupplierProposal en mode incompatible pour cette action");
798  return -2;
799  }
800  }
801 
802 
809  function deleteline($lineid)
810  {
811  if ($this->statut == 0)
812  {
813  $line=new SupplierProposalLine($this->db);
814 
815  // For triggers
816  $line->fetch($lineid);
817 
818  if ($line->delete() > 0)
819  {
820  $this->update_price(1);
821 
822  return 1;
823  }
824  else
825  {
826  return -1;
827  }
828  }
829  else
830  {
831  return -2;
832  }
833  }
834 
835 
844  function create($user, $notrigger=0)
845  {
846  global $langs, $conf, $mysoc, $hookmanager;
847  $error=0;
848 
849  $now=dol_now();
850 
851  dol_syslog(get_class($this)."::create");
852 
853  // Check parameters
854  $result=$this->fetch_thirdparty();
855  if ($result < 0)
856  {
857  $this->error="Failed to fetch company";
858  dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
859  return -3;
860  }
861 
862  // Check parameters
863  if (! empty($this->ref)) // We check that ref is not already used
864  {
865  $result=self::isExistingObject($this->element, 0, $this->ref); // Check ref is not yet used
866  if ($result > 0)
867  {
868  $this->error='ErrorRefAlreadyExists';
869  dol_syslog(get_class($this)."::create ".$this->error,LOG_WARNING);
870  $this->db->rollback();
871  return -1;
872  }
873  }
874 
875  // Multicurrency
876  if (!empty($this->multicurrency_code)) list($this->fk_multicurrency,$this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
877  if (empty($this->fk_multicurrency))
878  {
879  $this->multicurrency_code = $conf->currency;
880  $this->fk_multicurrency = 0;
881  $this->multicurrency_tx = 1;
882  }
883 
884  $this->db->begin();
885 
886  // Insert into database
887  $sql = "INSERT INTO ".MAIN_DB_PREFIX."supplier_proposal (";
888  $sql.= "fk_soc";
889  $sql.= ", price";
890  $sql.= ", remise";
891  $sql.= ", remise_percent";
892  $sql.= ", remise_absolue";
893  $sql.= ", tva";
894  $sql.= ", total";
895  $sql.= ", datec";
896  $sql.= ", ref";
897  $sql.= ", fk_user_author";
898  $sql.= ", note_private";
899  $sql.= ", note_public";
900  $sql.= ", model_pdf";
901  $sql.= ", fk_cond_reglement";
902  $sql.= ", fk_mode_reglement";
903  $sql.= ", fk_account";
904  $sql.= ", date_livraison";
905  $sql.= ", fk_shipping_method";
906  $sql.= ", fk_projet";
907  $sql.= ", entity";
908  $sql.= ", fk_multicurrency";
909  $sql.= ", multicurrency_code";
910  $sql.= ", multicurrency_tx";
911  $sql.= ") ";
912  $sql.= " VALUES (";
913  $sql.= $this->socid;
914  $sql.= ", 0";
915  $sql.= ", ".$this->remise;
916  $sql.= ", ".($this->remise_percent?$this->db->escape($this->remise_percent):'null');
917  $sql.= ", ".($this->remise_absolue?$this->db->escape($this->remise_absolue):'null');
918  $sql.= ", 0";
919  $sql.= ", 0";
920  $sql.= ", '".$this->db->idate($now)."'";
921  $sql.= ", '(PROV)'";
922  $sql.= ", ".($user->id > 0 ? "'".$user->id."'":"null");
923  $sql.= ", '".$this->db->escape($this->note_private)."'";
924  $sql.= ", '".$this->db->escape($this->note_public)."'";
925  $sql.= ", '".$this->db->escape($this->modelpdf)."'";
926  $sql.= ", ".($this->cond_reglement_id > 0 ? $this->cond_reglement_id : 'NULL');
927  $sql.= ", ".($this->mode_reglement_id > 0 ? $this->mode_reglement_id : 'NULL');
928  $sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL');
929  $sql.= ", ".($this->date_livraison!=''?"'".$this->db->idate($this->date_livraison)."'":"null");
930  $sql.= ", ".($this->shipping_method_id>0?$this->shipping_method_id:'NULL');
931  $sql.= ", ".($this->fk_project?$this->fk_project:"null");
932  $sql.= ", ".$conf->entity;
933  $sql.= ", ".(int) $this->fk_multicurrency;
934  $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
935  $sql.= ", ".(double) $this->multicurrency_tx;
936  $sql.= ")";
937 
938  dol_syslog(get_class($this)."::create", LOG_DEBUG);
939  $resql=$this->db->query($sql);
940  if ($resql)
941  {
942  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."supplier_proposal");
943 
944  if ($this->id)
945  {
946  $this->ref='(PROV'.$this->id.')';
947  $sql = 'UPDATE '.MAIN_DB_PREFIX."supplier_proposal SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".$this->id;
948 
949  dol_syslog(get_class($this)."::create", LOG_DEBUG);
950  $resql=$this->db->query($sql);
951  if (! $resql) $error++;
952 
953  if (! empty($this->linkedObjectsIds) && empty($this->linked_objects)) // To use new linkedObjectsIds instead of old linked_objects
954  {
955  $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
956  }
957 
958  // Add object linked
959  if (! $error && $this->id && is_array($this->linked_objects) && ! empty($this->linked_objects))
960  {
961  foreach($this->linked_objects as $origin => $tmp_origin_id)
962  {
963  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, ...))
964  {
965  foreach($tmp_origin_id as $origin_id)
966  {
967  $ret = $this->add_object_linked($origin, $origin_id);
968  if (! $ret)
969  {
970  dol_print_error($this->db);
971  $error++;
972  }
973  }
974  }
975  }
976  }
977 
978  // Add linked object (deprecated, use ->linkedObjectsIds instead)
979  if (! $error && $this->origin && $this->origin_id)
980  {
981  $ret = $this->add_object_linked();
982  if (! $ret) dol_print_error($this->db);
983  }
984 
985  /*
986  * Insertion du detail des produits dans la base
987  */
988  if (! $error)
989  {
990  $fk_parent_line=0;
991  $num=count($this->lines);
992 
993  for ($i=0;$i<$num;$i++)
994  {
995  // Reset fk_parent_line for no child products and special product
996  if (($this->lines[$i]->product_type != 9 && empty($this->lines[$i]->fk_parent_line)) || $this->lines[$i]->product_type == 9) {
997  $fk_parent_line = 0;
998  }
999 
1000  $result = $this->addline(
1001  $this->lines[$i]->desc,
1002  $this->lines[$i]->subprice,
1003  $this->lines[$i]->qty,
1004  $this->lines[$i]->tva_tx,
1005  $this->lines[$i]->localtax1_tx,
1006  $this->lines[$i]->localtax2_tx,
1007  $this->lines[$i]->fk_product,
1008  $this->lines[$i]->remise_percent,
1009  'HT',
1010  0,
1011  0,
1012  $this->lines[$i]->product_type,
1013  $this->lines[$i]->rang,
1014  $this->lines[$i]->special_code,
1015  $fk_parent_line,
1016  $this->lines[$i]->fk_fournprice,
1017  $this->lines[$i]->pa_ht,
1018  $this->lines[$i]->label,
1019  $this->lines[$i]->array_options,
1020  $this->lines[$i]->ref_fourn,
1021  $this->lines[$i]->fk_unit,
1022  'supplier_proposal',
1023  $this->lines[$i]->rowid
1024  );
1025 
1026  if ($result < 0)
1027  {
1028  $error++;
1029  $this->error=$this->db->error;
1030  dol_print_error($this->db);
1031  break;
1032  }
1033  // Defined the new fk_parent_line
1034  if ($result > 0 && $this->lines[$i]->product_type == 9) {
1035  $fk_parent_line = $result;
1036  }
1037  }
1038  }
1039 
1040  if (! $error)
1041  {
1042  // Mise a jour infos denormalisees
1043  $resql=$this->update_price(1);
1044  if ($resql)
1045  {
1046  $action='update';
1047 
1048  // Actions on extra fields
1049  if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))
1050  {
1051  $result=$this->insertExtraFields();
1052  if ($result < 0)
1053  {
1054  $error++;
1055  }
1056  }
1057 
1058  if (! $error && ! $notrigger)
1059  {
1060  // Call trigger
1061  $result=$this->call_trigger('PROPAL_SUPPLIER_CREATE',$user);
1062  if ($result < 0) { $error++; }
1063  // End call triggers
1064  }
1065  }
1066  else
1067  {
1068  $this->error=$this->db->lasterror();
1069  $error++;
1070  }
1071  }
1072  }
1073  else
1074  {
1075  $this->error=$this->db->lasterror();
1076  $error++;
1077  }
1078 
1079  if (! $error)
1080  {
1081  $this->db->commit();
1082  dol_syslog(get_class($this)."::create done id=".$this->id);
1083  return $this->id;
1084  }
1085  else
1086  {
1087  $this->db->rollback();
1088  return -2;
1089  }
1090  }
1091  else
1092  {
1093  $this->error=$this->db->lasterror();
1094  $this->db->rollback();
1095  return -1;
1096  }
1097  }
1098 
1099 
1100  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1108  function create_from($user)
1109  {
1110  // phpcs:enable
1111  $this->products=$this->lines;
1112 
1113  return $this->create($user);
1114  }
1115 
1122  function createFromClone($socid=0)
1123  {
1124  global $user,$langs,$conf,$hookmanager;
1125 
1126  $error=0;
1127  $now=dol_now();
1128 
1129  $this->db->begin();
1130 
1131  // get extrafields so they will be clone
1132  foreach($this->lines as $line)
1133  $line->fetch_optionals();
1134 
1135  // Load source object
1136  $objFrom = clone $this;
1137 
1138  $objsoc=new Societe($this->db);
1139 
1140  // Change socid if needed
1141  if (! empty($socid) && $socid != $this->socid)
1142  {
1143  if ($objsoc->fetch($socid) > 0)
1144  {
1145  $this->socid = $objsoc->id;
1146  $this->cond_reglement_id = (! empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
1147  $this->mode_reglement_id = (! empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
1148  $this->fk_project = '';
1149  }
1150 
1151  // TODO Change product price if multi-prices
1152  }
1153  else
1154  {
1155  $objsoc->fetch($this->socid);
1156  }
1157 
1158  $this->id=0;
1159  $this->statut=0;
1160 
1161  if (empty($conf->global->SUPPLIER_PROPOSAL_ADDON) || ! is_readable(DOL_DOCUMENT_ROOT ."/core/modules/supplier_proposal/".$conf->global->SUPPLIER_PROPOSAL_ADDON.".php"))
1162  {
1163  $this->error='ErrorSetupNotComplete';
1164  return -1;
1165  }
1166 
1167  // Clear fields
1168  $this->user_author = $user->id;
1169  $this->user_valid = '';
1170  $this->date = $now;
1171 
1172  // Set ref
1173  require_once DOL_DOCUMENT_ROOT ."/core/modules/supplier_proposal/".$conf->global->SUPPLIER_PROPOSAL_ADDON.'.php';
1174  $obj = $conf->global->SUPPLIER_PROPOSAL_ADDON;
1175  $modSupplierProposal = new $obj;
1176  $this->ref = $modSupplierProposal->getNextValue($objsoc,$this);
1177 
1178  // Create clone
1179  $this->context['createfromclone'] = 'createfromclone';
1180  $result=$this->create($user);
1181  if ($result < 0) $error++;
1182 
1183  if (! $error)
1184  {
1185  // Hook of thirdparty module
1186  if (is_object($hookmanager))
1187  {
1188  $parameters=array('objFrom'=>$objFrom);
1189  $action='';
1190  $reshook=$hookmanager->executeHooks('createFrom',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks
1191  if ($reshook < 0) $error++;
1192  }
1193  }
1194 
1195  unset($this->context['createfromclone']);
1196 
1197  // End
1198  if (! $error)
1199  {
1200  $this->db->commit();
1201  return $this->id;
1202  }
1203  else
1204  {
1205  $this->db->rollback();
1206  return -1;
1207  }
1208  }
1209 
1217  function fetch($rowid,$ref='')
1218  {
1219  global $conf;
1220 
1221  $sql = "SELECT p.rowid, p.entity, p.ref, p.remise, p.remise_percent, p.remise_absolue, p.fk_soc";
1222  $sql.= ", p.total, p.tva, p.localtax1, p.localtax2, p.total_ht";
1223  $sql.= ", p.datec";
1224  $sql.= ", p.date_valid as datev";
1225  $sql.= ", p.date_livraison as date_livraison";
1226  $sql.= ", p.model_pdf, p.extraparams";
1227  $sql.= ", p.note_private, p.note_public";
1228  $sql.= ", p.fk_projet, p.fk_statut";
1229  $sql.= ", p.fk_user_author, p.fk_user_valid, p.fk_user_cloture";
1230  $sql.= ", p.fk_cond_reglement";
1231  $sql.= ", p.fk_mode_reglement";
1232  $sql.= ', p.fk_account';
1233  $sql.= ", p.fk_shipping_method";
1234  $sql.= ", p.fk_multicurrency, p.multicurrency_code, p.multicurrency_tx, p.multicurrency_total_ht, p.multicurrency_total_tva, p.multicurrency_total_ttc";
1235  $sql.= ", c.label as statut_label";
1236  $sql.= ", cr.code as cond_reglement_code, cr.libelle as cond_reglement, cr.libelle_facture as cond_reglement_libelle_doc";
1237  $sql.= ", cp.code as mode_reglement_code, cp.libelle as mode_reglement";
1238  $sql.= " FROM ".MAIN_DB_PREFIX."c_propalst as c, ".MAIN_DB_PREFIX."supplier_proposal as p";
1239  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as cp ON p.fk_mode_reglement = cp.id';
1240  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON p.fk_cond_reglement = cr.rowid';
1241  $sql.= " WHERE p.fk_statut = c.id";
1242  $sql.= " AND p.entity IN (".getEntity('supplier_proposal').")";
1243  if ($ref) $sql.= " AND p.ref='".$ref."'";
1244  else $sql.= " AND p.rowid=".$rowid;
1245 
1246  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1247  $resql=$this->db->query($sql);
1248  if ($resql)
1249  {
1250  if ($this->db->num_rows($resql))
1251  {
1252  $obj = $this->db->fetch_object($resql);
1253 
1254  $this->id = $obj->rowid;
1255  $this->entity = $obj->entity;
1256 
1257  $this->ref = $obj->ref;
1258  $this->remise = $obj->remise;
1259  $this->remise_percent = $obj->remise_percent;
1260  $this->remise_absolue = $obj->remise_absolue;
1261  $this->total = $obj->total; // TODO deprecated
1262  $this->total_ht = $obj->total_ht;
1263  $this->total_tva = $obj->tva;
1264  $this->total_localtax1 = $obj->localtax1;
1265  $this->total_localtax2 = $obj->localtax2;
1266  $this->total_ttc = $obj->total;
1267  $this->socid = $obj->fk_soc;
1268  $this->fk_project = $obj->fk_projet;
1269  $this->modelpdf = $obj->model_pdf;
1270  $this->note = $obj->note_private; // TODO deprecated
1271  $this->note_private = $obj->note_private;
1272  $this->note_public = $obj->note_public;
1273  $this->statut = (int) $obj->fk_statut;
1274  $this->statut_libelle = $obj->statut_label;
1275  $this->datec = $this->db->jdate($obj->datec); // TODO deprecated
1276  $this->datev = $this->db->jdate($obj->datev); // TODO deprecated
1277  $this->date_creation = $this->db->jdate($obj->datec); //Creation date
1278  $this->date_validation = $this->db->jdate($obj->datev); //Validation date
1279  $this->date_livraison = $this->db->jdate($obj->date_livraison);
1280  $this->shipping_method_id = ($obj->fk_shipping_method>0)?$obj->fk_shipping_method:null;
1281 
1282  $this->mode_reglement_id = $obj->fk_mode_reglement;
1283  $this->mode_reglement_code = $obj->mode_reglement_code;
1284  $this->mode_reglement = $obj->mode_reglement;
1285  $this->fk_account = ($obj->fk_account>0)?$obj->fk_account:null;
1286  $this->cond_reglement_id = $obj->fk_cond_reglement;
1287  $this->cond_reglement_code = $obj->cond_reglement_code;
1288  $this->cond_reglement = $obj->cond_reglement;
1289  $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
1290 
1291  $this->extraparams = (array) json_decode($obj->extraparams, true);
1292 
1293  $this->user_author_id = $obj->fk_user_author;
1294  $this->user_valid_id = $obj->fk_user_valid;
1295  $this->user_close_id = $obj->fk_user_cloture;
1296 
1297  // Multicurrency
1298  $this->fk_multicurrency = $obj->fk_multicurrency;
1299  $this->multicurrency_code = $obj->multicurrency_code;
1300  $this->multicurrency_tx = $obj->multicurrency_tx;
1301  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
1302  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
1303  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
1304 
1305  if ($obj->fk_statut == 0)
1306  {
1307  $this->brouillon = 1;
1308  }
1309 
1310  // Retreive all extrafield
1311  // fetch optionals attributes and labels
1312  $this->fetch_optionals();
1313 
1314  $this->db->free($resql);
1315 
1316  $this->lines = array();
1317 
1318  // Lines of supplier proposals
1319  $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,";
1320  $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,";
1321  $sql.= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label,';
1322  $sql.= ' d.ref_fourn as ref_produit_fourn,';
1323  $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';
1324  $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposaldet as d";
1325  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON d.fk_product = p.rowid";
1326  $sql.= " WHERE d.fk_supplier_proposal = ".$this->id;
1327  $sql.= " ORDER by d.rang";
1328 
1329  $result = $this->db->query($sql);
1330  if ($result)
1331  {
1332  $num = $this->db->num_rows($result);
1333  $i = 0;
1334 
1335  while ($i < $num)
1336  {
1337  $objp = $this->db->fetch_object($result);
1338 
1339  $line = new SupplierProposalLine($this->db);
1340 
1341  $line->rowid = $objp->rowid; // deprecated
1342  $line->id = $objp->rowid;
1343  $line->fk_supplier_proposal = $objp->fk_supplier_proposal;
1344  $line->fk_parent_line = $objp->fk_parent_line;
1345  $line->product_type = $objp->product_type;
1346  $line->label = $objp->custom_label;
1347  $line->desc = $objp->description; // Description ligne
1348  $line->qty = $objp->qty;
1349  $line->tva_tx = $objp->tva_tx;
1350  $line->localtax1_tx = $objp->localtax1_tx;
1351  $line->localtax2_tx = $objp->localtax2_tx;
1352  $line->subprice = $objp->subprice;
1353  $line->fk_remise_except = $objp->fk_remise_except;
1354  $line->remise_percent = $objp->remise_percent;
1355  $line->price = $objp->price; // TODO deprecated
1356 
1357  $line->info_bits = $objp->info_bits;
1358  $line->total_ht = $objp->total_ht;
1359  $line->total_tva = $objp->total_tva;
1360  $line->total_localtax1 = $objp->total_localtax1;
1361  $line->total_localtax2 = $objp->total_localtax2;
1362  $line->total_ttc = $objp->total_ttc;
1363  $line->fk_fournprice = $objp->fk_fournprice;
1364  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
1365  $line->pa_ht = $marginInfos[0];
1366  $line->marge_tx = $marginInfos[1];
1367  $line->marque_tx = $marginInfos[2];
1368  $line->special_code = $objp->special_code;
1369  $line->rang = $objp->rang;
1370 
1371  $line->fk_product = $objp->fk_product;
1372 
1373  $line->ref = $objp->product_ref; // TODO deprecated
1374  $line->product_ref = $objp->product_ref;
1375  $line->libelle = $objp->product_label; // TODO deprecated
1376  $line->product_label = $objp->product_label;
1377  $line->product_desc = $objp->product_desc; // Description produit
1378  $line->fk_product_type = $objp->fk_product_type;
1379 
1380  $line->ref_fourn = $objp->ref_produit_fourn;
1381 
1382  // Multicurrency
1383  $line->fk_multicurrency = $objp->fk_multicurrency;
1384  $line->multicurrency_code = $objp->multicurrency_code;
1385  $line->multicurrency_subprice = $objp->multicurrency_subprice;
1386  $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
1387  $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
1388  $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
1389  $line->fk_unit = $objp->fk_unit;
1390 
1391  $this->lines[$i] = $line;
1392 
1393  $i++;
1394  }
1395  $this->db->free($result);
1396  }
1397  else
1398  {
1399  $this->error=$this->db->error();
1400  return -1;
1401  }
1402 
1403  // Retreive all extrafield
1404  // fetch optionals attributes and labels
1405  $this->fetch_optionals();
1406 
1407  return 1;
1408  }
1409 
1410  $this->error="Record Not Found";
1411  return 0;
1412  }
1413  else
1414  {
1415  $this->error=$this->db->error();
1416  return -1;
1417  }
1418  }
1419 
1427  function valid($user, $notrigger=0)
1428  {
1429  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1430 
1431  global $conf,$langs;
1432 
1433  $error=0;
1434  $now=dol_now();
1435 
1436  if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->supplier_proposal->creer))
1437  || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->supplier_proposal->validate_advance)))
1438  {
1439  $this->db->begin();
1440 
1441  // Numbering module definition
1442  $soc = new Societe($this->db);
1443  $soc->fetch($this->socid);
1444 
1445  // Define new ref
1446  if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life
1447  {
1448  $num = $this->getNextNumRef($soc);
1449  }
1450  else
1451  {
1452  $num = $this->ref;
1453  }
1454  $this->newref = $num;
1455 
1456  $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal";
1457  $sql.= " SET ref = '".$this->db->escape($num)."',";
1458  $sql.= " fk_statut = 1, date_valid='".$this->db->idate($now)."', fk_user_valid=".$user->id;
1459  $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
1460 
1461  dol_syslog(get_class($this)."::valid", LOG_DEBUG);
1462  $resql=$this->db->query($sql);
1463  if (! $resql)
1464  {
1465  dol_print_error($this->db);
1466  $error++;
1467  }
1468 
1469  // Trigger calls
1470  if (! $error && ! $notrigger)
1471  {
1472  // Call trigger
1473  $result=$this->call_trigger('SUPPLIER_PROPOSAL_VALIDATE',$user);
1474  if ($result < 0) { $error++; }
1475  // End call triggers
1476  }
1477 
1478  if (! $error)
1479  {
1480  $this->oldref = $this->ref;
1481 
1482  // Rename directory if dir was a temporary ref
1483  if (preg_match('/^[\(]?PROV/i', $this->ref))
1484  {
1485  // Rename of propal directory ($this->ref = old ref, $num = new ref)
1486  // to not lose the linked files
1487  $oldref = dol_sanitizeFileName($this->ref);
1488  $newref = dol_sanitizeFileName($num);
1489  $dirsource = $conf->supplier_proposal->dir_output.'/'.$oldref;
1490  $dirdest = $conf->supplier_proposal->dir_output.'/'.$newref;
1491 
1492  if (file_exists($dirsource))
1493  {
1494  dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest);
1495  if (@rename($dirsource, $dirdest))
1496  {
1497  dol_syslog("Rename ok");
1498  // Rename docs starting with $oldref with $newref
1499  $listoffiles=dol_dir_list($conf->supplier_proposal->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref,'/'));
1500  foreach($listoffiles as $fileentry)
1501  {
1502  $dirsource=$fileentry['name'];
1503  $dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource);
1504  $dirsource=$fileentry['path'].'/'.$dirsource;
1505  $dirdest=$fileentry['path'].'/'.$dirdest;
1506  @rename($dirsource, $dirdest);
1507  }
1508  }
1509  }
1510  }
1511 
1512  $this->ref=$num;
1513  $this->brouillon=0;
1514  $this->statut = 1;
1515  $this->user_valid_id=$user->id;
1516  $this->datev=$now;
1517 
1518  $this->db->commit();
1519  return 1;
1520  }
1521  else
1522  {
1523  $this->db->rollback();
1524  return -1;
1525  }
1526  }
1527  else
1528  {
1529  dol_syslog("You don't have permission to validate supplier proposal", LOG_WARNING);
1530  return -2;
1531  }
1532  }
1533 
1534  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1542  function set_date_livraison($user, $date_livraison)
1543  {
1544  // phpcs:enable
1545  if (! empty($user->rights->supplier_proposal->creer))
1546  {
1547  $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal ";
1548  $sql.= " SET date_livraison = ".($date_livraison!=''?"'".$this->db->idate($date_livraison)."'":'null');
1549  $sql.= " WHERE rowid = ".$this->id;
1550 
1551  if ($this->db->query($sql))
1552  {
1553  $this->date_livraison = $date_livraison;
1554  return 1;
1555  }
1556  else
1557  {
1558  $this->error=$this->db->error();
1559  dol_syslog(get_class($this)."::set_date_livraison Erreur SQL");
1560  return -1;
1561  }
1562  }
1563  }
1564 
1565  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1573  function set_remise_percent($user, $remise)
1574  {
1575  // phpcs:enable
1576  $remise=trim($remise)?trim($remise):0;
1577 
1578  if (! empty($user->rights->supplier_proposal->creer))
1579  {
1580  $remise = price2num($remise);
1581 
1582  $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal SET remise_percent = ".$remise;
1583  $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
1584 
1585  if ($this->db->query($sql) )
1586  {
1587  $this->remise_percent = $remise;
1588  $this->update_price(1);
1589  return 1;
1590  }
1591  else
1592  {
1593  $this->error=$this->db->error();
1594  return -1;
1595  }
1596  }
1597  }
1598 
1599 
1600  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1608  function set_remise_absolue($user, $remise)
1609  {
1610  // phpcs:enable
1611  $remise=trim($remise)?trim($remise):0;
1612 
1613  if (! empty($user->rights->supplier_proposal->creer))
1614  {
1615  $remise = price2num($remise);
1616 
1617  $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal ";
1618  $sql.= " SET remise_absolue = ".$remise;
1619  $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
1620 
1621  if ($this->db->query($sql) )
1622  {
1623  $this->remise_absolue = $remise;
1624  $this->update_price(1);
1625  return 1;
1626  }
1627  else
1628  {
1629  $this->error=$this->db->error();
1630  return -1;
1631  }
1632  }
1633  }
1634 
1635 
1636 
1646  function reopen($user, $statut, $note='', $notrigger=0)
1647  {
1648  global $langs,$conf;
1649 
1650  $this->statut = $statut;
1651  $error=0;
1652 
1653  $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal";
1654  $sql.= " SET fk_statut = ".$this->statut.",";
1655  if (! empty($note)) $sql.= " note_private = '".$this->db->escape($note)."',";
1656  $sql.= " date_cloture=NULL, fk_user_cloture=NULL";
1657  $sql.= " WHERE rowid = ".$this->id;
1658 
1659  $this->db->begin();
1660 
1661  dol_syslog(get_class($this)."::reopen", LOG_DEBUG);
1662  $resql = $this->db->query($sql);
1663  if (! $resql) {
1664  $error++; $this->errors[]="Error ".$this->db->lasterror();
1665  }
1666  if (! $error)
1667  {
1668  if (! $notrigger)
1669  {
1670  // Call trigger
1671  $result=$this->call_trigger('SUPPLIER_PROPOSAL_REOPEN',$user);
1672  if ($result < 0) { $error++; }
1673  // End call triggers
1674  }
1675  }
1676 
1677  // Commit or rollback
1678  if ($error)
1679  {
1680  if (!empty($this->errors))
1681  {
1682  foreach($this->errors as $errmsg)
1683  {
1684  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
1685  $this->error.=($this->error?', '.$errmsg:$errmsg);
1686  }
1687  }
1688  $this->db->rollback();
1689  return -1*$error;
1690  }
1691  else
1692  {
1693  $this->db->commit();
1694  return 1;
1695  }
1696  }
1697 
1698 
1707  function cloture($user, $statut, $note)
1708  {
1709  global $langs,$conf;
1710 
1711  $this->statut = $statut;
1712  $error=0;
1713  $now=dol_now();
1714 
1715  $this->db->begin();
1716 
1717  $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal";
1718  $sql.= " SET fk_statut = ".$statut.", note_private = '".$this->db->escape($note)."', date_cloture='".$this->db->idate($now)."', fk_user_cloture=".$user->id;
1719  $sql.= " WHERE rowid = ".$this->id;
1720 
1721  $resql=$this->db->query($sql);
1722  if ($resql)
1723  {
1724  $modelpdf=$conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_CLOSED?$conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_CLOSED:$this->modelpdf;
1725  $trigger_name='SUPPLIER_PROPOSAL_CLOSE_REFUSED';
1726 
1727  if ($statut == 2)
1728  {
1729  $trigger_name='SUPPLIER_PROPOSAL_CLOSE_SIGNED';
1730  $modelpdf=$conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_TOBILL?$conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_TOBILL:$this->modelpdf;
1731 
1732  if (! empty($conf->global->SUPPLIER_PROPOSAL_UPDATE_PRICE_ON_SUPPlIER_PROPOSAL)) // TODO This option was not tested correctly. Error if product ref does not exists
1733  {
1734  $result = $this->updateOrCreatePriceFournisseur($user);
1735  }
1736  }
1737  if ($statut == 4)
1738  {
1739  $trigger_name='SUPPLIER_PROPOSAL_CLASSIFY_BILLED';
1740  }
1741 
1742  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
1743  {
1744  // Define output language
1745  $outputlangs = $langs;
1746  if (! empty($conf->global->MAIN_MULTILANGS))
1747  {
1748  $outputlangs = new Translate("",$conf);
1749  $newlang=(GETPOST('lang_id','aZ09') ? GETPOST('lang_id','aZ09') : $this->thirdparty->default_lang);
1750  $outputlangs->setDefaultLang($newlang);
1751  }
1752  //$ret=$object->fetch($id); // Reload to get new records
1753  $this->generateDocument($modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1754  }
1755 
1756  // Call trigger
1757  $result=$this->call_trigger($trigger_name,$user);
1758  if ($result < 0) { $error++; }
1759  // End call triggers
1760 
1761  if ( ! $error )
1762  {
1763  $this->db->commit();
1764  return 1;
1765  }
1766  else
1767  {
1768  $this->db->rollback();
1769  return -1;
1770  }
1771  }
1772  else
1773  {
1774  $this->error=$this->db->lasterror();
1775  $this->errors[]=$this->db->lasterror();
1776  $this->db->rollback();
1777  return -1;
1778  }
1779  }
1780 
1788  {
1789  $productsupplier = new ProductFournisseur($this->db);
1790 
1791  dol_syslog(get_class($this)."::updateOrCreatePriceFournisseur", LOG_DEBUG);
1792  foreach ($this->lines as $product)
1793  {
1794  if ($product->subprice <= 0) continue;
1795 
1796  $idProductFourn = $productsupplier->find_min_price_product_fournisseur($product->fk_product, $product->qty);
1797  $res = $productsupplier->fetch($idProductFourn);
1798 
1799  if ($productsupplier->id) {
1800  if ($productsupplier->fourn_qty == $product->qty) {
1801  $this->updatePriceFournisseur($productsupplier->product_fourn_price_id, $product, $user);
1802  } else {
1803  $this->createPriceFournisseur($product, $user);
1804  }
1805  } else {
1806  $this->createPriceFournisseur($product, $user);
1807  }
1808  }
1809 
1810  return 1;
1811  }
1812 
1821  function updatePriceFournisseur($idProductFournPrice, $product, $user)
1822  {
1823  $price=price2num($product->subprice*$product->qty,'MU');
1824  $unitPrice = price2num($product->subprice,'MU');
1825 
1826  $sql = 'UPDATE '.MAIN_DB_PREFIX.'product_fournisseur_price SET '.(!empty($product->ref_fourn) ? 'ref_fourn = "'.$product->ref_fourn.'", ' : '').' price ='.$price.', unitprice ='.$unitPrice.' WHERE rowid = '.$idProductFournPrice;
1827 
1828  $resql = $this->db->query($sql);
1829  if (!$resql) {
1830  $this->error=$this->db->error();
1831  $this->db->rollback();
1832  return -1;
1833  }
1834  }
1835 
1843  function createPriceFournisseur($product, $user)
1844  {
1845  $price=price2num($product->subprice*$product->qty,'MU');
1846  $qty=price2num($product->qty);
1847  $unitPrice = price2num($product->subprice,'MU');
1848  $now=dol_now();
1849 
1850  $values = array(
1851  "'".$this->db->idate($now)."'",
1852  $product->fk_product,
1853  $this->thirdparty->id,
1854  "'".$product->ref_fourn."'",
1855  $price,
1856  $qty,
1857  $unitPrice,
1858  $product->tva_tx,
1859  $user->id
1860  );
1861 
1862  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'product_fournisseur_price ';
1863  $sql .= '(datec, fk_product, fk_soc, ref_fourn, price, quantity, unitprice, tva_tx, fk_user) VALUES ('.implode(',', $values).')';
1864 
1865  $resql = $this->db->query($sql);
1866  if (!$resql) {
1867  $this->error=$this->db->error();
1868  $this->db->rollback();
1869  return -1;
1870  }
1871  }
1872 
1873  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1880  function set_draft($user)
1881  {
1882  // phpcs:enable
1883  global $conf,$langs;
1884 
1885  $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal SET fk_statut = 0";
1886  $sql.= " WHERE rowid = ".$this->id;
1887 
1888  if ($this->db->query($sql))
1889  {
1890  $this->statut = 0;
1891  $this->brouillon = 1;
1892  return 1;
1893  }
1894  else
1895  {
1896  return -1;
1897  }
1898  }
1899 
1900 
1901  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1915  function liste_array($shortlist=0, $draft=0, $notcurrentuser=0, $socid=0, $limit=0, $offset=0, $sortfield='p.datec', $sortorder='DESC')
1916  {
1917  // phpcs:enable
1918  global $conf,$user;
1919 
1920  $ga = array();
1921 
1922  $sql = "SELECT s.rowid, s.nom as name, s.client,";
1923  $sql.= " p.rowid as supplier_proposalid, p.fk_statut, p.total_ht, p.ref, p.remise, ";
1924  $sql.= " p.datep as dp, p.fin_validite as datelimite";
1925  if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", sc.fk_soc, sc.fk_user";
1926  $sql.= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."supplier_proposal as p, ".MAIN_DB_PREFIX."c_propalst as c";
1927  if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
1928  $sql.= " WHERE p.entity IN (".getEntity('supplier_proposal').")";
1929  $sql.= " AND p.fk_soc = s.rowid";
1930  $sql.= " AND p.fk_statut = c.id";
1931  if (! $user->rights->societe->client->voir && ! $socid) //restriction
1932  {
1933  $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id;
1934  }
1935  if ($socid) $sql.= " AND s.rowid = ".$socid;
1936  if ($draft) $sql.= " AND p.fk_statut = 0";
1937  if ($notcurrentuser > 0) $sql.= " AND p.fk_user_author <> ".$user->id;
1938  $sql.= $this->db->order($sortfield,$sortorder);
1939  $sql.= $this->db->plimit($limit,$offset);
1940 
1941  $result=$this->db->query($sql);
1942  if ($result)
1943  {
1944  $num = $this->db->num_rows($result);
1945  if ($num)
1946  {
1947  $i = 0;
1948  while ($i < $num)
1949  {
1950  $obj = $this->db->fetch_object($result);
1951 
1952  if ($shortlist == 1)
1953  {
1954  $ga[$obj->supplier_proposalid] = $obj->ref;
1955  }
1956  else if ($shortlist == 2)
1957  {
1958  $ga[$obj->supplier_proposalid] = $obj->ref.' ('.$obj->name.')';
1959  }
1960  else
1961  {
1962  $ga[$i]['id'] = $obj->supplier_proposalid;
1963  $ga[$i]['ref'] = $obj->ref;
1964  $ga[$i]['name'] = $obj->name;
1965  }
1966 
1967  $i++;
1968  }
1969  }
1970  return $ga;
1971  }
1972  else
1973  {
1974  dol_print_error($this->db);
1975  return -1;
1976  }
1977  }
1978 
1986  function delete($user, $notrigger=0)
1987  {
1988  global $conf,$langs;
1989  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1990 
1991  $error=0;
1992 
1993  $this->db->begin();
1994 
1995  if (! $notrigger)
1996  {
1997  // Call trigger
1998  $result=$this->call_trigger('SUPPLIER_PROPOSAL_DELETE',$user);
1999  if ($result < 0) { $error++; }
2000  // End call triggers
2001  }
2002 
2003  if (! $error)
2004  {
2005  $sql = "DELETE FROM ".MAIN_DB_PREFIX."supplier_proposaldet WHERE fk_supplier_proposal = ".$this->id;
2006  if ($this->db->query($sql))
2007  {
2008  $sql = "DELETE FROM ".MAIN_DB_PREFIX."supplier_proposal WHERE rowid = ".$this->id;
2009  if ($this->db->query($sql))
2010  {
2011  // Delete linked object
2012  $res = $this->deleteObjectLinked();
2013  if ($res < 0) $error++;
2014 
2015  if (! $error)
2016  {
2017  // We remove directory
2018  $ref = dol_sanitizeFileName($this->ref);
2019  if ($conf->supplier_proposal->dir_output && !empty($this->ref))
2020  {
2021  $dir = $conf->supplier_proposal->dir_output . "/" . $ref ;
2022  $file = $dir . "/" . $ref . ".pdf";
2023  if (file_exists($file))
2024  {
2025  dol_delete_preview($this);
2026 
2027  if (! dol_delete_file($file,0,0,0,$this)) // For triggers
2028  {
2029  $this->error='ErrorFailToDeleteFile';
2030  $this->errors=array('ErrorFailToDeleteFile');
2031  $this->db->rollback();
2032  return 0;
2033  }
2034  }
2035  if (file_exists($dir))
2036  {
2037  $res=@dol_delete_dir_recursive($dir);
2038  if (! $res)
2039  {
2040  $this->error='ErrorFailToDeleteDir';
2041  $this->errors=array('ErrorFailToDeleteDir');
2042  $this->db->rollback();
2043  return 0;
2044  }
2045  }
2046  }
2047  }
2048 
2049  // Removed extrafields
2050  if (! $error)
2051  {
2052  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
2053  {
2054  $result=$this->deleteExtraFields();
2055  if ($result < 0)
2056  {
2057  $error++;
2058  $errorflag=-4;
2059  dol_syslog(get_class($this)."::delete erreur ".$errorflag." ".$this->error, LOG_ERR);
2060  }
2061  }
2062  }
2063 
2064  if (! $error)
2065  {
2066  dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
2067  $this->db->commit();
2068  return 1;
2069  }
2070  else
2071  {
2072  $this->error=$this->db->lasterror();
2073  $this->db->rollback();
2074  return 0;
2075  }
2076  }
2077  else
2078  {
2079  $this->error=$this->db->lasterror();
2080  $this->db->rollback();
2081  return -3;
2082  }
2083  }
2084  else
2085  {
2086  $this->error=$this->db->lasterror();
2087  $this->db->rollback();
2088  return -2;
2089  }
2090  }
2091  else
2092  {
2093  $this->db->rollback();
2094  return -1;
2095  }
2096  }
2097 
2104  function info($id)
2105  {
2106  $sql = "SELECT c.rowid, ";
2107  $sql.= " c.datec, c.date_valid as datev, c.date_cloture as dateo,";
2108  $sql.= " c.fk_user_author, c.fk_user_valid, c.fk_user_cloture";
2109  $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposal as c";
2110  $sql.= " WHERE c.rowid = ".$id;
2111 
2112  $result = $this->db->query($sql);
2113 
2114  if ($result)
2115  {
2116  if ($this->db->num_rows($result))
2117  {
2118  $obj = $this->db->fetch_object($result);
2119 
2120  $this->id = $obj->rowid;
2121 
2122  $this->date_creation = $this->db->jdate($obj->datec);
2123  $this->date_validation = $this->db->jdate($obj->datev);
2124  $this->date_cloture = $this->db->jdate($obj->dateo);
2125 
2126  $cuser = new User($this->db);
2127  $cuser->fetch($obj->fk_user_author);
2128  $this->user_creation = $cuser;
2129 
2130  if ($obj->fk_user_valid)
2131  {
2132  $vuser = new User($this->db);
2133  $vuser->fetch($obj->fk_user_valid);
2134  $this->user_validation = $vuser;
2135  }
2136 
2137  if ($obj->fk_user_cloture)
2138  {
2139  $cluser = new User($this->db);
2140  $cluser->fetch($obj->fk_user_cloture);
2141  $this->user_cloture = $cluser;
2142  }
2143  }
2144  $this->db->free($result);
2145  }
2146  else
2147  {
2148  dol_print_error($this->db);
2149  }
2150  }
2151 
2152 
2159  function getLibStatut($mode=0)
2160  {
2161  return $this->LibStatut($this->statut,$mode);
2162  }
2163 
2164  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2172  function LibStatut($statut,$mode=1)
2173  {
2174  // phpcs:enable
2175  // Init/load array of translation of status
2176  if (empty($this->labelstatut) || empty($this->labelstatut_short))
2177  {
2178  global $langs;
2179  $langs->load("supplier_proposal");
2180  $this->labelstatut[0]=$langs->trans("SupplierProposalStatusDraft");
2181  $this->labelstatut[1]=$langs->trans("SupplierProposalStatusValidated");
2182  $this->labelstatut[2]=$langs->trans("SupplierProposalStatusSigned");
2183  $this->labelstatut[3]=$langs->trans("SupplierProposalStatusNotSigned");
2184  $this->labelstatut[4]=$langs->trans("SupplierProposalStatusClosed");
2185  $this->labelstatut_short[0]=$langs->trans("SupplierProposalStatusDraftShort");
2186  $this->labelstatut_short[1]=$langs->trans("Opened");
2187  $this->labelstatut_short[2]=$langs->trans("SupplierProposalStatusSignedShort");
2188  $this->labelstatut_short[3]=$langs->trans("SupplierProposalStatusNotSignedShort");
2189  $this->labelstatut_short[4]=$langs->trans("SupplierProposalStatusClosedShort");
2190  }
2191 
2192  $statuttrans='';
2193  if ($statut==0) $statuttrans='statut0';
2194  elseif ($statut==1) $statuttrans='statut1';
2195  elseif ($statut==2) $statuttrans='statut3';
2196  elseif ($statut==3) $statuttrans='statut5';
2197  elseif ($statut==4) $statuttrans='statut6';
2198 
2199  if ($mode == 0) return $this->labelstatut[$statut];
2200  elseif ($mode == 1) return $this->labelstatut_short[$statut];
2201  elseif ($mode == 2) return img_picto($this->labelstatut[$statut], $statuttrans).' '.$this->labelstatut_short[$statut];
2202  elseif ($mode == 3) return img_picto($this->labelstatut[$statut], $statuttrans);
2203  elseif ($mode == 4) return img_picto($this->labelstatut[$statut],$statuttrans).' '.$this->labelstatut[$statut];
2204  elseif ($mode == 5) return '<span class="hideonsmartphone">'.$this->labelstatut_short[$statut].' </span>'.img_picto($this->labelstatut[$statut],$statuttrans);
2205  elseif ($mode == 6) return '<span class="hideonsmartphone">'.$this->labelstatut[$statut].' </span>'.img_picto($this->labelstatut[$statut],$statuttrans);
2206  }
2207 
2208 
2209  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2217  function load_board($user,$mode)
2218  {
2219  // phpcs:enable
2220  global $conf, $user, $langs;
2221 
2222  $now=dol_now();
2223 
2224  $this->nbtodo=$this->nbtodolate=0;
2225  $clause = " WHERE";
2226 
2227  $sql = "SELECT p.rowid, p.ref, p.datec as datec";
2228  $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposal as p";
2229  if (!$user->rights->societe->client->voir && !$user->socid)
2230  {
2231  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc";
2232  $sql.= " WHERE sc.fk_user = " .$user->id;
2233  $clause = " AND";
2234  }
2235  $sql.= $clause." p.entity IN (".getEntity('supplier_proposal').")";
2236  if ($mode == 'opened') $sql.= " AND p.fk_statut = 1";
2237  if ($mode == 'signed') $sql.= " AND p.fk_statut = 2";
2238  if ($user->socid) $sql.= " AND p.fk_soc = ".$user->socid;
2239 
2240  $resql=$this->db->query($sql);
2241  if ($resql)
2242  {
2243  if ($mode == 'opened') {
2244  $delay_warning=$conf->supplier_proposal->cloture->warning_delay;
2245  $statut = self::STATUS_VALIDATED;
2246  $label = $langs->trans("SupplierProposalsToClose");
2247  }
2248  if ($mode == 'signed') {
2249  $delay_warning=$conf->supplier_proposal->facturation->warning_delay;
2250  $statut = self::STATUS_SIGNED;
2251  $label = $langs->trans("SupplierProposalsToProcess"); // May be billed or ordered
2252  }
2253 
2254  $response = new WorkboardResponse();
2255  $response->warning_delay = $delay_warning/60/60/24;
2256  $response->label = $label;
2257  $response->url = DOL_URL_ROOT.'/supplier_proposal/list.php?viewstatut='.$statut;
2258  $response->img = img_object('',"propal");
2259 
2260  // This assignment in condition is not a bug. It allows walking the results.
2261  while ($obj=$this->db->fetch_object($resql))
2262  {
2263  $response->nbtodo++;
2264  if ($mode == 'opened')
2265  {
2266  $datelimit = $this->db->jdate($obj->datefin);
2267  if ($datelimit < ($now - $delay_warning))
2268  {
2269  $response->nbtodolate++;
2270  }
2271  }
2272  // TODO Definir regle des propales a facturer en retard
2273  // if ($mode == 'signed' && ! count($this->FactureListeArray($obj->rowid))) $this->nbtodolate++;
2274  }
2275  return $response;
2276  }
2277  else
2278  {
2279  $this->error=$this->db->lasterror();
2280  return -1;
2281  }
2282  }
2283 
2284 
2292  function initAsSpecimen()
2293  {
2294  global $user,$langs,$conf;
2295 
2296  // Load array of products prodids
2297  $num_prods = 0;
2298  $prodids = array();
2299  $sql = "SELECT rowid";
2300  $sql.= " FROM ".MAIN_DB_PREFIX."product";
2301  $sql.= " WHERE entity IN (".getEntity('product').")";
2302  $resql = $this->db->query($sql);
2303  if ($resql)
2304  {
2305  $num_prods = $this->db->num_rows($resql);
2306  $i = 0;
2307  while ($i < $num_prods)
2308  {
2309  $i++;
2310  $row = $this->db->fetch_row($resql);
2311  $prodids[$i] = $row[0];
2312  }
2313  }
2314 
2315  // Initialise parametres
2316  $this->id=0;
2317  $this->ref = 'SPECIMEN';
2318  $this->specimen=1;
2319  $this->socid = 1;
2320  $this->date = time();
2321  $this->cond_reglement_id = 1;
2322  $this->cond_reglement_code = 'RECEP';
2323  $this->mode_reglement_id = 7;
2324  $this->mode_reglement_code = 'CHQ';
2325  $this->note_public='This is a comment (public)';
2326  $this->note_private='This is a comment (private)';
2327  // Lines
2328  $nbp = 5;
2329  $xnbp = 0;
2330  while ($xnbp < $nbp)
2331  {
2332  $line=new SupplierProposalLine($this->db);
2333  $line->desc=$langs->trans("Description")." ".$xnbp;
2334  $line->qty=1;
2335  $line->subprice=100;
2336  $line->price=100;
2337  $line->tva_tx=19.6;
2338  $line->localtax1_tx=0;
2339  $line->localtax2_tx=0;
2340  if ($xnbp == 2)
2341  {
2342  $line->total_ht=50;
2343  $line->total_ttc=59.8;
2344  $line->total_tva=9.8;
2345  $line->remise_percent=50;
2346  }
2347  else
2348  {
2349  $line->total_ht=100;
2350  $line->total_ttc=119.6;
2351  $line->total_tva=19.6;
2352  $line->remise_percent=00;
2353  }
2354 
2355  if ($num_prods > 0)
2356  {
2357  $prodid = mt_rand(1, $num_prods);
2358  $line->fk_product=$prodids[$prodid];
2359  }
2360 
2361  $this->lines[$xnbp]=$line;
2362 
2363  $this->total_ht += $line->total_ht;
2364  $this->total_tva += $line->total_tva;
2365  $this->total_ttc += $line->total_ttc;
2366 
2367  $xnbp++;
2368  }
2369  }
2370 
2371  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2377  function load_state_board()
2378  {
2379  // phpcs:enable
2380  global $conf, $user;
2381 
2382  $this->nb=array();
2383  $clause = "WHERE";
2384 
2385  $sql = "SELECT count(p.rowid) as nb";
2386  $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposal as p";
2387  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
2388  if (!$user->rights->societe->client->voir && !$user->socid)
2389  {
2390  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
2391  $sql.= " WHERE sc.fk_user = " .$user->id;
2392  $clause = "AND";
2393  }
2394  $sql.= " ".$clause." p.entity IN (".getEntity('supplier_proposal').")";
2395 
2396  $resql=$this->db->query($sql);
2397  if ($resql)
2398  {
2399  // This assignment in condition is not a bug. It allows walking the results.
2400  while ($obj=$this->db->fetch_object($resql))
2401  {
2402  $this->nb["askprice"]=$obj->nb;
2403  }
2404  $this->db->free($resql);
2405  return 1;
2406  }
2407  else
2408  {
2409  dol_print_error($this->db);
2410  $this->error=$this->db->lasterror();
2411  return -1;
2412  }
2413  }
2414 
2415 
2423  function getNextNumRef($soc)
2424  {
2425  global $conf, $db, $langs;
2426  $langs->load("supplier_proposal");
2427 
2428  if (! empty($conf->global->SUPPLIER_PROPOSAL_ADDON))
2429  {
2430  $mybool=false;
2431 
2432  $file = $conf->global->SUPPLIER_PROPOSAL_ADDON.".php";
2433  $classname = $conf->global->SUPPLIER_PROPOSAL_ADDON;
2434 
2435  // Include file with class
2436  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2437  foreach ($dirmodels as $reldir) {
2438 
2439  $dir = dol_buildpath($reldir."core/modules/supplier_proposal/");
2440 
2441  // Load file with numbering class (if found)
2442  $mybool|=@include_once $dir.$file;
2443  }
2444 
2445  if (! $mybool)
2446  {
2447  dol_print_error('',"Failed to include file ".$file);
2448  return '';
2449  }
2450 
2451  $obj = new $classname();
2452  $numref = "";
2453  $numref = $obj->getNextValue($soc,$this);
2454 
2455  if ($numref != "")
2456  {
2457  return $numref;
2458  }
2459  else
2460  {
2461  $this->error=$obj->error;
2462  return "";
2463  }
2464  }
2465  else
2466  {
2467  $langs->load("errors");
2468  print $langs->trans("Error")." ".$langs->trans("ErrorModuleSetupNotComplete");
2469  return "";
2470  }
2471  }
2472 
2483  function getNomUrl($withpicto=0, $option='', $get_params='', $notooltip=0, $save_lastsearch_value=-1)
2484  {
2485  global $langs, $conf, $user;
2486 
2487  if (! empty($conf->dol_no_mouse_hover)) $notooltip=1; // Force disable tooltips
2488 
2489  $url='';
2490  $result='';
2491 
2492  $label='<u>'.$langs->trans("ShowSupplierProposal").'</u>';
2493  if (! empty($this->ref))
2494  $label.= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
2495  if (! empty($this->ref_fourn))
2496  $label.= '<br><b>'.$langs->trans('RefSupplier').':</b> '.$this->ref_fourn;
2497  if (! empty($this->total_ht))
2498  $label.= '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
2499  if (! empty($this->total_tva))
2500  $label.= '<br><b>' . $langs->trans('VAT') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
2501  if (! empty($this->total_ttc))
2502  $label.= '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
2503  if ($option == '') {
2504  $url = DOL_URL_ROOT.'/supplier_proposal/card.php?id='.$this->id. $get_params;
2505  }
2506  if ($option == 'document') {
2507  $url = DOL_URL_ROOT.'/supplier_proposal/document.php?id='.$this->id. $get_params;
2508  }
2509 
2510  if ($option !== 'nolink')
2511  {
2512  // Add param to save lastsearch_values or not
2513  $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
2514  if ($save_lastsearch_value == -1 && preg_match('/list\.php/',$_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
2515  if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
2516  }
2517 
2518  $linkclose='';
2519  if (empty($notooltip) && $user->rights->propal->lire)
2520  {
2521  if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
2522  {
2523  $label=$langs->trans("ShowSupplierProposal");
2524  $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
2525  }
2526  $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
2527  $linkclose.=' class="classfortooltip"';
2528  }
2529 
2530  $linkstart = '<a href="'.$url.'"';
2531  $linkstart.=$linkclose.'>';
2532  $linkend='</a>';
2533 
2534  $picto='supplier_proposal';
2535 
2536  $result .= $linkstart;
2537  if ($withpicto) $result.=img_object(($notooltip?'':$label), $this->picto, ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
2538  if ($withpicto != 2) $result.= $this->ref;
2539  $result .= $linkend;
2540 
2541  return $result;
2542  }
2543 
2549  function getLinesArray()
2550  {
2551  // For other object, here we call fetch_lines. But fetch_lines does not exists on supplier proposal
2552 
2553  $sql = 'SELECT pt.rowid, pt.label as custom_label, pt.description, pt.fk_product, pt.fk_remise_except,';
2554  $sql.= ' pt.qty, pt.tva_tx, pt.remise_percent, pt.subprice, pt.info_bits,';
2555  $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,';
2556  $sql.= ' pt.product_type, pt.rang, pt.fk_parent_line,';
2557  $sql.= ' p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid,';
2558  $sql.= ' p.description as product_desc, pt.ref_fourn as ref_supplier,';
2559  $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';
2560  $sql.= ' FROM '.MAIN_DB_PREFIX.'supplier_proposaldet as pt';
2561  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pt.fk_product=p.rowid';
2562  $sql.= ' WHERE pt.fk_supplier_proposal = '.$this->id;
2563  $sql.= ' ORDER BY pt.rang ASC, pt.rowid';
2564 
2565  dol_syslog(get_class($this).'::getLinesArray', LOG_DEBUG);
2566  $resql = $this->db->query($sql);
2567  if ($resql)
2568  {
2569  $num = $this->db->num_rows($resql);
2570  $i = 0;
2571 
2572  while ($i < $num)
2573  {
2574  $obj = $this->db->fetch_object($resql);
2575 
2576  $this->lines[$i] = new SupplierProposalLine($this->db);
2577  $this->lines[$i]->id = $obj->rowid; // for backward compatibility
2578  $this->lines[$i]->rowid = $obj->rowid;
2579  $this->lines[$i]->label = $obj->custom_label;
2580  $this->lines[$i]->description = $obj->description;
2581  $this->lines[$i]->fk_product = $obj->fk_product;
2582  $this->lines[$i]->ref = $obj->ref;
2583  $this->lines[$i]->product_label = $obj->product_label;
2584  $this->lines[$i]->product_desc = $obj->product_desc;
2585  $this->lines[$i]->fk_product_type = $obj->fk_product_type; // deprecated
2586  $this->lines[$i]->product_type = $obj->product_type;
2587  $this->lines[$i]->qty = $obj->qty;
2588  $this->lines[$i]->subprice = $obj->subprice;
2589  $this->lines[$i]->fk_remise_except = $obj->fk_remise_except;
2590  $this->lines[$i]->remise_percent = $obj->remise_percent;
2591  $this->lines[$i]->tva_tx = $obj->tva_tx;
2592  $this->lines[$i]->info_bits = $obj->info_bits;
2593  $this->lines[$i]->total_ht = $obj->total_ht;
2594  $this->lines[$i]->total_tva = $obj->total_tva;
2595  $this->lines[$i]->total_ttc = $obj->total_ttc;
2596  $this->lines[$i]->fk_fournprice = $obj->fk_fournprice;
2597  $marginInfos = getMarginInfos($obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, $this->lines[$i]->fk_fournprice, $obj->pa_ht);
2598  $this->lines[$i]->pa_ht = $marginInfos[0];
2599  $this->lines[$i]->marge_tx = $marginInfos[1];
2600  $this->lines[$i]->marque_tx = $marginInfos[2];
2601  $this->lines[$i]->fk_parent_line = $obj->fk_parent_line;
2602  $this->lines[$i]->special_code = $obj->special_code;
2603  $this->lines[$i]->rang = $obj->rang;
2604 
2605  $this->lines[$i]->ref_fourn = $obj->ref_supplier; // deprecated
2606  $this->lines[$i]->ref_supplier = $obj->ref_supplier;
2607 
2608  // Multicurrency
2609  $this->lines[$i]->fk_multicurrency = $obj->fk_multicurrency;
2610  $this->lines[$i]->multicurrency_code = $obj->multicurrency_code;
2611  $this->lines[$i]->multicurrency_subprice = $obj->multicurrency_subprice;
2612  $this->lines[$i]->multicurrency_total_ht = $obj->multicurrency_total_ht;
2613  $this->lines[$i]->multicurrency_total_tva = $obj->multicurrency_total_tva;
2614  $this->lines[$i]->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
2615  $this->lines[$i]->fk_unit = $obj->fk_unit;
2616 
2617  $i++;
2618  }
2619  $this->db->free($resql);
2620 
2621  return 1;
2622  }
2623  else
2624  {
2625  $this->error=$this->db->error();
2626  return -1;
2627  }
2628  }
2629 
2641  public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
2642  {
2643  global $conf, $langs;
2644 
2645  $langs->load("supplier_proposal");
2646 
2647  if (! dol_strlen($modele)) {
2648 
2649  $modele = 'aurore';
2650 
2651  if ($this->modelpdf) {
2652  $modele = $this->modelpdf;
2653  } elseif (! empty($conf->global->SUPPLIER_PROPOSAL_ADDON_PDF)) {
2654  $modele = $conf->global->SUPPLIER_PROPOSAL_ADDON_PDF;
2655  }
2656  }
2657 
2658  $modelpath = "core/modules/supplier_proposal/doc/";
2659 
2660  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2661  }
2662 
2663 
2672  public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
2673  {
2674  $tables = array(
2675  'supplier_proposal'
2676  );
2677 
2678  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
2679  }
2680 }
2681 
2682 
2687 {
2691  public $db;
2692 
2696  public $error='';
2697 
2701  public $element='supplier_proposaldet';
2702 
2706  public $table_element='supplier_proposaldet';
2707 
2708  public $oldline;
2709 
2710  // From llx_supplier_proposaldet
2711  public $rowid; // deprecated
2712 
2716  public $id;
2717 
2721  public $fk_supplier_proposal;
2722 
2726  public $fk_parent_line;
2727 
2728  public $desc; // Description ligne
2729 
2733  public $fk_product; // Id produit predefini
2734 
2745  public $product_type = Product::TYPE_PRODUCT;
2746 
2747  public $qty;
2748  public $tva_tx;
2749  public $subprice;
2750  public $remise_percent;
2751 
2755  public $fk_remise_except;
2756 
2757  public $rang = 0;
2758 
2762  public $fk_fournprice;
2763 
2764  public $pa_ht;
2765  public $marge_tx;
2766  public $marque_tx;
2767 
2768  public $special_code; // Tag for special lines (exlusive tags)
2769  // 1: frais de port
2770  // 2: ecotaxe
2771  // 3: option line (when qty = 0)
2772 
2773  public $info_bits = 0; // Liste d'options cumulables:
2774  // Bit 0: 0 si TVA normal - 1 si TVA NPR
2775  // Bit 1: 0 ligne normale - 1 si ligne de remise fixe
2776 
2777  public $total_ht; // Total HT de la ligne toute quantite et incluant la remise ligne
2778  public $total_tva; // Total TVA de la ligne toute quantite et incluant la remise ligne
2779  public $total_ttc; // Total TTC de la ligne toute quantite et incluant la remise ligne
2780 
2785  public $remise;
2786 
2791  public $price;
2792 
2793  // From llx_product
2798  public $ref;
2799 
2804  public $product_ref;
2805 
2810  public $libelle;
2811 
2816  public $product_label;
2817 
2822  public $product_desc;
2823 
2824  public $localtax1_tx; // Local tax 1
2825  public $localtax2_tx; // Local tax 2
2826  public $localtax1_type; // Local tax 1 type
2827  public $localtax2_type; // Local tax 2 type
2828  public $total_localtax1; // Line total local tax 1
2829  public $total_localtax2; // Line total local tax 2
2830 
2831  public $skip_update_total; // Skip update price total for special lines
2832 
2833  public $ref_fourn;
2834  public $ref_supplier;
2835 
2836  // Multicurrency
2840  public $fk_multicurrency;
2841 
2842  public $multicurrency_code;
2843  public $multicurrency_subprice;
2844  public $multicurrency_total_ht;
2845  public $multicurrency_total_tva;
2846  public $multicurrency_total_ttc;
2847 
2853  function __construct($db)
2854  {
2855  $this->db= $db;
2856  }
2857 
2864  function fetch($rowid)
2865  {
2866  $sql = 'SELECT pd.rowid, pd.fk_supplier_proposal, pd.fk_parent_line, pd.fk_product, pd.label as custom_label, pd.description, pd.price, pd.qty, pd.tva_tx,';
2867  $sql.= ' pd.remise, pd.remise_percent, pd.fk_remise_except, pd.subprice,';
2868  $sql.= ' pd.info_bits, pd.total_ht, pd.total_tva, pd.total_ttc, pd.fk_product_fournisseur_price as fk_fournprice, pd.buy_price_ht as pa_ht, pd.special_code, pd.rang,';
2869  $sql.= ' pd.localtax1_tx, pd.localtax2_tx, pd.total_localtax1, pd.total_localtax2,';
2870  $sql.= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,';
2871  $sql.= ' pd.product_type, pd.ref_fourn as ref_produit_fourn,';
2872  $sql.= ' pd.fk_multicurrency, pd.multicurrency_code, pd.multicurrency_subprice, pd.multicurrency_total_ht, pd.multicurrency_total_tva, pd.multicurrency_total_ttc, pd.fk_unit';
2873  $sql.= ' FROM '.MAIN_DB_PREFIX.'supplier_proposaldet as pd';
2874  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pd.fk_product = p.rowid';
2875  $sql.= ' WHERE pd.rowid = '.$rowid;
2876 
2877  $result = $this->db->query($sql);
2878  if ($result)
2879  {
2880  $objp = $this->db->fetch_object($result);
2881 
2882  $this->rowid = $objp->rowid; // deprecated
2883  $this->id = $objp->rowid;
2884  $this->fk_supplier_proposal = $objp->fk_supplier_proposal;
2885  $this->fk_parent_line = $objp->fk_parent_line;
2886  $this->label = $objp->custom_label;
2887  $this->desc = $objp->description;
2888  $this->qty = $objp->qty;
2889  $this->price = $objp->price; // deprecated
2890  $this->subprice = $objp->subprice;
2891  $this->tva_tx = $objp->tva_tx;
2892  $this->remise = $objp->remise;
2893  $this->remise_percent = $objp->remise_percent;
2894  $this->fk_remise_except = $objp->fk_remise_except;
2895  $this->fk_product = $objp->fk_product;
2896  $this->info_bits = $objp->info_bits;
2897 
2898  $this->total_ht = $objp->total_ht;
2899  $this->total_tva = $objp->total_tva;
2900  $this->total_ttc = $objp->total_ttc;
2901 
2902  $this->fk_fournprice = $objp->fk_fournprice;
2903 
2904  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht);
2905  $this->pa_ht = $marginInfos[0];
2906  $this->marge_tx = $marginInfos[1];
2907  $this->marque_tx = $marginInfos[2];
2908 
2909  $this->special_code = $objp->special_code;
2910  $this->product_type = $objp->product_type;
2911  $this->rang = $objp->rang;
2912 
2913  $this->ref = $objp->product_ref; // deprecated
2914  $this->product_ref = $objp->product_ref;
2915  $this->libelle = $objp->product_label; // deprecated
2916  $this->product_label = $objp->product_label;
2917  $this->product_desc = $objp->product_desc;
2918 
2919  $this->ref_fourn = $objp->ref_produit_forun;
2920 
2921  // Multicurrency
2922  $this->fk_multicurrency = $objp->fk_multicurrency;
2923  $this->multicurrency_code = $objp->multicurrency_code;
2924  $this->multicurrency_subprice = $objp->multicurrency_subprice;
2925  $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
2926  $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
2927  $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
2928  $this->fk_unit = $objp->fk_unit;
2929 
2930  $this->db->free($result);
2931  }
2932  else
2933  {
2934  dol_print_error($this->db);
2935  }
2936  }
2937 
2944  function insert($notrigger=0)
2945  {
2946  global $conf,$langs,$user;
2947 
2948  $error=0;
2949 
2950  dol_syslog(get_class($this)."::insert rang=".$this->rang);
2951 
2952  // Clean parameters
2953  if (empty($this->tva_tx)) $this->tva_tx=0;
2954  if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
2955  if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
2956  if (empty($this->localtax1_type)) $this->localtax1_type=0;
2957  if (empty($this->localtax2_type)) $this->localtax2_type=0;
2958  if (empty($this->total_localtax1)) $this->total_localtax1=0;
2959  if (empty($this->total_localtax2)) $this->total_localtax2=0;
2960  if (empty($this->rang)) $this->rang=0;
2961  if (empty($this->remise)) $this->remise=0;
2962  if (empty($this->remise_percent)) $this->remise_percent=0;
2963  if (empty($this->info_bits)) $this->info_bits=0;
2964  if (empty($this->special_code)) $this->special_code=0;
2965  if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
2966  if (empty($this->fk_fournprice)) $this->fk_fournprice=0;
2967  if (empty($this->fk_unit)) $this->fk_unit=0;
2968  if (empty($this->subprice)) $this->subprice=0;
2969 
2970  if (empty($this->pa_ht)) $this->pa_ht=0;
2971 
2972  // if buy price not defined, define buyprice as configured in margin admin
2973  if ($this->pa_ht == 0)
2974  {
2975  if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0)
2976  {
2977  return $result;
2978  }
2979  else
2980  {
2981  $this->pa_ht = $result;
2982  }
2983  }
2984 
2985  // Check parameters
2986  if ($this->product_type < 0) return -1;
2987 
2988  $this->db->begin();
2989 
2990  // Insert line into database
2991  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'supplier_proposaldet';
2992  $sql.= ' (fk_supplier_proposal, fk_parent_line, label, description, fk_product, product_type,';
2993  $sql.= ' fk_remise_except, qty, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
2994  $sql.= ' subprice, remise_percent, ';
2995  $sql.= ' info_bits, ';
2996  $sql.= ' total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, fk_product_fournisseur_price, buy_price_ht, special_code, rang,';
2997  $sql.= ' ref_fourn,';
2998  $sql.= ' fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc, fk_unit)';
2999  $sql.= " VALUES (".$this->fk_supplier_proposal.",";
3000  $sql.= " ".($this->fk_parent_line>0?"'".$this->db->escape($this->fk_parent_line)."'":"null").",";
3001  $sql.= " ".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null").",";
3002  $sql.= " '".$this->db->escape($this->desc)."',";
3003  $sql.= " ".($this->fk_product?"'".$this->db->escape($this->fk_product)."'":"null").",";
3004  $sql.= " '".$this->db->escape($this->product_type)."',";
3005  $sql.= " ".($this->fk_remise_except?"'".$this->db->escape($this->fk_remise_except)."'":"null").",";
3006  $sql.= " ".price2num($this->qty).",";
3007  $sql.= " ".price2num($this->tva_tx).",";
3008  $sql.= " ".price2num($this->localtax1_tx).",";
3009  $sql.= " ".price2num($this->localtax2_tx).",";
3010  $sql.= " '".$this->db->escape($this->localtax1_type)."',";
3011  $sql.= " '".$this->db->escape($this->localtax2_type)."',";
3012  $sql.= " ".(!empty($this->subprice)?price2num($this->subprice):"null").",";
3013  $sql.= " ".price2num($this->remise_percent).",";
3014  $sql.= " ".(isset($this->info_bits)?"'".$this->db->escape($this->info_bits)."'":"null").",";
3015  $sql.= " ".price2num($this->total_ht).",";
3016  $sql.= " ".price2num($this->total_tva).",";
3017  $sql.= " ".price2num($this->total_localtax1).",";
3018  $sql.= " ".price2num($this->total_localtax2).",";
3019  $sql.= " ".price2num($this->total_ttc).",";
3020  $sql.= " ".(!empty($this->fk_fournprice)?"'".$this->db->escape($this->fk_fournprice)."'":"null").",";
3021  $sql.= " ".(isset($this->pa_ht)?"'".price2num($this->pa_ht)."'":"null").",";
3022  $sql.= ' '.$this->special_code.',';
3023  $sql.= ' '.$this->rang.',';
3024  $sql.= " '".$this->db->escape($this->ref_fourn)."'";
3025  $sql.= ", ".($this->fk_multicurrency > 0?$this->fk_multicurrency:'null');
3026  $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
3027  $sql.= ", ".$this->multicurrency_subprice;
3028  $sql.= ", ".$this->multicurrency_total_ht;
3029  $sql.= ", ".$this->multicurrency_total_tva;
3030  $sql.= ", ".$this->multicurrency_total_ttc;
3031  $sql.= ", ".($this->fk_unit?$this->fk_unit:'null');
3032  $sql.= ')';
3033 
3034  dol_syslog(get_class($this).'::insert', LOG_DEBUG);
3035  $resql=$this->db->query($sql);
3036  if ($resql)
3037  {
3038  $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'supplier_proposaldet');
3039  $this->id=$this->rowid;
3040 
3041  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
3042  {
3043  $result=$this->insertExtraFields();
3044  if ($result < 0)
3045  {
3046  $error++;
3047  }
3048  }
3049 
3050  if (! $error && ! $notrigger)
3051  {
3052  // Call trigger
3053  $result=$this->call_trigger('LINESUPPLIER_PROPOSAL_INSERT',$user);
3054  if ($result < 0)
3055  {
3056  $this->db->rollback();
3057  return -1;
3058  }
3059  // End call triggers
3060  }
3061 
3062  $this->db->commit();
3063  return 1;
3064  }
3065  else
3066  {
3067  $this->error=$this->db->error()." sql=".$sql;
3068  $this->db->rollback();
3069  return -1;
3070  }
3071  }
3072 
3078  function delete()
3079  {
3080  global $conf,$langs,$user;
3081 
3082  $error=0;
3083  $this->db->begin();
3084 
3085  $sql = "DELETE FROM ".MAIN_DB_PREFIX."supplier_proposaldet WHERE rowid = ".$this->rowid;
3086  dol_syslog("SupplierProposalLine::delete", LOG_DEBUG);
3087  if ($this->db->query($sql) )
3088  {
3089 
3090  // Remove extrafields
3091  if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used
3092  {
3093  $this->id=$this->rowid;
3094  $result=$this->deleteExtraFields();
3095  if ($result < 0)
3096  {
3097  $error++;
3098  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
3099  }
3100  }
3101 
3102  // Call trigger
3103  $result=$this->call_trigger('LINESUPPLIER_PROPOSAL_DELETE',$user);
3104  if ($result < 0)
3105  {
3106  $this->db->rollback();
3107  return -1;
3108  }
3109  // End call triggers
3110 
3111  $this->db->commit();
3112 
3113  return 1;
3114  }
3115  else
3116  {
3117  $this->error=$this->db->error()." sql=".$sql;
3118  $this->db->rollback();
3119  return -1;
3120  }
3121  }
3122 
3129  function update($notrigger=0)
3130  {
3131  global $conf,$langs,$user;
3132 
3133  $error=0;
3134 
3135  // Clean parameters
3136  if (empty($this->tva_tx)) $this->tva_tx=0;
3137  if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
3138  if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
3139  if (empty($this->total_localtax1)) $this->total_localtax1=0;
3140  if (empty($this->total_localtax2)) $this->total_localtax2=0;
3141  if (empty($this->localtax1_type)) $this->localtax1_type=0;
3142  if (empty($this->localtax2_type)) $this->localtax2_type=0;
3143  if (empty($this->marque_tx)) $this->marque_tx=0;
3144  if (empty($this->marge_tx)) $this->marge_tx=0;
3145  if (empty($this->price)) $this->price=0; // TODO A virer
3146  if (empty($this->remise)) $this->remise=0; // TODO A virer
3147  if (empty($this->remise_percent)) $this->remise_percent=0;
3148  if (empty($this->info_bits)) $this->info_bits=0;
3149  if (empty($this->special_code)) $this->special_code=0;
3150  if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
3151  if (empty($this->fk_fournprice)) $this->fk_fournprice=0;
3152  if (empty($this->fk_unit)) $this->fk_unit=0;
3153  if (empty($this->subprice)) $this->subprice=0;
3154 
3155  if (empty($this->pa_ht)) $this->pa_ht=0;
3156 
3157  // if buy price not defined, define buyprice as configured in margin admin
3158  if ($this->pa_ht == 0)
3159  {
3160  if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0)
3161  {
3162  return $result;
3163  }
3164  else
3165  {
3166  $this->pa_ht = $result;
3167  }
3168  }
3169 
3170  $this->db->begin();
3171 
3172  // Mise a jour ligne en base
3173  $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposaldet SET";
3174  $sql.= " description='".$this->db->escape($this->desc)."'";
3175  $sql.= " , label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null");
3176  $sql.= " , product_type=".$this->product_type;
3177  $sql.= " , tva_tx='".price2num($this->tva_tx)."'";
3178  $sql.= " , localtax1_tx=".price2num($this->localtax1_tx);
3179  $sql.= " , localtax2_tx=".price2num($this->localtax2_tx);
3180  $sql.= " , localtax1_type='".$this->db->escape($this->localtax1_type)."'";
3181  $sql.= " , localtax2_type='".$this->db->escape($this->localtax2_type)."'";
3182  $sql.= " , qty='".price2num($this->qty)."'";
3183  $sql.= " , subprice=".price2num($this->subprice)."";
3184  $sql.= " , remise_percent=".price2num($this->remise_percent)."";
3185  $sql.= " , price=".price2num($this->price).""; // TODO A virer
3186  $sql.= " , remise=".price2num($this->remise).""; // TODO A virer
3187  $sql.= " , info_bits='".$this->db->escape($this->info_bits)."'";
3188  if (empty($this->skip_update_total))
3189  {
3190  $sql.= " , total_ht=".price2num($this->total_ht)."";
3191  $sql.= " , total_tva=".price2num($this->total_tva)."";
3192  $sql.= " , total_ttc=".price2num($this->total_ttc)."";
3193  $sql.= " , total_localtax1=".price2num($this->total_localtax1)."";
3194  $sql.= " , total_localtax2=".price2num($this->total_localtax2)."";
3195  }
3196  $sql.= " , fk_product_fournisseur_price=".(! empty($this->fk_fournprice)?"'".$this->db->escape($this->fk_fournprice)."'":"null");
3197  $sql.= " , buy_price_ht=".price2num($this->pa_ht);
3198  if (strlen($this->special_code)) $sql.= " , special_code=".$this->special_code;
3199  $sql.= " , fk_parent_line=".($this->fk_parent_line>0?$this->fk_parent_line:"null");
3200  if (! empty($this->rang)) $sql.= ", rang=".$this->rang;
3201  $sql.= " , ref_fourn=".(! empty($this->ref_fourn)?"'".$this->db->escape($this->ref_fourn)."'":"null");
3202  $sql.= " , fk_unit=".($this->fk_unit?$this->fk_unit:'null');
3203 
3204  // Multicurrency
3205  $sql.= " , multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
3206  $sql.= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
3207  $sql.= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
3208  $sql.= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
3209 
3210  $sql.= " WHERE rowid = ".$this->rowid;
3211 
3212  dol_syslog(get_class($this)."::update", LOG_DEBUG);
3213  $resql=$this->db->query($sql);
3214  if ($resql)
3215  {
3216  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
3217  {
3218  $this->id=$this->rowid;
3219  $result=$this->insertExtraFields();
3220  if ($result < 0)
3221  {
3222  $error++;
3223  }
3224  }
3225 
3226  if (! $error && ! $notrigger)
3227  {
3228  // Call trigger
3229  $result=$this->call_trigger('LINESUPPLIER_PROPOSAL_UPDATE',$user);
3230  if ($result < 0)
3231  {
3232  $this->db->rollback();
3233  return -1;
3234  }
3235  // End call triggers
3236  }
3237 
3238  $this->db->commit();
3239  return 1;
3240  }
3241  else
3242  {
3243  $this->error=$this->db->error();
3244  $this->db->rollback();
3245  return -2;
3246  }
3247  }
3248 
3249  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3256  function update_total()
3257  {
3258  // phpcs:enable
3259  $this->db->begin();
3260 
3261  // Mise a jour ligne en base
3262  $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposaldet SET";
3263  $sql.= " total_ht=".price2num($this->total_ht,'MT')."";
3264  $sql.= ",total_tva=".price2num($this->total_tva,'MT')."";
3265  $sql.= ",total_ttc=".price2num($this->total_ttc,'MT')."";
3266  $sql.= " WHERE rowid = ".$this->rowid;
3267 
3268  dol_syslog("SupplierProposalLine::update_total", LOG_DEBUG);
3269 
3270  $resql=$this->db->query($sql);
3271  if ($resql)
3272  {
3273  $this->db->commit();
3274  return 1;
3275  }
3276  else
3277  {
3278  $this->error=$this->db->error();
3279  $this->db->rollback();
3280  return -2;
3281  }
3282  }
3283 }
print $object label
hash of file content (md5_file(dol_osencode($destfull))
Definition: edit.php:153
fetch($rowid)
Retrieve the propal line object.
reopen($user, $statut, $note='', $notrigger=0)
Reopen the commercial proposal.
GETPOST($paramname, $check='none', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
print
Draft customers invoices.
Definition: index.php:91
if(! empty($conf->facture->enabled) && $user->rights->facture->lire) if(! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture->lire) if(! empty($conf->don->enabled) && $user->rights->societe->lire) if(! empty($conf->tax->enabled) && $user->rights->tax->charges->lire) if(! empty($conf->facture->enabled) &&! empty($conf->commande->enabled) && $user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(! empty($conf->facture->enabled) && $user->rights->facture->lire) if(! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1053
const STATUS_NOTSIGNED
Not signed quote, canceled.
getMarginInfos($pvht, $remise_percent, $tva_tx, $localtax1_tx, $localtax2_tx, $fk_pa, $paht)
Return an array with margins information of a line.
create_from($user)
Insert into DB a supplier_proposal object completely defined by its data members (ex, results from copy).
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
Delete all links between an object $this.
set_date_livraison($user, $date_livraison)
Set delivery date.
addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $pu_ttc=0, $info_bits=0, $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=0, $pa_ht=0, $label='', $array_option=0, $ref_supplier='', $fk_unit='', $origin='', $origin_id=0, $pu_ht_devise=0)
Add a proposal line into database (linked to product/service or not) Les parametres sont deja cense e...
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
updatePriceFournisseur($idProductFournPrice, $product, $user)
Upate ProductFournisseur.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
liste_array($shortlist=0, $draft=0, $notcurrentuser=0, $socid=0, $limit=0, $offset=0, $sortfield='p.datec', $sortorder='DESC')
Return list of askprice (eventually filtered on user) into an array.
LibStatut($statut, $mode=1)
Return label of a status (draft, validated, ...)
if(! empty($search_group)) natural_search(array("g.nom" g note
Definition: list.php:123
Class to manage products or services.
dol_delete_preview($object)
Delete all preview files linked to object instance.
Definition: files.lib.php:1324
Class to manage Dolibarr users.
Definition: user.class.php:41
__construct($db)
Class line Contructor.
Class to manage Dolibarr database access.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
__construct($db, $socid="", $supplier_proposalid=0)
Constructor.
const STATUS_CLOSE
Billed or closed/processed quote.
dol_print_error($db='', $error='', $errors=null)
Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remonte...
info($id)
Object SupplierProposal Information.
const TYPE_PRODUCT
Regular product.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Fonction qui renvoie si tva doit etre tva percue recuperable.
fetch_thirdparty($force_thirdparty_id=0)
Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty.
update($notrigger=0)
Update propal line object into DB.
load_state_board()
Charge indicateurs this->nb de tableau de bord.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate, from a $thirdparty_buyer to a $thirdparty_seller Note: This function applies same rules than get_default_tva.
create($user, $notrigger=0)
Create commercial proposal into database this->ref can be set or empty.
static replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
getLinesArray()
Retrieve an array of supplier proposal lines.
const STATUS_SIGNED
Signed quote.
insert($notrigger=0)
Insert object line propal in database.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='')
Write log message into outputs.
Class to manage third parties objects (customers, suppliers, prospects...)
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
update_total()
Update DB line fields total_xxx Used by migration.
createPriceFournisseur($product, $user)
Create ProductFournisseur.
cloture($user, $statut, $note)
Close the askprice.
add_product($idproduct, $qty, $remise_percent=0)
Add line into array products $this->client doit etre charge.
update_price($exclspec=0, $roundingadjust='none', $nodatabaseupdate=0, $seller=null)
Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines)...
const STATUS_VALIDATED
Validated status.
insert_discount($idremise)
Adding line of fixed discount in the proposal in DB.
static commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
load_board($user, $mode)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
getNomUrl($withpicto=0, $option='', $get_params='', $notooltip=0, $save_lastsearch_value=-1)
Return clicable link of object (with eventually picto)
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories) ...
Definition: files.lib.php:1273
updateline($rowid, $pu, $qty, $remise_percent, $txtva, $txlocaltax1=0, $txlocaltax2=0, $desc='', $price_base_type='HT', $info_bits=0, $special_code=0, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=0, $pa_ht=0, $label='', $type=0, $array_option=0, $ref_supplier='', $fk_unit='')
Update a proposal line.
valid($user, $notrigger=0)
Set status to validated.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1)
Remove a file or several files with a mask.
Definition: files.lib.php:1139
createFromClone($socid=0)
Load an object from its id and create a new one in database.
deleteExtraFields()
Delete all extra fields values for the current object.
Class to manage translations.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:59
set_remise_absolue($user, $remise)
Set an absolute overall discount on the proposal.
dol_now($mode='gmt')
Return date for now.
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
fetch($rowid, $ref='')
Load a proposal from database and its ligne array.
defineBuyPrice($unitPrice=0.0, $discountPercent=0.0, $fk_product=0)
Get buy price to use for margin calculation.
Class to manage supplier_proposal lines.
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller='', $localtaxes_array='', $progress=100, $multicurrency_tx=1, $pu_devise=0)
Calculate totals (net, vat, ...) of a line.
Definition: price.lib.php:85
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages...
const STATUS_DRAFT
Draft status.
getLibStatut($mode=0)
Return label of status of proposal (draft, validated, ...)
Class to manage price ask supplier.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) Si ...
line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
Save a new position (field rang) for details lines.
Class to manage absolute discounts.
initAsSpecimen()
Initialise an instance with random values.
call_trigger($trigger_name, $user)
Call trigger based on this instance.
updateOrCreatePriceFournisseur($user)
Add or update supplier price according to result of proposal.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
getNextNumRef($soc)
Returns the reference to the following non used Proposal used depending on the active numbering modul...
add_object_linked($origin=null, $origin_id=null)
Add objects linked in llx_element_element.
deleteline($lineid)
Delete detail line.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='')
Show picto whatever it&#39;s its name (generic function)
price2num($amount, $rounding='', $alreadysqlnb=0)
Function that return a number with universal decimal format (decimal separator is &#39;...
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Parent class of all other business classes (invoices, contracts, proposals, orders, ...)
Class to manage predefined suppliers products.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
set_draft($user)
Set draft status.
set_remise_percent($user, $remise)
Set an overall discount on the proposal.
static getIdAndTxFromCode(&$db, $code, $date_document='')
Get id and rate of currency from code.