dolibarr  9.0.0
propal.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-2014 Juanjo Menent <jmenent@2byte.es>
10  * Copyright (C) 2010-2017 Philippe Grand <philippe.grand@atoo-net.com>
11  * Copyright (C) 2012-2014 Christophe Battarel <christophe.battarel@altairis.fr>
12  * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
13  * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
14  * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
15  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
16  * Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
17  * Copyright (C) 2018 Ferran Marcet <fmarcet@2byte.es>
18  *
19  * This program is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program. If not, see <http://www.gnu.org/licenses/>.
31  */
32 
38 require_once DOL_DOCUMENT_ROOT .'/core/class/commonobject.class.php';
39 require_once DOL_DOCUMENT_ROOT ."/core/class/commonobjectline.class.php";
40 require_once DOL_DOCUMENT_ROOT .'/product/class/product.class.php';
41 require_once DOL_DOCUMENT_ROOT .'/contact/class/contact.class.php';
42 require_once DOL_DOCUMENT_ROOT .'/margin/lib/margins.lib.php';
43 require_once DOL_DOCUMENT_ROOT .'/multicurrency/class/multicurrency.class.php';
44 
48 class Propal extends CommonObject
49 {
53  public $element='propal';
54 
58  public $table_element='propal';
59 
63  public $table_element_line='propaldet';
64 
68  public $fk_element ='fk_propal';
69 
73  public $picto='propal';
74 
79  public $ismultientitymanaged = 1;
80 
85  public $restrictiononfksoc = 1;
86 
90  protected $table_ref_field = 'ref';
91 
96  public $socid;
97 
98  public $contactid;
99  public $author;
100  public $ref_client;
101 
107  public $statut;
108 
113  public $datec;
114 
119  public $date_creation;
120 
125  public $datev;
126 
131  public $date_validation;
132 
137  public $date;
138 
143  public $datep;
144  public $date_livraison;
145  public $fin_validite;
146 
147  public $user_author_id;
148  public $user_valid_id;
149  public $user_close_id;
150 
155  public $price;
160  public $tva;
165  public $total;
166 
167  public $cond_reglement_code;
168  public $mode_reglement_code;
169  public $remise = 0;
170  public $remise_percent = 0;
171  public $remise_absolue = 0;
172 
176  public $fk_address;
177 
178  public $address_type;
179  public $address;
180  public $availability_id;
181  public $availability_code;
182  public $demand_reason_id;
183  public $demand_reason_code;
184 
185  public $products=array();
186  public $extraparams=array();
187 
191  public $lines = array();
192  public $line;
193 
194  public $labelstatut=array();
195  public $labelstatut_short=array();
196 
197  public $specimen;
198 
199  // Multicurrency
203  public $fk_multicurrency;
204 
205  public $multicurrency_code;
206  public $multicurrency_tx;
207  public $multicurrency_total_ht;
208  public $multicurrency_total_tva;
209  public $multicurrency_total_ttc;
210 
211  public $oldcopy;
212 
216  const STATUS_DRAFT = 0;
220  const STATUS_VALIDATED = 1;
224  const STATUS_SIGNED = 2;
228  const STATUS_NOTSIGNED = 3;
232  const STATUS_BILLED = 4; // Todo rename into STATUS_CLOSE ?
233 
234 
242  function __construct($db, $socid="", $propalid=0)
243  {
244  global $conf,$langs;
245 
246  $this->db = $db;
247 
248  $this->socid = $socid;
249  $this->id = $propalid;
250 
251  $this->products = array();
252 
253  $this->duree_validite=$conf->global->PROPALE_VALIDITY_DURATION;
254  }
255 
256 
257  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
270  function add_product($idproduct, $qty, $remise_percent=0)
271  {
272  // phpcs:enable
273  global $conf, $mysoc;
274 
275  if (! $qty) $qty = 1;
276 
277  dol_syslog(get_class($this)."::add_product $idproduct, $qty, $remise_percent");
278  if ($idproduct > 0)
279  {
280  $prod=new Product($this->db);
281  $prod->fetch($idproduct);
282 
283  $productdesc = $prod->description;
284 
285  $tva_tx = get_default_tva($mysoc,$this->thirdparty,$prod->id);
286  $tva_npr = get_default_npr($mysoc,$this->thirdparty,$prod->id);
287  if (empty($tva_tx)) $tva_npr=0;
288  $vat_src_code = ''; // May be defined into tva_tx
289 
290  $localtax1_tx = get_localtax($tva_tx,1,$mysoc,$this->thirdparty,$tva_npr);
291  $localtax2_tx = get_localtax($tva_tx,2,$mysoc,$this->thirdparty,$tva_npr);
292 
293  // multiprices
294  if($conf->global->PRODUIT_MULTIPRICES && $this->thirdparty->price_level)
295  {
296  $price = $prod->multiprices[$this->thirdparty->price_level];
297  }
298  else
299  {
300  $price = $prod->price;
301  }
302 
303  $line = new PropaleLigne($this->db);
304 
305  $line->fk_product=$idproduct;
306  $line->desc=$productdesc;
307  $line->qty=$qty;
308  $line->subprice=$price;
309  $line->remise_percent=$remise_percent;
310  $line->vat_src_code=$vat_src_code;
311  $line->tva_tx=$tva_tx;
312  $line->fk_unit=$prod->fk_unit;
313  if ($tva_npr) $line->info_bits = 1;
314 
315  $this->lines[]=$line;
316  }
317  }
318 
319  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
326  function insert_discount($idremise)
327  {
328  // phpcs:enable
329  global $langs;
330 
331  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
332  include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
333 
334  $this->db->begin();
335 
336  $remise=new DiscountAbsolute($this->db);
337  $result=$remise->fetch($idremise);
338 
339  if ($result > 0)
340  {
341  if ($remise->fk_facture) // Protection against multiple submission
342  {
343  $this->error=$langs->trans("ErrorDiscountAlreadyUsed");
344  $this->db->rollback();
345  return -5;
346  }
347 
348  $line=new PropaleLigne($this->db);
349 
350  $this->line->context = $this->context;
351 
352  $line->fk_propal=$this->id;
353  $line->fk_remise_except=$remise->id;
354  $line->desc=$remise->description; // Description ligne
355  $line->vat_src_code=$remise->vat_src_code;
356  $line->tva_tx=$remise->tva_tx;
357  $line->subprice=-$remise->amount_ht;
358  $line->fk_product=0; // Id produit predefined
359  $line->qty=1;
360  $line->remise=0;
361  $line->remise_percent=0;
362  $line->rang=-1;
363  $line->info_bits=2;
364 
365  // TODO deprecated
366  $line->price=-$remise->amount_ht;
367 
368  $line->total_ht = -$remise->amount_ht;
369  $line->total_tva = -$remise->amount_tva;
370  $line->total_ttc = -$remise->amount_ttc;
371 
372  $result=$line->insert();
373  if ($result > 0)
374  {
375  $result=$this->update_price(1);
376  if ($result > 0)
377  {
378  $this->db->commit();
379  return 1;
380  }
381  else
382  {
383  $this->db->rollback();
384  return -1;
385  }
386  }
387  else
388  {
389  $this->error=$line->error;
390  $this->db->rollback();
391  return -2;
392  }
393  }
394  else
395  {
396  $this->db->rollback();
397  return -2;
398  }
399  }
400 
437  function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0.0, $txlocaltax2=0.0, $fk_product=0, $remise_percent=0.0, $price_base_type='HT', $pu_ttc=0.0, $info_bits=0, $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=0, $pa_ht=0, $label='',$date_start='', $date_end='',$array_options=0, $fk_unit=null, $origin='', $origin_id=0, $pu_ht_devise=0, $fk_remise_except=0)
438  {
439  global $mysoc, $conf, $langs;
440 
441  dol_syslog(get_class($this)."::addline propalid=$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, fk_remise_except=".$fk_remise_except);
442  if ($this->statut == self::STATUS_DRAFT)
443  {
444  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
445 
446  // Clean parameters
447  if (empty($remise_percent)) $remise_percent=0;
448  if (empty($qty)) $qty=0;
449  if (empty($info_bits)) $info_bits=0;
450  if (empty($rang)) $rang=0;
451  if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0;
452 
453  $remise_percent=price2num($remise_percent);
454  $qty=price2num($qty);
455  $pu_ht=price2num($pu_ht);
456  $pu_ht_devise=price2num($pu_ht_devise);
457  $pu_ttc=price2num($pu_ttc);
458  if (!preg_match('/\((.*)\)/', $txtva)) {
459  $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
460  }
461  $txlocaltax1=price2num($txlocaltax1);
462  $txlocaltax2=price2num($txlocaltax2);
463  $pa_ht=price2num($pa_ht);
464  if ($price_base_type=='HT')
465  {
466  $pu=$pu_ht;
467  }
468  else
469  {
470  $pu=$pu_ttc;
471  }
472 
473  // Check parameters
474  if ($type < 0) return -1;
475 
476  $this->db->begin();
477 
478  $product_type=$type;
479  if (!empty($fk_product))
480  {
481  $product=new Product($this->db);
482  $result=$product->fetch($fk_product);
483  $product_type=$product->type;
484 
485  if (! empty($conf->global->STOCK_MUST_BE_ENOUGH_FOR_PROPOSAL) && $product_type == 0 && $product->stock_reel < $qty) {
486  $langs->load("errors");
487  $this->error=$langs->trans('ErrorStockIsNotEnoughToAddProductOnProposal', $product->ref);
488  $this->db->rollback();
489  return -3;
490  }
491  }
492 
493  // Calcul du total TTC et de la TVA pour la ligne a partir de
494  // qty, pu, remise_percent et txtva
495  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
496  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
497 
498  $localtaxes_type=getLocalTaxesFromRate($txtva,0,$this->thirdparty,$mysoc);
499 
500  // Clean vat code
501  $vat_src_code='';
502  if (preg_match('/\((.*)\)/', $txtva, $reg))
503  {
504  $vat_src_code = $reg[1];
505  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
506  }
507 
508  $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $product_type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
509 
510  $total_ht = $tabprice[0];
511  $total_tva = $tabprice[1];
512  $total_ttc = $tabprice[2];
513  $total_localtax1 = $tabprice[9];
514  $total_localtax2 = $tabprice[10];
515  $pu_ht = $tabprice[3];
516  $pu_tva = $tabprice[4];
517  $pu_ttc = $tabprice[5];
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 PropaleLigne($this->db);
545 
546  $this->line->context = $this->context;
547 
548  $this->line->fk_propal=$this->id;
549  $this->line->label=$label;
550  $this->line->desc=$desc;
551  $this->line->qty=$qty;
552 
553  $this->line->vat_src_code=$vat_src_code;
554  $this->line->tva_tx=$txtva;
555  $this->line->localtax1_tx=($total_localtax1?$localtaxes_type[1]:0);
556  $this->line->localtax2_tx=($total_localtax2?$localtaxes_type[3]:0);
557  $this->line->localtax1_type = $localtaxes_type[0];
558  $this->line->localtax2_type = $localtaxes_type[2];
559  $this->line->fk_product=$fk_product;
560  $this->line->product_type=$type;
561  $this->line->fk_remise_except=$fk_remise_except;
562  $this->line->remise_percent=$remise_percent;
563  $this->line->subprice=$pu_ht;
564  $this->line->rang=$rangtouse;
565  $this->line->info_bits=$info_bits;
566  $this->line->total_ht=$total_ht;
567  $this->line->total_tva=$total_tva;
568  $this->line->total_localtax1=$total_localtax1;
569  $this->line->total_localtax2=$total_localtax2;
570  $this->line->total_ttc=$total_ttc;
571  $this->line->special_code=$special_code;
572  $this->line->fk_parent_line=$fk_parent_line;
573  $this->line->fk_unit=$fk_unit;
574 
575  $this->line->date_start=$date_start;
576  $this->line->date_end=$date_end;
577 
578  $this->line->fk_fournprice = $fk_fournprice;
579  $this->line->pa_ht = $pa_ht;
580 
581  $this->line->origin_id = $origin_id;
582  $this->line->origin = $origin;
583 
584  // Multicurrency
585  $this->line->fk_multicurrency = $this->fk_multicurrency;
586  $this->line->multicurrency_code = $this->multicurrency_code;
587  $this->line->multicurrency_subprice = $pu_ht_devise;
588  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
589  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
590  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
591 
592  // Mise en option de la ligne
593  if (empty($qty) && empty($special_code)) $this->line->special_code=3;
594 
595  // TODO deprecated
596  $this->line->price=$price;
597  $this->line->remise=$remise;
598 
599  if (is_array($array_options) && count($array_options)>0) {
600  $this->line->array_options=$array_options;
601  }
602 
603  $result=$this->line->insert();
604  if ($result > 0)
605  {
606  // Reorder if child line
607  if (! empty($fk_parent_line)) $this->line_order(true,'DESC');
608 
609  // Mise a jour informations denormalisees au niveau de la propale meme
610  $result=$this->update_price(1,'auto',0,$mysoc); // This method is designed to add line from user input so total calculation must be done using 'auto' mode.
611  if ($result > 0)
612  {
613  $this->db->commit();
614  return $this->line->rowid;
615  }
616  else
617  {
618  $this->error=$this->db->error();
619  $this->db->rollback();
620  return -1;
621  }
622  }
623  else
624  {
625  $this->error=$this->line->error;
626  $this->db->rollback();
627  return -2;
628  }
629  }
630  else
631  {
632  dol_syslog(get_class($this)."::addline status of order must be Draft to allow use of ->addline()", LOG_ERR);
633  return -3;
634  }
635  }
636 
637 
666  function updateline($rowid, $pu, $qty, $remise_percent, $txtva, $txlocaltax1=0.0, $txlocaltax2=0.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, $date_start='', $date_end='', $array_options=0, $fk_unit=null, $pu_ht_devise = 0, $notrigger=0)
667  {
668  global $mysoc;
669 
670  dol_syslog(get_class($this)."::updateLine rowid=$rowid, pu=$pu, qty=$qty, remise_percent=$remise_percent,
671  txtva=$txtva, desc=$desc, price_base_type=$price_base_type, info_bits=$info_bits, special_code=$special_code, fk_parent_line=$fk_parent_line, pa_ht=$pa_ht, type=$type, date_start=$date_start, date_end=$date_end");
672  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
673 
674  // Clean parameters
675  $remise_percent=price2num($remise_percent);
676  $qty=price2num($qty);
677  $pu = price2num($pu);
678  $pu_ht_devise=price2num($pu_ht_devise);
679  $txtva = price2num($txtva);
680  $txlocaltax1=price2num($txlocaltax1);
681  $txlocaltax2=price2num($txlocaltax2);
682  $pa_ht=price2num($pa_ht);
683  if (empty($qty) && empty($special_code)) $special_code=3; // Set option tag
684  if (! empty($qty) && $special_code == 3) $special_code=0; // Remove option tag
685  if (empty($type)) $type=0;
686 
687  if ($this->statut == self::STATUS_DRAFT)
688  {
689  $this->db->begin();
690 
691  // Calcul du total TTC et de la TVA pour la ligne a partir de
692  // qty, pu, remise_percent et txtva
693  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
694  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
695 
696  $localtaxes_type=getLocalTaxesFromRate($txtva,0,$this->thirdparty,$mysoc);
697 
698  // Clean vat code
699  $vat_src_code='';
700  if (preg_match('/\((.*)\)/', $txtva, $reg))
701  {
702  $vat_src_code = $reg[1];
703  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
704  }
705 
706  $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
707  $total_ht = $tabprice[0];
708  $total_tva = $tabprice[1];
709  $total_ttc = $tabprice[2];
710  $total_localtax1 = $tabprice[9];
711  $total_localtax2 = $tabprice[10];
712  $pu_ht = $tabprice[3];
713  $pu_tva = $tabprice[4];
714  $pu_ttc = $tabprice[5];
715 
716  // MultiCurrency
717  $multicurrency_total_ht = $tabprice[16];
718  $multicurrency_total_tva = $tabprice[17];
719  $multicurrency_total_ttc = $tabprice[18];
720  $pu_ht_devise = $tabprice[19];
721 
722  // Anciens indicateurs: $price, $remise (a ne plus utiliser)
723  $price = $pu;
724  $remise = 0;
725  if ($remise_percent > 0)
726  {
727  $remise = round(($pu * $remise_percent / 100), 2);
728  $price = $pu - $remise;
729  }
730 
731  //Fetch current line from the database and then clone the object and set it in $oldline property
732  $line = new PropaleLigne($this->db);
733  $line->fetch($rowid);
734  $line->fetch_optionals(); // Fetch extrafields for oldcopy
735 
736  $staticline = clone $line;
737 
738  $line->oldline = $staticline;
739  $this->line = $line;
740  $this->line->context = $this->context;
741 
742  // Reorder if fk_parent_line change
743  if (! empty($fk_parent_line) && ! empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line)
744  {
745  $rangmax = $this->line_max($fk_parent_line);
746  $this->line->rang = $rangmax + 1;
747  }
748 
749  $this->line->rowid = $rowid;
750  $this->line->label = $label;
751  $this->line->desc = $desc;
752  $this->line->qty = $qty;
753  $this->line->product_type = $type;
754  $this->line->vat_src_code = $vat_src_code;
755  $this->line->tva_tx = $txtva;
756  $this->line->localtax1_tx = $txlocaltax1;
757  $this->line->localtax2_tx = $txlocaltax2;
758  $this->line->localtax1_type = $localtaxes_type[0];
759  $this->line->localtax2_type = $localtaxes_type[2];
760  $this->line->remise_percent = $remise_percent;
761  $this->line->subprice = $pu_ht;
762  $this->line->info_bits = $info_bits;
763 
764  $this->line->total_ht = $total_ht;
765  $this->line->total_tva = $total_tva;
766  $this->line->total_localtax1 = $total_localtax1;
767  $this->line->total_localtax2 = $total_localtax2;
768  $this->line->total_ttc = $total_ttc;
769  $this->line->special_code = $special_code;
770  $this->line->fk_parent_line = $fk_parent_line;
771  $this->line->skip_update_total = $skip_update_total;
772  $this->line->fk_unit = $fk_unit;
773 
774  $this->line->fk_fournprice = $fk_fournprice;
775  $this->line->pa_ht = $pa_ht;
776 
777  $this->line->date_start=$date_start;
778  $this->line->date_end=$date_end;
779 
780  // TODO deprecated
781  $this->line->price=$price;
782  $this->line->remise=$remise;
783 
784  if (is_array($array_options) && count($array_options)>0) {
785  $this->line->array_options=$array_options;
786  }
787 
788  // Multicurrency
789  $this->line->multicurrency_subprice = $pu_ht_devise;
790  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
791  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
792  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
793 
794  $result=$this->line->update($notrigger);
795  if ($result > 0)
796  {
797  // Reorder if child line
798  if (! empty($fk_parent_line)) $this->line_order(true,'DESC');
799 
800  $this->update_price(1);
801 
802  $this->fk_propal = $this->id;
803  $this->rowid = $rowid;
804 
805  $this->db->commit();
806  return $result;
807  }
808  else
809  {
810  $this->error=$this->line->error;
811 
812  $this->db->rollback();
813  return -1;
814  }
815  }
816  else
817  {
818  dol_syslog(get_class($this)."::updateline Erreur -2 Propal en mode incompatible pour cette action");
819  return -2;
820  }
821  }
822 
823 
830  function deleteline($lineid)
831  {
832  global $user;
833 
834  if ($this->statut == self::STATUS_DRAFT)
835  {
836  $this->db->begin();
837 
838  $line=new PropaleLigne($this->db);
839 
840  // For triggers
841  $line->fetch($lineid);
842 
843  if ($line->delete($user) > 0)
844  {
845  $this->update_price(1);
846 
847  $this->db->commit();
848  return 1;
849  }
850  else
851  {
852  $this->db->rollback();
853  return -1;
854  }
855  }
856  else
857  {
858  $this->error='ErrorDeleteLineNotAllowedByObjectStatus';
859  return -2;
860  }
861  }
862 
863 
872  function create($user, $notrigger=0)
873  {
874  global $conf,$hookmanager;
875  $error=0;
876 
877  $now=dol_now();
878 
879  // Clean parameters
880  if (empty($this->entity)) $this->entity = $conf->entity;
881  if (empty($this->date)) $this->date=$this->datep;
882  $this->fin_validite = $this->date + ($this->duree_validite * 24 * 3600);
883  if (empty($this->availability_id)) $this->availability_id=0;
884  if (empty($this->demand_reason_id)) $this->demand_reason_id=0;
885 
886  // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
887  if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) list($this->fk_multicurrency,$this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $this->date);
888  else $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
889  if (empty($this->fk_multicurrency))
890  {
891  $this->multicurrency_code = $conf->currency;
892  $this->fk_multicurrency = 0;
893  $this->multicurrency_tx = 1;
894  }
895 
896  dol_syslog(get_class($this)."::create");
897 
898  // Check parameters
899  $result=$this->fetch_thirdparty();
900  if ($result < 0)
901  {
902  $this->error="Failed to fetch company";
903  dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
904  return -3;
905  }
906 
907  // Check parameters
908  if (! empty($this->ref)) // We check that ref is not already used
909  {
910  $result=self::isExistingObject($this->element, 0, $this->ref); // Check ref is not yet used
911  if ($result > 0)
912  {
913  $this->error='ErrorRefAlreadyExists';
914  dol_syslog(get_class($this)."::create ".$this->error,LOG_WARNING);
915  $this->db->rollback();
916  return -1;
917  }
918  }
919 
920  if (empty($this->date))
921  {
922  $this->error="Date of proposal is required";
923  dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
924  return -4;
925  }
926 
927 
928  $this->db->begin();
929 
930  // Insert into database
931  $sql = "INSERT INTO ".MAIN_DB_PREFIX."propal (";
932  $sql.= "fk_soc";
933  $sql.= ", price";
934  $sql.= ", remise";
935  $sql.= ", remise_percent";
936  $sql.= ", remise_absolue";
937  $sql.= ", tva";
938  $sql.= ", total";
939  $sql.= ", datep";
940  $sql.= ", datec";
941  $sql.= ", ref";
942  $sql.= ", fk_user_author";
943  $sql.= ", note_private";
944  $sql.= ", note_public";
945  $sql.= ", model_pdf";
946  $sql.= ", fin_validite";
947  $sql.= ", fk_cond_reglement";
948  $sql.= ", fk_mode_reglement";
949  $sql.= ", fk_account";
950  $sql.= ", ref_client";
951  $sql.= ", date_livraison";
952  $sql.= ", fk_shipping_method";
953  $sql.= ", fk_availability";
954  $sql.= ", fk_input_reason";
955  $sql.= ", fk_projet";
956  $sql.= ", fk_incoterms";
957  $sql.= ", location_incoterms";
958  $sql.= ", entity";
959  $sql.= ", fk_multicurrency";
960  $sql.= ", multicurrency_code";
961  $sql.= ", multicurrency_tx";
962  $sql.= ") ";
963  $sql.= " VALUES (";
964  $sql.= $this->socid;
965  $sql.= ", 0";
966  $sql.= ", ".$this->remise;
967  $sql.= ", ".($this->remise_percent?$this->db->escape($this->remise_percent):'NULL');
968  $sql.= ", ".($this->remise_absolue?$this->db->escape($this->remise_absolue):'NULL');
969  $sql.= ", 0";
970  $sql.= ", 0";
971  $sql.= ", '".$this->db->idate($this->date)."'";
972  $sql.= ", '".$this->db->idate($now)."'";
973  $sql.= ", '(PROV)'";
974  $sql.= ", ".($user->id > 0 ? "'".$user->id."'":"NULL");
975  $sql.= ", '".$this->db->escape($this->note_private)."'";
976  $sql.= ", '".$this->db->escape($this->note_public)."'";
977  $sql.= ", '".$this->db->escape($this->modelpdf)."'";
978  $sql.= ", ".($this->fin_validite!=''?"'".$this->db->idate($this->fin_validite)."'":"NULL");
979  $sql.= ", ".($this->cond_reglement_id > 0 ? $this->cond_reglement_id : 'NULL');
980  $sql.= ", ".($this->mode_reglement_id > 0 ? $this->mode_reglement_id : 'NULL');
981  $sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL');
982  $sql.= ", '".$this->db->escape($this->ref_client)."'";
983  $sql.= ", ".($this->date_livraison!=''?"'".$this->db->idate($this->date_livraison)."'":"NULL");
984  $sql.= ", ".($this->shipping_method_id>0?$this->shipping_method_id:'NULL');
985  $sql.= ", ".$this->availability_id;
986  $sql.= ", ".$this->demand_reason_id;
987  $sql.= ", ".($this->fk_project?$this->fk_project:"null");
988  $sql.= ", ".(int) $this->fk_incoterms;
989  $sql.= ", '".$this->db->escape($this->location_incoterms)."'";
990  $sql.= ", ".$this->entity;
991  $sql.= ", ".(int) $this->fk_multicurrency;
992  $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
993  $sql.= ", ".(double) $this->multicurrency_tx;
994  $sql.= ")";
995 
996  dol_syslog(get_class($this)."::create", LOG_DEBUG);
997  $resql=$this->db->query($sql);
998  if ($resql)
999  {
1000  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."propal");
1001 
1002  if ($this->id)
1003  {
1004  $this->ref='(PROV'.$this->id.')';
1005  $sql = 'UPDATE '.MAIN_DB_PREFIX."propal SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".$this->id;
1006 
1007  dol_syslog(get_class($this)."::create", LOG_DEBUG);
1008  $resql=$this->db->query($sql);
1009  if (! $resql) $error++;
1010 
1011  if (! empty($this->linkedObjectsIds) && empty($this->linked_objects)) // To use new linkedObjectsIds instead of old linked_objects
1012  {
1013  $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
1014  }
1015 
1016  // Add object linked
1017  if (! $error && $this->id && is_array($this->linked_objects) && ! empty($this->linked_objects))
1018  {
1019  foreach($this->linked_objects as $origin => $tmp_origin_id)
1020  {
1021  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, ...))
1022  {
1023  foreach($tmp_origin_id as $origin_id)
1024  {
1025  $ret = $this->add_object_linked($origin, $origin_id);
1026  if (! $ret)
1027  {
1028  $this->error=$this->db->lasterror();
1029  $error++;
1030  }
1031  }
1032  }
1033  else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
1034  {
1035  $origin_id = $tmp_origin_id;
1036  $ret = $this->add_object_linked($origin, $origin_id);
1037  if (! $ret)
1038  {
1039  $this->error=$this->db->lasterror();
1040  $error++;
1041  }
1042  }
1043  }
1044  }
1045 
1046  // Add linked object (deprecated, use ->linkedObjectsIds instead)
1047  if (! $error && $this->origin && $this->origin_id)
1048  {
1049  dol_syslog('Deprecated use of linked object, use ->linkedObjectsIds instead', LOG_WARNING);
1050  $ret = $this->add_object_linked();
1051  if (! $ret) dol_print_error($this->db);
1052  }
1053 
1054  /*
1055  * Insertion du detail des produits dans la base
1056  * Insert products detail in database
1057  */
1058  if (! $error)
1059  {
1060  $fk_parent_line=0;
1061  $num=count($this->lines);
1062 
1063  for ($i=0;$i<$num;$i++)
1064  {
1065  if (! is_object($this->lines[$i])) // If this->lines is not array of objects, coming from REST API
1066  { // Convert into object this->lines[$i].
1067  $line = (object) $this->lines[$i];
1068  }
1069  else
1070  {
1071  $line = $this->lines[$i];
1072  }
1073  // Reset fk_parent_line for line that are not child lines or special product
1074  if (($line->product_type != 9 && empty($line->fk_parent_line)) || $line->product_type == 9) {
1075  $fk_parent_line = 0;
1076  }
1077  // Complete vat rate with code
1078  $vatrate = $line->tva_tx;
1079  if ($line->vat_src_code && ! preg_match('/\(.*\)/', $vatrate)) $vatrate.=' ('.$line->vat_src_code.')';
1080 
1081  $result = $this->addline(
1082  $line->desc,
1083  $line->subprice,
1084  $line->qty,
1085  $vatrate,
1086  $line->localtax1_tx,
1087  $line->localtax2_tx,
1088  $line->fk_product,
1089  $line->remise_percent,
1090  'HT',
1091  0,
1092  $line->info_bits,
1093  $line->product_type,
1094  $line->rang,
1095  $line->special_code,
1096  $fk_parent_line,
1097  $line->fk_fournprice,
1098  $line->pa_ht,
1099  $line->label,
1100  $line->date_start,
1101  $line->date_end,
1102  $line->array_options,
1103  $line->fk_unit,
1104  $this->element,
1105  $line->id
1106  );
1107 
1108  if ($result < 0)
1109  {
1110  $error++;
1111  $this->error=$this->db->error;
1112  dol_print_error($this->db);
1113  break;
1114  }
1115  // Defined the new fk_parent_line
1116  if ($result > 0 && $line->product_type == 9) {
1117  $fk_parent_line = $result;
1118  }
1119  }
1120  }
1121 
1122  // Set delivery address
1123  if (! $error && $this->fk_delivery_address)
1124  {
1125  $sql = "UPDATE ".MAIN_DB_PREFIX."propal";
1126  $sql.= " SET fk_delivery_address = ".$this->fk_delivery_address;
1127  $sql.= " WHERE ref = '".$this->db->escape($this->ref)."'";
1128  $sql.= " AND entity = ".$conf->entity;
1129 
1130  $result=$this->db->query($sql);
1131  }
1132 
1133  if (! $error)
1134  {
1135  // Mise a jour infos denormalisees
1136  $resql=$this->update_price(1);
1137  if ($resql)
1138  {
1139  $action='update';
1140 
1141  // Actions on extra fields
1142  if (! $error)
1143  {
1144  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
1145  {
1146  $result=$this->insertExtraFields();
1147  if ($result < 0)
1148  {
1149  $error++;
1150  }
1151  }
1152  }
1153 
1154  if (! $error && ! $notrigger)
1155  {
1156  // Call trigger
1157  $result=$this->call_trigger('PROPAL_CREATE',$user);
1158  if ($result < 0) { $error++; }
1159  // End call triggers
1160  }
1161  }
1162  else
1163  {
1164  $this->error=$this->db->lasterror();
1165  $error++;
1166  }
1167  }
1168  }
1169  else
1170  {
1171  $this->error=$this->db->lasterror();
1172  $error++;
1173  }
1174 
1175  if (! $error)
1176  {
1177  $this->db->commit();
1178  dol_syslog(get_class($this)."::create done id=".$this->id);
1179  return $this->id;
1180  }
1181  else
1182  {
1183  $this->db->rollback();
1184  return -2;
1185  }
1186  }
1187  else
1188  {
1189  $this->error=$this->db->lasterror();
1190  $this->db->rollback();
1191  return -1;
1192  }
1193  }
1194 
1195 
1196  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1204  function create_from($user)
1205  {
1206  // phpcs:enable
1207  // i love this function because $this->products is not used in create function...
1208  $this->products=$this->lines;
1209 
1210  return $this->create($user);
1211  }
1212 
1219  function createFromClone($socid=0)
1220  {
1221  global $user,$conf,$hookmanager;
1222 
1223  dol_include_once('/projet/class/project.class.php');
1224 
1225  $error=0;
1226  $now=dol_now();
1227 
1228  dol_syslog(__METHOD__, LOG_DEBUG);
1229 
1230  $object = new self($this->db);
1231 
1232  $this->db->begin();
1233 
1234  // Load source object
1235  $object->fetch($this->id);
1236  $object->fetch_lines();
1237 
1238  $objsoc=new Societe($this->db);
1239 
1240  // Change socid if needed
1241  if (! empty($socid) && $socid != $object->socid)
1242  {
1243  if ($objsoc->fetch($socid) > 0)
1244  {
1245  $object->socid = $objsoc->id;
1246  $object->cond_reglement_id = (! empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
1247  $object->mode_reglement_id = (! empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
1248  $object->fk_delivery_address = '';
1249 
1250  /*if (!empty($conf->projet->enabled))
1251  {
1252  $project = new Project($db);
1253  if ($this->fk_project > 0 && $project->fetch($this->fk_project)) {
1254  if ($project->socid <= 0) $clonedObj->fk_project = $this->fk_project;
1255  else $clonedObj->fk_project = '';
1256  } else {
1257  $clonedObj->fk_project = '';
1258  }
1259  }*/
1260  $object->fk_project = ''; // A cloned proposal is set by default to no project.
1261  }
1262 
1263  // reset ref_client
1264  $object->ref_client = '';
1265 
1266  // TODO Change product price if multi-prices
1267  }
1268  else
1269  {
1270  $objsoc->fetch($object->socid);
1271  }
1272 
1273  $object->id=0;
1274  $object->ref='';
1275  $object->statut=self::STATUS_DRAFT;
1276 
1277  // Clear fields
1278  $object->user_author = $user->id;
1279  $object->user_valid = '';
1280  $object->date = $now;
1281  $object->datep = $now; // deprecated
1282  $object->fin_validite = $object->date + ($object->duree_validite * 24 * 3600);
1283  if (empty($conf->global->MAIN_KEEP_REF_CUSTOMER_ON_CLONING)) $object->ref_client = '';
1284 
1285  // Create clone
1286  $object->context['createfromclone']='createfromclone';
1287  $result=$object->create($user);
1288  if ($result < 0)
1289  {
1290  $this->error = $object->error;
1291  $this->errors = array_merge($this->errors, $object->errors);
1292  $error++;
1293  }
1294 
1295  if (! $error)
1296  {
1297  // copy internal contacts
1298  if ($object->copy_linked_contact($this, 'internal') < 0)
1299  {
1300  $error++;
1301  }
1302  }
1303 
1304  if (! $error)
1305  {
1306  // copy external contacts if same company
1307  if ($this->socid == $object->socid)
1308  {
1309  if ($object->copy_linked_contact($this, 'external') < 0)
1310  $error++;
1311  }
1312  }
1313 
1314  if (! $error)
1315  {
1316  // Hook of thirdparty module
1317  if (is_object($hookmanager))
1318  {
1319  $parameters=array('objFrom'=>$this,'clonedObj'=>$clonedObj);
1320  $action='';
1321  $reshook=$hookmanager->executeHooks('createFrom',$parameters,$clonedObj,$action); // Note that $action and $object may have been modified by some hooks
1322  if ($reshook < 0) $error++;
1323  }
1324  }
1325 
1326  unset($object->context['createfromclone']);
1327 
1328  // End
1329  if (! $error)
1330  {
1331  $this->db->commit();
1332  return $object->id;
1333  }
1334  else
1335  {
1336  $this->db->rollback();
1337  return -1;
1338  }
1339  }
1340 
1348  function fetch($rowid,$ref='')
1349  {
1350 
1351  $sql = "SELECT p.rowid, p.ref, p.entity, p.remise, p.remise_percent, p.remise_absolue, p.fk_soc";
1352  $sql.= ", p.total, p.tva, p.localtax1, p.localtax2, p.total_ht";
1353  $sql.= ", p.datec";
1354  $sql.= ", p.date_valid as datev";
1355  $sql.= ", p.datep as dp";
1356  $sql.= ", p.fin_validite as dfv";
1357  $sql.= ", p.date_livraison as date_livraison";
1358  $sql.= ", p.model_pdf, p.last_main_doc, p.ref_client, p.extraparams";
1359  $sql.= ", p.note_private, p.note_public";
1360  $sql.= ", p.fk_projet, p.fk_statut";
1361  $sql.= ", p.fk_user_author, p.fk_user_valid, p.fk_user_cloture";
1362  $sql.= ", p.fk_delivery_address";
1363  $sql.= ", p.fk_availability";
1364  $sql.= ", p.fk_input_reason";
1365  $sql.= ", p.fk_cond_reglement";
1366  $sql.= ", p.fk_mode_reglement";
1367  $sql.= ', p.fk_account';
1368  $sql.= ", p.fk_shipping_method";
1369  $sql.= ", p.fk_incoterms, p.location_incoterms";
1370  $sql.= ", p.fk_multicurrency, p.multicurrency_code, p.multicurrency_tx, p.multicurrency_total_ht, p.multicurrency_total_tva, p.multicurrency_total_ttc";
1371  $sql.= ", p.tms as date_modification";
1372  $sql.= ", i.libelle as libelle_incoterms";
1373  $sql.= ", c.label as statut_label";
1374  $sql.= ", ca.code as availability_code, ca.label as availability";
1375  $sql.= ", dr.code as demand_reason_code, dr.label as demand_reason";
1376  $sql.= ", cr.code as cond_reglement_code, cr.libelle as cond_reglement, cr.libelle_facture as cond_reglement_libelle_doc";
1377  $sql.= ", cp.code as mode_reglement_code, cp.libelle as mode_reglement";
1378  $sql.= " FROM ".MAIN_DB_PREFIX."propal as p";
1379  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_propalst as c ON p.fk_statut = c.id';
1380  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as cp ON p.fk_mode_reglement = cp.id AND cp.entity IN ('.getEntity('c_paiement').')';
1381  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON p.fk_cond_reglement = cr.rowid AND cr.entity IN ('.getEntity('c_payment_term').')';
1382  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_availability as ca ON p.fk_availability = ca.rowid';
1383  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_input_reason as dr ON p.fk_input_reason = dr.rowid';
1384  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON p.fk_incoterms = i.rowid';
1385 
1386  if ($ref) {
1387  $sql.= " WHERE p.entity IN (".getEntity('propal').")"; // Dont't use entity if you use rowid
1388  $sql.= " AND p.ref='".$this->db->escape($ref)."'";
1389  }
1390  else $sql.= " WHERE p.rowid=".$rowid;
1391 
1392  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1393  $resql=$this->db->query($sql);
1394  if ($resql)
1395  {
1396  if ($this->db->num_rows($resql))
1397  {
1398  $obj = $this->db->fetch_object($resql);
1399 
1400  $this->id = $obj->rowid;
1401  $this->entity = $obj->entity;
1402 
1403  $this->ref = $obj->ref;
1404  $this->ref_client = $obj->ref_client;
1405  $this->remise = $obj->remise;
1406  $this->remise_percent = $obj->remise_percent;
1407  $this->remise_absolue = $obj->remise_absolue;
1408  $this->total = $obj->total; // TODO deprecated
1409  $this->total_ht = $obj->total_ht;
1410  $this->total_tva = $obj->tva;
1411  $this->total_localtax1 = $obj->localtax1;
1412  $this->total_localtax2 = $obj->localtax2;
1413  $this->total_ttc = $obj->total;
1414  $this->socid = $obj->fk_soc;
1415  $this->fk_project = $obj->fk_projet;
1416  $this->modelpdf = $obj->model_pdf;
1417  $this->last_main_doc = $obj->last_main_doc;
1418  $this->note = $obj->note_private; // TODO deprecated
1419  $this->note_private = $obj->note_private;
1420  $this->note_public = $obj->note_public;
1421  $this->statut = (int) $obj->fk_statut;
1422  $this->statut_libelle = $obj->statut_label;
1423 
1424  $this->datec = $this->db->jdate($obj->datec); // TODO deprecated
1425  $this->datev = $this->db->jdate($obj->datev); // TODO deprecated
1426  $this->date_creation = $this->db->jdate($obj->datec); //Creation date
1427  $this->date_validation = $this->db->jdate($obj->datev); //Validation date
1428  $this->date_modification = $this->db->jdate($obj->date_modification); // tms
1429  $this->date = $this->db->jdate($obj->dp); // Proposal date
1430  $this->datep = $this->db->jdate($obj->dp); // deprecated
1431  $this->fin_validite = $this->db->jdate($obj->dfv);
1432  $this->date_livraison = $this->db->jdate($obj->date_livraison);
1433  $this->shipping_method_id = ($obj->fk_shipping_method>0)?$obj->fk_shipping_method:null;
1434  $this->availability_id = $obj->fk_availability;
1435  $this->availability_code = $obj->availability_code;
1436  $this->availability = $obj->availability;
1437  $this->demand_reason_id = $obj->fk_input_reason;
1438  $this->demand_reason_code = $obj->demand_reason_code;
1439  $this->demand_reason = $obj->demand_reason;
1440  $this->fk_address = $obj->fk_delivery_address;
1441 
1442  $this->mode_reglement_id = $obj->fk_mode_reglement;
1443  $this->mode_reglement_code = $obj->mode_reglement_code;
1444  $this->mode_reglement = $obj->mode_reglement;
1445  $this->fk_account = ($obj->fk_account>0)?$obj->fk_account:null;
1446  $this->cond_reglement_id = $obj->fk_cond_reglement;
1447  $this->cond_reglement_code = $obj->cond_reglement_code;
1448  $this->cond_reglement = $obj->cond_reglement;
1449  $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
1450 
1451  $this->extraparams = (array) json_decode($obj->extraparams, true);
1452 
1453  $this->user_author_id = $obj->fk_user_author;
1454  $this->user_valid_id = $obj->fk_user_valid;
1455  $this->user_close_id = $obj->fk_user_cloture;
1456 
1457  //Incoterms
1458  $this->fk_incoterms = $obj->fk_incoterms;
1459  $this->location_incoterms = $obj->location_incoterms;
1460  $this->libelle_incoterms = $obj->libelle_incoterms;
1461 
1462  // Multicurrency
1463  $this->fk_multicurrency = $obj->fk_multicurrency;
1464  $this->multicurrency_code = $obj->multicurrency_code;
1465  $this->multicurrency_tx = $obj->multicurrency_tx;
1466  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
1467  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
1468  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
1469 
1470  if ($obj->fk_statut == self::STATUS_DRAFT)
1471  {
1472  $this->brouillon = 1;
1473  }
1474 
1475  // Retreive all extrafield
1476  // fetch optionals attributes and labels
1477  $this->fetch_optionals();
1478 
1479  $this->db->free($resql);
1480 
1481  $this->lines = array();
1482 
1483  /*
1484  * Lines
1485  */
1486  $result=$this->fetch_lines();
1487  if ($result < 0)
1488  {
1489  return -3;
1490  }
1491 
1492  return 1;
1493  }
1494 
1495  $this->error="Record Not Found";
1496  return 0;
1497  }
1498  else
1499  {
1500  $this->error=$this->db->lasterror();
1501  return -1;
1502  }
1503  }
1504 
1512  function update(User $user, $notrigger=0)
1513  {
1514  global $conf;
1515 
1516  $error=0;
1517 
1518  // Clean parameters
1519  if (isset($this->ref)) $this->ref=trim($this->ref);
1520  if (isset($this->ref_client)) $this->ref_client=trim($this->ref_client);
1521  if (isset($this->note) || isset($this->note_private)) $this->note_private=(isset($this->note_private) ? trim($this->note_private) : trim($this->note));
1522  if (isset($this->note_public)) $this->note_public=trim($this->note_public);
1523  if (isset($this->modelpdf)) $this->modelpdf=trim($this->modelpdf);
1524  if (isset($this->import_key)) $this->import_key=trim($this->import_key);
1525 
1526  // Check parameters
1527  // Put here code to add control on parameters values
1528 
1529  // Update request
1530  $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET";
1531 
1532  $sql.= " ref=".(isset($this->ref)?"'".$this->db->escape($this->ref)."'":"null").",";
1533  $sql.= " ref_client=".(isset($this->ref_client)?"'".$this->db->escape($this->ref_client)."'":"null").",";
1534  $sql.= " ref_ext=".(isset($this->ref_ext)?"'".$this->db->escape($this->ref_ext)."'":"null").",";
1535  $sql.= " fk_soc=".(isset($this->socid)?$this->socid:"null").",";
1536  $sql.= " datep=".(strval($this->datep)!='' ? "'".$this->db->idate($this->datep)."'" : 'null').",";
1537  $sql.= " date_valid=".(strval($this->date_validation)!='' ? "'".$this->db->idate($this->date_validation)."'" : 'null').",";
1538  $sql.= " tva=".(isset($this->total_tva)?$this->total_tva:"null").",";
1539  $sql.= " localtax1=".(isset($this->total_localtax1)?$this->total_localtax1:"null").",";
1540  $sql.= " localtax2=".(isset($this->total_localtax2)?$this->total_localtax2:"null").",";
1541  $sql.= " total_ht=".(isset($this->total_ht)?$this->total_ht:"null").",";
1542  $sql.= " total=".(isset($this->total_ttc)?$this->total_ttc:"null").",";
1543  $sql.= " fk_statut=".(isset($this->statut)?$this->statut:"null").",";
1544  $sql.= " fk_user_author=".(isset($this->user_author_id)?$this->user_author_id:"null").",";
1545  $sql.= " fk_user_valid=".(isset($this->user_valid)?$this->user_valid:"null").",";
1546  $sql.= " fk_projet=".(isset($this->fk_project)?$this->fk_project:"null").",";
1547  $sql.= " fk_cond_reglement=".(isset($this->cond_reglement_id)?$this->cond_reglement_id:"null").",";
1548  $sql.= " fk_mode_reglement=".(isset($this->mode_reglement_id)?$this->mode_reglement_id:"null").",";
1549  $sql.= " note_private=".(isset($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null").",";
1550  $sql.= " note_public=".(isset($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null").",";
1551  $sql.= " model_pdf=".(isset($this->modelpdf)?"'".$this->db->escape($this->modelpdf)."'":"null").",";
1552  $sql.= " import_key=".(isset($this->import_key)?"'".$this->db->escape($this->import_key)."'":"null")."";
1553 
1554  $sql.= " WHERE rowid=".$this->id;
1555 
1556  $this->db->begin();
1557 
1558  dol_syslog(get_class($this)."::update", LOG_DEBUG);
1559  $resql = $this->db->query($sql);
1560  if (! $resql) {
1561  $error++; $this->errors[]="Error ".$this->db->lasterror();
1562  }
1563 
1564  if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options)>0)
1565  {
1566  $result=$this->insertExtraFields();
1567  if ($result < 0)
1568  {
1569  $error++;
1570  }
1571  }
1572 
1573  if (! $error && ! $notrigger)
1574  {
1575  // Call trigger
1576  $result=$this->call_trigger('PROPAL_MODIFY', $user);
1577  if ($result < 0) $error++;
1578  // End call triggers
1579  }
1580 
1581  // Commit or rollback
1582  if ($error)
1583  {
1584  foreach($this->errors as $errmsg)
1585  {
1586  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
1587  $this->error.=($this->error?', '.$errmsg:$errmsg);
1588  }
1589  $this->db->rollback();
1590  return -1*$error;
1591  }
1592  else
1593  {
1594  $this->db->commit();
1595  return 1;
1596  }
1597  }
1598 
1599 
1600  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1607  function fetch_lines($only_product=0)
1608  {
1609  // phpcs:enable
1610  $this->lines=array();
1611 
1612  $sql = 'SELECT d.rowid, d.fk_propal, d.fk_parent_line, d.label as custom_label, d.description, d.price, d.vat_src_code, d.tva_tx, d.localtax1_tx, d.localtax2_tx, d.localtax1_type, d.localtax2_type, d.qty, d.fk_remise_except, d.remise_percent, d.subprice, d.fk_product,';
1613  $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,';
1614  $sql.= ' d.fk_unit,';
1615  $sql.= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label, p.tobatch as product_batch,';
1616  $sql.= ' p.weight, p.weight_units, p.volume, p.volume_units,';
1617  $sql.= ' d.date_start, d.date_end,';
1618  $sql.= ' d.fk_multicurrency, d.multicurrency_code, d.multicurrency_subprice, d.multicurrency_total_ht, d.multicurrency_total_tva, d.multicurrency_total_ttc';
1619  $sql.= ' FROM '.MAIN_DB_PREFIX.'propaldet as d';
1620  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON (d.fk_product = p.rowid)';
1621  $sql.= ' WHERE d.fk_propal = '.$this->id;
1622  if ($only_product) $sql .= ' AND p.fk_product_type = 0';
1623  $sql.= ' ORDER by d.rang';
1624 
1625  dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
1626  $result = $this->db->query($sql);
1627  if ($result)
1628  {
1629  require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
1630 
1631  $num = $this->db->num_rows($result);
1632 
1633  $i = 0;
1634  while ($i < $num)
1635  {
1636  $objp = $this->db->fetch_object($result);
1637 
1638  $line = new PropaleLigne($this->db);
1639 
1640  $line->rowid = $objp->rowid; //Deprecated
1641  $line->id = $objp->rowid;
1642  $line->fk_propal = $objp->fk_propal;
1643  $line->fk_parent_line = $objp->fk_parent_line;
1644  $line->product_type = $objp->product_type;
1645  $line->label = $objp->custom_label;
1646  $line->desc = $objp->description; // Description ligne
1647  $line->description = $objp->description; // Description ligne
1648  $line->qty = $objp->qty;
1649  $line->vat_src_code = $objp->vat_src_code;
1650  $line->tva_tx = $objp->tva_tx;
1651  $line->localtax1_tx = $objp->localtax1_tx;
1652  $line->localtax2_tx = $objp->localtax2_tx;
1653  $line->localtax1_type = $objp->localtax1_type;
1654  $line->localtax2_type = $objp->localtax2_type;
1655  $line->subprice = $objp->subprice;
1656  $line->fk_remise_except = $objp->fk_remise_except;
1657  $line->remise_percent = $objp->remise_percent;
1658  $line->price = $objp->price; // TODO deprecated
1659 
1660  $line->info_bits = $objp->info_bits;
1661  $line->total_ht = $objp->total_ht;
1662  $line->total_tva = $objp->total_tva;
1663  $line->total_localtax1 = $objp->total_localtax1;
1664  $line->total_localtax2 = $objp->total_localtax2;
1665  $line->total_ttc = $objp->total_ttc;
1666  $line->fk_fournprice = $objp->fk_fournprice;
1667  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
1668  $line->pa_ht = $marginInfos[0];
1669  $line->marge_tx = $marginInfos[1];
1670  $line->marque_tx = $marginInfos[2];
1671  $line->special_code = $objp->special_code;
1672  $line->rang = $objp->rang;
1673 
1674  $line->fk_product = $objp->fk_product;
1675 
1676  $line->ref = $objp->product_ref; // TODO deprecated
1677  $line->product_ref = $objp->product_ref;
1678  $line->libelle = $objp->product_label; // TODO deprecated
1679  $line->product_label = $objp->product_label;
1680  $line->product_desc = $objp->product_desc; // Description produit
1681  $line->product_tobatch = $objp->product_tobatch;
1682  $line->fk_product_type = $objp->fk_product_type; // TODO deprecated
1683  $line->fk_unit = $objp->fk_unit;
1684  $line->weight = $objp->weight;
1685  $line->weight_units = $objp->weight_units;
1686  $line->volume = $objp->volume;
1687  $line->volume_units = $objp->volume_units;
1688 
1689  $line->date_start = $this->db->jdate($objp->date_start);
1690  $line->date_end = $this->db->jdate($objp->date_end);
1691 
1692  // Multicurrency
1693  $line->fk_multicurrency = $objp->fk_multicurrency;
1694  $line->multicurrency_code = $objp->multicurrency_code;
1695  $line->multicurrency_subprice = $objp->multicurrency_subprice;
1696  $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
1697  $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
1698  $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
1699 
1700  $line->fetch_optionals();
1701 
1702  $this->lines[$i] = $line;
1703  //dol_syslog("1 ".$line->fk_product);
1704  //print "xx $i ".$this->lines[$i]->fk_product;
1705  $i++;
1706  }
1707 
1708  $this->db->free($result);
1709 
1710  return $num;
1711  }
1712  else
1713  {
1714  $this->error=$this->db->lasterror();
1715  return -3;
1716  }
1717  }
1718 
1726  function valid($user, $notrigger=0)
1727  {
1728  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1729 
1730  global $conf;
1731 
1732  $error=0;
1733 
1734  // Protection
1735  if ($this->statut == self::STATUS_VALIDATED)
1736  {
1737  dol_syslog(get_class($this)."::valid action abandonned: already validated", LOG_WARNING);
1738  return 0;
1739  }
1740 
1741  if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->propal->creer))
1742  || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->propal->propal_advance->validate))))
1743  {
1744  $this->error='ErrorPermissionDenied';
1745  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
1746  return -1;
1747  }
1748 
1749  $now=dol_now();
1750 
1751  $this->db->begin();
1752 
1753  // Numbering module definition
1754  $soc = new Societe($this->db);
1755  $soc->fetch($this->socid);
1756 
1757  // Define new ref
1758  if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life
1759  {
1760  $num = $this->getNextNumRef($soc);
1761  }
1762  else
1763  {
1764  $num = $this->ref;
1765  }
1766  $this->newref = $num;
1767 
1768  $sql = "UPDATE ".MAIN_DB_PREFIX."propal";
1769  $sql.= " SET ref = '".$num."',";
1770  $sql.= " fk_statut = ".self::STATUS_VALIDATED.", date_valid='".$this->db->idate($now)."', fk_user_valid=".$user->id;
1771  $sql.= " WHERE rowid = ".$this->id." AND fk_statut = ".self::STATUS_DRAFT;
1772 
1773  dol_syslog(get_class($this)."::valid", LOG_DEBUG);
1774  $resql=$this->db->query($sql);
1775  if (! $resql)
1776  {
1777  dol_print_error($this->db);
1778  $error++;
1779  }
1780 
1781  // Trigger calls
1782  if (! $error && ! $notrigger)
1783  {
1784  // Call trigger
1785  $result=$this->call_trigger('PROPAL_VALIDATE',$user);
1786  if ($result < 0) { $error++; }
1787  // End call triggers
1788  }
1789 
1790  if (! $error)
1791  {
1792  $this->oldref = $this->ref;
1793 
1794  // Rename directory if dir was a temporary ref
1795  if (preg_match('/^[\(]?PROV/i', $this->ref))
1796  {
1797  // Rename of propal directory ($this->ref = old ref, $num = new ref)
1798  // to not lose the linked files
1799  $oldref = dol_sanitizeFileName($this->ref);
1800  $newref = dol_sanitizeFileName($num);
1801  $dirsource = $conf->propal->multidir_output[$this->entity].'/'.$oldref;
1802  $dirdest = $conf->propal->multidir_output[$this->entity].'/'.$newref;
1803 
1804  if (file_exists($dirsource))
1805  {
1806  dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest);
1807  if (@rename($dirsource, $dirdest))
1808  {
1809  dol_syslog("Rename ok");
1810  // Rename docs starting with $oldref with $newref
1811  $listoffiles=dol_dir_list($dirdest, 'files', 1, '^'.preg_quote($oldref,'/'));
1812  foreach($listoffiles as $fileentry)
1813  {
1814  $dirsource=$fileentry['name'];
1815  $dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource);
1816  $dirsource=$fileentry['path'].'/'.$dirsource;
1817  $dirdest=$fileentry['path'].'/'.$dirdest;
1818  @rename($dirsource, $dirdest);
1819  }
1820  }
1821  }
1822  }
1823 
1824  $this->ref=$num;
1825  $this->brouillon=0;
1826  $this->statut = self::STATUS_VALIDATED;
1827  $this->user_valid_id=$user->id;
1828  $this->datev=$now;
1829 
1830  $this->db->commit();
1831  return 1;
1832  }
1833  else
1834  {
1835  $this->db->rollback();
1836  return -1;
1837  }
1838  }
1839 
1840 
1841  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1850  function set_date($user, $date, $notrigger=0)
1851  {
1852  // phpcs:enable
1853  if (empty($date))
1854  {
1855  $this->error='ErrorBadParameter';
1856  dol_syslog(get_class($this)."::set_date ".$this->error, LOG_ERR);
1857  return -1;
1858  }
1859 
1860  if (! empty($user->rights->propal->creer))
1861  {
1862  $error=0;
1863 
1864  $this->db->begin();
1865 
1866  $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET datep = '".$this->db->idate($date)."'";
1867  $sql.= " WHERE rowid = ".$this->id." AND fk_statut = ".self::STATUS_DRAFT;
1868 
1869  dol_syslog(__METHOD__, LOG_DEBUG);
1870  $resql=$this->db->query($sql);
1871  if (!$resql)
1872  {
1873  $this->errors[]=$this->db->error();
1874  $error++;
1875  }
1876 
1877  if (! $error)
1878  {
1879  $this->oldcopy= clone $this;
1880  $this->date = $date;
1881  $this->datep = $date; // deprecated
1882  }
1883 
1884  if (! $notrigger && empty($error))
1885  {
1886  // Call trigger
1887  $result=$this->call_trigger('PROPAL_MODIFY',$user);
1888  if ($result < 0) $error++;
1889  // End call triggers
1890  }
1891 
1892  if (! $error)
1893  {
1894  $this->db->commit();
1895  return 1;
1896  }
1897  else
1898  {
1899  foreach($this->errors as $errmsg)
1900  {
1901  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
1902  $this->error.=($this->error?', '.$errmsg:$errmsg);
1903  }
1904  $this->db->rollback();
1905  return -1*$error;
1906  }
1907  }
1908  }
1909 
1910  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1919  function set_echeance($user, $date_fin_validite, $notrigger=0)
1920  {
1921  // phpcs:enable
1922  if (! empty($user->rights->propal->creer))
1923  {
1924  $error=0;
1925 
1926  $this->db->begin();
1927 
1928  $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET fin_validite = ".($date_fin_validite!=''?"'".$this->db->idate($date_fin_validite)."'":'null');
1929  $sql.= " WHERE rowid = ".$this->id." AND fk_statut = ".self::STATUS_DRAFT;
1930 
1931  dol_syslog(__METHOD__, LOG_DEBUG);
1932  $resql=$this->db->query($sql);
1933  if (!$resql)
1934  {
1935  $this->errors[]=$this->db->error();
1936  $error++;
1937  }
1938 
1939 
1940  if (! $error)
1941  {
1942  $this->oldcopy= clone $this;
1943  $this->fin_validite = $date_fin_validite;
1944  }
1945 
1946  if (! $notrigger && empty($error))
1947  {
1948  // Call trigger
1949  $result=$this->call_trigger('PROPAL_MODIFY',$user);
1950  if ($result < 0) $error++;
1951  // End call triggers
1952  }
1953 
1954  if (! $error)
1955  {
1956  $this->db->commit();
1957  return 1;
1958  }
1959  else
1960  {
1961  foreach($this->errors as $errmsg)
1962  {
1963  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
1964  $this->error.=($this->error?', '.$errmsg:$errmsg);
1965  }
1966  $this->db->rollback();
1967  return -1*$error;
1968  }
1969  }
1970  }
1971 
1972  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1981  function set_date_livraison($user, $date_livraison, $notrigger=0)
1982  {
1983  // phpcs:enable
1984  if (! empty($user->rights->propal->creer))
1985  {
1986  $error=0;
1987 
1988  $this->db->begin();
1989 
1990  $sql = "UPDATE ".MAIN_DB_PREFIX."propal ";
1991  $sql.= " SET date_livraison = ".($date_livraison!=''?"'".$this->db->idate($date_livraison)."'":'null');
1992  $sql.= " WHERE rowid = ".$this->id;
1993 
1994  dol_syslog(__METHOD__, LOG_DEBUG);
1995  $resql=$this->db->query($sql);
1996  if (!$resql)
1997  {
1998  $this->errors[]=$this->db->error();
1999  $error++;
2000  }
2001 
2002  if (! $error)
2003  {
2004  $this->oldcopy= clone $this;
2005  $this->date_livraison = $date_livraison;
2006  }
2007 
2008  if (! $notrigger && empty($error))
2009  {
2010  // Call trigger
2011  $result=$this->call_trigger('PROPAL_MODIFY',$user);
2012  if ($result < 0) $error++;
2013  // End call triggers
2014  }
2015 
2016  if (! $error)
2017  {
2018  $this->db->commit();
2019  return 1;
2020  }
2021  else
2022  {
2023  foreach($this->errors as $errmsg)
2024  {
2025  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2026  $this->error.=($this->error?', '.$errmsg:$errmsg);
2027  }
2028  $this->db->rollback();
2029  return -1*$error;
2030  }
2031  }
2032  }
2033 
2034  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2043  function set_availability($user, $id, $notrigger=0)
2044  {
2045  // phpcs:enable
2046  if (! empty($user->rights->propal->creer) && $this->statut >= self::STATUS_DRAFT)
2047  {
2048  $error=0;
2049 
2050  $this->db->begin();
2051 
2052  $sql = "UPDATE ".MAIN_DB_PREFIX."propal ";
2053  $sql.= " SET fk_availability = '".$id."'";
2054  $sql.= " WHERE rowid = ".$this->id;
2055 
2056  dol_syslog(__METHOD__.' availability('.$id.')', LOG_DEBUG);
2057  $resql=$this->db->query($sql);
2058  if (!$resql)
2059  {
2060  $this->errors[]=$this->db->error();
2061  $error++;
2062  }
2063 
2064  if (! $error)
2065  {
2066  $this->oldcopy= clone $this;
2067  $this->fk_availability = $id;
2068  $this->availability_id = $id;
2069  }
2070 
2071  if (! $notrigger && empty($error))
2072  {
2073  // Call trigger
2074  $result=$this->call_trigger('PROPAL_MODIFY',$user);
2075  if ($result < 0) $error++;
2076  // End call triggers
2077  }
2078 
2079  if (! $error)
2080  {
2081  $this->db->commit();
2082  return 1;
2083  }
2084  else
2085  {
2086  foreach($this->errors as $errmsg)
2087  {
2088  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2089  $this->error.=($this->error?', '.$errmsg:$errmsg);
2090  }
2091  $this->db->rollback();
2092  return -1*$error;
2093  }
2094  }
2095  else
2096  {
2097  $error_str='Propal status do not meet requirement '.$this->statut;
2098  dol_syslog(__METHOD__.$error_str, LOG_ERR);
2099  $this->error=$error_str;
2100  $this->errors[]= $this->error;
2101  return -2;
2102  }
2103  }
2104 
2105  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2114  function set_demand_reason($user, $id, $notrigger=0)
2115  {
2116  // phpcs:enable
2117  if (! empty($user->rights->propal->creer) && $this->statut >= self::STATUS_DRAFT)
2118  {
2119  $error=0;
2120 
2121  $this->db->begin();
2122 
2123  $sql = "UPDATE ".MAIN_DB_PREFIX."propal ";
2124  $sql.= " SET fk_input_reason = ".$id;
2125  $sql.= " WHERE rowid = ".$this->id;
2126 
2127  dol_syslog(__METHOD__, LOG_DEBUG);
2128  $resql=$this->db->query($sql);
2129  if (!$resql)
2130  {
2131  $this->errors[]=$this->db->error();
2132  $error++;
2133  }
2134 
2135 
2136  if (! $error)
2137  {
2138  $this->oldcopy= clone $this;
2139  $this->fk_input_reason = $id;
2140  $this->demand_reason_id = $id;
2141  }
2142 
2143 
2144  if (! $notrigger && empty($error))
2145  {
2146  // Call trigger
2147  $result=$this->call_trigger('PROPAL_MODIFY',$user);
2148  if ($result < 0) $error++;
2149  // End call triggers
2150  }
2151 
2152  if (! $error)
2153  {
2154  $this->db->commit();
2155  return 1;
2156  }
2157  else
2158  {
2159  foreach($this->errors as $errmsg)
2160  {
2161  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2162  $this->error.=($this->error?', '.$errmsg:$errmsg);
2163  }
2164  $this->db->rollback();
2165  return -1*$error;
2166  }
2167  }
2168  else
2169  {
2170  $error_str='Propal status do not meet requirement '.$this->statut;
2171  dol_syslog(__METHOD__.$error_str, LOG_ERR);
2172  $this->error=$error_str;
2173  $this->errors[]= $this->error;
2174  return -2;
2175  }
2176  }
2177 
2178  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2187  function set_ref_client($user, $ref_client, $notrigger=0)
2188  {
2189  // phpcs:enable
2190  if (! empty($user->rights->propal->creer))
2191  {
2192  $error=0;
2193 
2194  $this->db->begin();
2195 
2196  $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal SET ref_client = '.(empty($ref_client) ? 'NULL' : '\''.$this->db->escape($ref_client).'\'');
2197  $sql.= ' WHERE rowid = '.$this->id;
2198 
2199  dol_syslog(__METHOD__.' $this->id='.$this->id.', ref_client='.$ref_client, LOG_DEBUG);
2200  $resql=$this->db->query($sql);
2201  if (!$resql)
2202  {
2203  $this->errors[]=$this->db->error();
2204  $error++;
2205  }
2206 
2207  if (! $error)
2208  {
2209  $this->oldcopy= clone $this;
2210  $this->ref_client = $ref_client;
2211  }
2212 
2213  if (! $notrigger && empty($error))
2214  {
2215  // Call trigger
2216  $result=$this->call_trigger('PROPAL_MODIFY',$user);
2217  if ($result < 0) $error++;
2218  // End call triggers
2219  }
2220 
2221  if (! $error)
2222  {
2223  $this->db->commit();
2224  return 1;
2225  }
2226  else
2227  {
2228  foreach($this->errors as $errmsg)
2229  {
2230  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2231  $this->error.=($this->error?', '.$errmsg:$errmsg);
2232  }
2233  $this->db->rollback();
2234  return -1*$error;
2235  }
2236  }
2237  else
2238  {
2239  return -1;
2240  }
2241  }
2242 
2243  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2252  function set_remise_percent($user, $remise, $notrigger=0)
2253  {
2254  // phpcs:enable
2255  $remise=trim($remise)?trim($remise):0;
2256 
2257  if (! empty($user->rights->propal->creer))
2258  {
2259  $remise = price2num($remise);
2260 
2261  $error=0;
2262 
2263  $this->db->begin();
2264 
2265  $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET remise_percent = ".$remise;
2266  $sql.= " WHERE rowid = ".$this->id." AND fk_statut = ".self::STATUS_DRAFT;
2267 
2268  dol_syslog(__METHOD__, LOG_DEBUG);
2269  $resql=$this->db->query($sql);
2270  if (!$resql)
2271  {
2272  $this->errors[]=$this->db->error();
2273  $error++;
2274  }
2275 
2276  if (! $error)
2277  {
2278  $this->oldcopy= clone $this;
2279  $this->remise_percent = $remise;
2280  $this->update_price(1);
2281  }
2282 
2283  if (! $notrigger && empty($error))
2284  {
2285  // Call trigger
2286  $result=$this->call_trigger('PROPAL_MODIFY',$user);
2287  if ($result < 0) $error++;
2288  // End call triggers
2289  }
2290 
2291  if (! $error)
2292  {
2293  $this->db->commit();
2294  return 1;
2295  }
2296  else
2297  {
2298  foreach($this->errors as $errmsg)
2299  {
2300  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2301  $this->error.=($this->error?', '.$errmsg:$errmsg);
2302  }
2303  $this->db->rollback();
2304  return -1*$error;
2305  }
2306  }
2307  }
2308 
2309 
2310  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2319  function set_remise_absolue($user, $remise, $notrigger=0)
2320  {
2321  // phpcs:enable
2322  $remise=trim($remise)?trim($remise):0;
2323 
2324  if (! empty($user->rights->propal->creer))
2325  {
2326  $remise = price2num($remise);
2327 
2328  $error=0;
2329 
2330  $this->db->begin();
2331 
2332  $sql = "UPDATE ".MAIN_DB_PREFIX."propal ";
2333  $sql.= " SET remise_absolue = ".$remise;
2334  $sql.= " WHERE rowid = ".$this->id." AND fk_statut = ".self::STATUS_DRAFT;
2335 
2336  dol_syslog(__METHOD__, LOG_DEBUG);
2337  $resql=$this->db->query($sql);
2338  if (!$resql)
2339  {
2340  $this->errors[]=$this->db->error();
2341  $error++;
2342  }
2343 
2344  if (! $error)
2345  {
2346  $this->oldcopy= clone $this;
2347  $this->remise_absolue = $remise;
2348  $this->update_price(1);
2349  }
2350 
2351  if (! $notrigger && empty($error))
2352  {
2353  // Call trigger
2354  $result=$this->call_trigger('PROPAL_MODIFY',$user);
2355  if ($result < 0) $error++;
2356  // End call triggers
2357  }
2358 
2359  if (! $error)
2360  {
2361  $this->db->commit();
2362  return 1;
2363  }
2364  else
2365  {
2366  foreach($this->errors as $errmsg)
2367  {
2368  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2369  $this->error.=($this->error?', '.$errmsg:$errmsg);
2370  }
2371  $this->db->rollback();
2372  return -1*$error;
2373  }
2374  }
2375  }
2376 
2377 
2378 
2388  function reopen($user, $statut, $note='', $notrigger=0)
2389  {
2390 
2391  $this->statut = $statut;
2392  $error=0;
2393 
2394  $sql = "UPDATE ".MAIN_DB_PREFIX."propal";
2395  $sql.= " SET fk_statut = ".$this->statut.",";
2396  if (! empty($note)) $sql.= " note_private = '".$this->db->escape($note)."',";
2397  $sql.= " date_cloture=NULL, fk_user_cloture=NULL";
2398  $sql.= " WHERE rowid = ".$this->id;
2399 
2400  $this->db->begin();
2401 
2402  dol_syslog(get_class($this)."::reopen", LOG_DEBUG);
2403  $resql = $this->db->query($sql);
2404  if (! $resql) {
2405  $error++; $this->errors[]="Error ".$this->db->lasterror();
2406  }
2407  if (! $error)
2408  {
2409  if (! $notrigger)
2410  {
2411  // Call trigger
2412  $result=$this->call_trigger('PROPAL_REOPEN',$user);
2413  if ($result < 0) { $error++; }
2414  // End call triggers
2415  }
2416  }
2417 
2418  // Commit or rollback
2419  if ($error)
2420  {
2421  if (!empty($this->errors))
2422  {
2423  foreach($this->errors as $errmsg)
2424  {
2425  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
2426  $this->error.=($this->error?', '.$errmsg:$errmsg);
2427  }
2428  }
2429  $this->db->rollback();
2430  return -1*$error;
2431  }
2432  else
2433  {
2434  $this->db->commit();
2435  return 1;
2436  }
2437  }
2438 
2439 
2449  function cloture($user, $statut, $note="", $notrigger=0)
2450  {
2451  global $langs,$conf;
2452 
2453  $error=0;
2454  $now=dol_now();
2455 
2456  $this->db->begin();
2457 
2458  $newprivatenote = dol_concatdesc($this->note_private, $note);
2459 
2460  $sql = "UPDATE ".MAIN_DB_PREFIX."propal";
2461  $sql.= " SET fk_statut = ".$statut.", note_private = '".$this->db->escape($newprivatenote)."', date_cloture='".$this->db->idate($now)."', fk_user_cloture=".$user->id;
2462  $sql.= " WHERE rowid = ".$this->id;
2463 
2464  $resql=$this->db->query($sql);
2465  if ($resql)
2466  {
2467  $modelpdf=$conf->global->PROPALE_ADDON_PDF_ODT_CLOSED?$conf->global->PROPALE_ADDON_PDF_ODT_CLOSED:$this->modelpdf;
2468  $trigger_name='PROPAL_CLOSE_REFUSED';
2469 
2470  if ($statut == self::STATUS_SIGNED)
2471  {
2472  $trigger_name='PROPAL_CLOSE_SIGNED';
2473  $modelpdf=$conf->global->PROPALE_ADDON_PDF_ODT_TOBILL?$conf->global->PROPALE_ADDON_PDF_ODT_TOBILL:$this->modelpdf;
2474 
2475  // The connected company is classified as a client
2476  $soc=new Societe($this->db);
2477  $soc->id = $this->socid;
2478  $result=$soc->set_as_client();
2479 
2480  if ($result < 0)
2481  {
2482  $this->error=$this->db->lasterror();
2483  $this->db->rollback();
2484  return -2;
2485  }
2486  }
2487  if ($statut == self::STATUS_BILLED) // Why this ?
2488  {
2489  $trigger_name='PROPAL_CLASSIFY_BILLED';
2490  }
2491 
2492  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
2493  {
2494  // Define output language
2495  $outputlangs = $langs;
2496  if (! empty($conf->global->MAIN_MULTILANGS))
2497  {
2498  $outputlangs = new Translate("",$conf);
2499  $newlang=(GETPOST('lang_id','aZ09') ? GETPOST('lang_id','aZ09') : $this->thirdparty->default_lang);
2500  $outputlangs->setDefaultLang($newlang);
2501  }
2502  //$ret=$object->fetch($id); // Reload to get new records
2503  $this->generateDocument($modelpdf, $outputlangs);
2504  }
2505 
2506  if (! $error)
2507  {
2508  $this->oldcopy= clone $this;
2509  $this->statut = $statut;
2510  $this->date_cloture = $now;
2511  $this->note_private = $newprivatenote;
2512  }
2513 
2514  if (! $notrigger && empty($error))
2515  {
2516  // Call trigger
2517  $result=$this->call_trigger($trigger_name,$user);
2518  if ($result < 0) { $error++; }
2519  // End call triggers
2520  }
2521 
2522  if (! $error)
2523  {
2524  $this->db->commit();
2525  return 1;
2526  }
2527  else
2528  {
2529  $this->statut = $this->oldcopy->statut;
2530  $this->date_cloture = $this->oldcopy->date_cloture;
2531  $this->note_private = $this->oldcopy->note_private;
2532 
2533  $this->db->rollback();
2534  return -1;
2535  }
2536  }
2537  else
2538  {
2539  $this->error=$this->db->lasterror();
2540  $this->db->rollback();
2541  return -1;
2542  }
2543  }
2544 
2552  function classifyBilled(User $user, $notrigger=0)
2553  {
2554  $error=0;
2555 
2556  $this->db->begin();
2557 
2558  $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal SET fk_statut = '.self::STATUS_BILLED;
2559  $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > '.self::STATUS_DRAFT;
2560 
2561  dol_syslog(__METHOD__, LOG_DEBUG);
2562  $resql=$this->db->query($sql);
2563  if (!$resql)
2564  {
2565  $this->errors[]=$this->db->error();
2566  $error++;
2567  }
2568 
2569  if (! $error)
2570  {
2571  $this->oldcopy= clone $this;
2572  $this->statut=self::STATUS_BILLED;
2573  }
2574 
2575  if (! $notrigger && empty($error))
2576  {
2577  // Call trigger
2578  $result=$this->call_trigger('PROPAL_MODIFY',$user);
2579  if ($result < 0) $error++;
2580  // End call triggers
2581  }
2582 
2583  if (! $error)
2584  {
2585  $this->db->commit();
2586  return 1;
2587  }
2588  else
2589  {
2590  foreach($this->errors as $errmsg)
2591  {
2592  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2593  $this->error.=($this->error?', '.$errmsg:$errmsg);
2594  }
2595  $this->db->rollback();
2596  return -1*$error;
2597  }
2598  }
2599 
2600  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2608  function set_draft($user, $notrigger=0)
2609  {
2610  // phpcs:enable
2611  $error=0;
2612 
2613  $this->db->begin();
2614 
2615  $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET fk_statut = ".self::STATUS_DRAFT;
2616  $sql.= " WHERE rowid = ".$this->id;
2617 
2618  dol_syslog(__METHOD__, LOG_DEBUG);
2619  $resql=$this->db->query($sql);
2620  if (!$resql)
2621  {
2622  $this->errors[]=$this->db->error();
2623  $error++;
2624  }
2625 
2626  if (! $error)
2627  {
2628  $this->oldcopy= clone $this;
2629  $this->statut = self::STATUS_DRAFT;
2630  $this->brouillon = 1;
2631  }
2632 
2633  if (! $notrigger && empty($error))
2634  {
2635  // Call trigger
2636  $result=$this->call_trigger('PROPAL_MODIFY',$user);
2637  if ($result < 0) $error++;
2638  // End call triggers
2639  }
2640 
2641  if (! $error)
2642  {
2643  $this->db->commit();
2644  return 1;
2645  }
2646  else
2647  {
2648  foreach($this->errors as $errmsg)
2649  {
2650  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2651  $this->error.=($this->error?', '.$errmsg:$errmsg);
2652  }
2653  $this->db->rollback();
2654  return -1*$error;
2655  }
2656  }
2657 
2658 
2659  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2673  function liste_array($shortlist=0, $draft=0, $notcurrentuser=0, $socid=0, $limit=0, $offset=0, $sortfield='p.datep', $sortorder='DESC')
2674  {
2675  // phpcs:enable
2676  global $user;
2677 
2678  $ga = array();
2679 
2680  $sql = "SELECT s.rowid, s.nom as name, s.client,";
2681  $sql.= " p.rowid as propalid, p.fk_statut, p.total_ht, p.ref, p.remise, ";
2682  $sql.= " p.datep as dp, p.fin_validite as datelimite";
2683  if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", sc.fk_soc, sc.fk_user";
2684  $sql.= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."propal as p, ".MAIN_DB_PREFIX."c_propalst as c";
2685  if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
2686  $sql.= " WHERE p.entity IN (".getEntity('propal').")";
2687  $sql.= " AND p.fk_soc = s.rowid";
2688  $sql.= " AND p.fk_statut = c.id";
2689  if (! $user->rights->societe->client->voir && ! $socid) //restriction
2690  {
2691  $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id;
2692  }
2693  if ($socid) $sql.= " AND s.rowid = ".$socid;
2694  if ($draft) $sql.= " AND p.fk_statut = ".self::STATUS_DRAFT;
2695  if ($notcurrentuser > 0) $sql.= " AND p.fk_user_author <> ".$user->id;
2696  $sql.= $this->db->order($sortfield,$sortorder);
2697  $sql.= $this->db->plimit($limit,$offset);
2698 
2699  $result=$this->db->query($sql);
2700  if ($result)
2701  {
2702  $num = $this->db->num_rows($result);
2703  if ($num)
2704  {
2705  $i = 0;
2706  while ($i < $num)
2707  {
2708  $obj = $this->db->fetch_object($result);
2709 
2710  if ($shortlist == 1)
2711  {
2712  $ga[$obj->propalid] = $obj->ref;
2713  }
2714  else if ($shortlist == 2)
2715  {
2716  $ga[$obj->propalid] = $obj->ref.' ('.$obj->name.')';
2717  }
2718  else
2719  {
2720  $ga[$i]['id'] = $obj->propalid;
2721  $ga[$i]['ref'] = $obj->ref;
2722  $ga[$i]['name'] = $obj->name;
2723  }
2724 
2725  $i++;
2726  }
2727  }
2728  return $ga;
2729  }
2730  else
2731  {
2732  dol_print_error($this->db);
2733  return -1;
2734  }
2735  }
2736 
2743  {
2744  return $this->InvoiceArrayList($this->id);
2745  }
2746 
2747  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2754  function InvoiceArrayList($id)
2755  {
2756  // phpcs:enable
2757  $ga = array();
2758  $linkedInvoices = array();
2759 
2760  $this->fetchObjectLinked($id,$this->element);
2761  foreach($this->linkedObjectsIds as $objecttype => $objectid)
2762  {
2763  // Nouveau système du comon object renvoi des rowid et non un id linéaire de 1 à n
2764  // On parcourt donc une liste d'objets en tant qu'objet unique
2765  foreach($objectid as $key => $object)
2766  {
2767  // Cas des factures liees directement
2768  if ($objecttype == 'facture')
2769  {
2770  $linkedInvoices[] = $object;
2771  }
2772  // Cas des factures liees par un autre objet (ex: commande)
2773  else
2774  {
2775  $this->fetchObjectLinked($object,$objecttype);
2776  foreach($this->linkedObjectsIds as $subobjecttype => $subobjectid)
2777  {
2778  foreach($subobjectid as $subkey => $subobject)
2779  {
2780  if ($subobjecttype == 'facture')
2781  {
2782  $linkedInvoices[] = $subobject;
2783  }
2784  }
2785  }
2786  }
2787  }
2788  }
2789 
2790  if (count($linkedInvoices) > 0)
2791  {
2792  $sql= "SELECT rowid as facid, facnumber, total, datef as df, fk_user_author, fk_statut, paye";
2793  $sql.= " FROM ".MAIN_DB_PREFIX."facture";
2794  $sql.= " WHERE rowid IN (".implode(',',$linkedInvoices).")";
2795 
2796  dol_syslog(get_class($this)."::InvoiceArrayList", LOG_DEBUG);
2797  $resql=$this->db->query($sql);
2798 
2799  if ($resql)
2800  {
2801  $tab_sqlobj=array();
2802  $nump = $this->db->num_rows($resql);
2803  for ($i = 0;$i < $nump;$i++)
2804  {
2805  $sqlobj = $this->db->fetch_object($resql);
2806  $tab_sqlobj[] = $sqlobj;
2807  }
2808  $this->db->free($resql);
2809 
2810  $nump = count($tab_sqlobj);
2811 
2812  if ($nump)
2813  {
2814  $i = 0;
2815  while ($i < $nump)
2816  {
2817  $obj = array_shift($tab_sqlobj);
2818 
2819  $ga[$i] = $obj;
2820 
2821  $i++;
2822  }
2823  }
2824  return $ga;
2825  }
2826  else
2827  {
2828  return -1;
2829  }
2830  }
2831  else return $ga;
2832  }
2833 
2841  function delete($user, $notrigger=0)
2842  {
2843  global $conf;
2844  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2845 
2846  $error=0;
2847 
2848  $this->db->begin();
2849 
2850  if (! $notrigger)
2851  {
2852  // Call trigger
2853  $result=$this->call_trigger('PROPAL_DELETE',$user);
2854  if ($result < 0) { $error++; }
2855  // End call triggers
2856  }
2857 
2858  if (! $error)
2859  {
2860  $sql = "DELETE FROM ".MAIN_DB_PREFIX."propaldet WHERE fk_propal = ".$this->id;
2861  if ($this->db->query($sql))
2862  {
2863  $sql = "DELETE FROM ".MAIN_DB_PREFIX."propal WHERE rowid = ".$this->id;
2864  if ($this->db->query($sql))
2865  {
2866  // Delete linked object
2867  $res = $this->deleteObjectLinked();
2868  if ($res < 0) $error++;
2869 
2870  // Delete linked contacts
2871  $res = $this->delete_linked_contact();
2872  if ($res < 0) $error++;
2873 
2874  if (! $error)
2875  {
2876  // We remove directory
2877  $ref = dol_sanitizeFileName($this->ref);
2878  if ($conf->propal->multidir_output[$this->entity] && !empty($this->ref))
2879  {
2880  $dir = $conf->propal->multidir_output[$this->entity] . "/" . $ref ;
2881  $file = $dir . "/" . $ref . ".pdf";
2882  if (file_exists($file))
2883  {
2884  dol_delete_preview($this);
2885 
2886  if (! dol_delete_file($file,0,0,0,$this)) // For triggers
2887  {
2888  $this->error='ErrorFailToDeleteFile';
2889  $this->errors=array('ErrorFailToDeleteFile');
2890  $this->db->rollback();
2891  return 0;
2892  }
2893  }
2894  if (file_exists($dir))
2895  {
2896  $res=@dol_delete_dir_recursive($dir);
2897  if (! $res)
2898  {
2899  $this->error='ErrorFailToDeleteDir';
2900  $this->errors=array('ErrorFailToDeleteDir');
2901  $this->db->rollback();
2902  return 0;
2903  }
2904  }
2905  }
2906  }
2907 
2908  // Removed extrafields
2909  if (! $error)
2910  {
2911  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
2912  {
2913  $result=$this->deleteExtraFields();
2914  if ($result < 0)
2915  {
2916  $error++;
2917  $errorflag=-4;
2918  dol_syslog(get_class($this)."::delete erreur ".$errorflag." ".$this->error, LOG_ERR);
2919  }
2920  }
2921  }
2922 
2923  if (! $error)
2924  {
2925  dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
2926  $this->db->commit();
2927  return 1;
2928  }
2929  else
2930  {
2931  $this->error=$this->db->lasterror();
2932  $this->db->rollback();
2933  return 0;
2934  }
2935  }
2936  else
2937  {
2938  $this->error=$this->db->lasterror();
2939  $this->db->rollback();
2940  return -3;
2941  }
2942  }
2943  else
2944  {
2945  $this->error=$this->db->lasterror();
2946  $this->db->rollback();
2947  return -2;
2948  }
2949  }
2950  else
2951  {
2952  $this->db->rollback();
2953  return -1;
2954  }
2955  }
2956 
2965  function availability($availability_id, $notrigger=0)
2966  {
2967  global $user;
2968 
2969  if ($this->statut >= self::STATUS_DRAFT)
2970  {
2971  $error=0;
2972 
2973  $this->db->begin();
2974 
2975  $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal';
2976  $sql .= ' SET fk_availability = '.$availability_id;
2977  $sql .= ' WHERE rowid='.$this->id;
2978 
2979  dol_syslog(__METHOD__.' availability('.$availability_id.')', LOG_DEBUG);
2980  $resql=$this->db->query($sql);
2981  if (!$resql)
2982  {
2983  $this->errors[]=$this->db->error();
2984  $error++;
2985  }
2986 
2987  if (! $error)
2988  {
2989  $this->oldcopy= clone $this;
2990  $this->availability_id = $availability_id;
2991  }
2992 
2993  if (! $notrigger && empty($error))
2994  {
2995  // Call trigger
2996  $result=$this->call_trigger('PROPAL_MODIFY',$user);
2997  if ($result < 0) $error++;
2998  // End call triggers
2999  }
3000 
3001  if (! $error)
3002  {
3003  $this->db->commit();
3004  return 1;
3005  }
3006  else
3007  {
3008  foreach($this->errors as $errmsg)
3009  {
3010  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
3011  $this->error.=($this->error?', '.$errmsg:$errmsg);
3012  }
3013  $this->db->rollback();
3014  return -1*$error;
3015  }
3016  }
3017  else
3018  {
3019  $error_str='Propal status do not meet requirement '.$this->statut;
3020  dol_syslog(__METHOD__.$error_str, LOG_ERR);
3021  $this->error=$error_str;
3022  $this->errors[]= $this->error;
3023  return -2;
3024  }
3025  }
3026 
3027  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3036  function demand_reason($demand_reason_id, $notrigger=0)
3037  {
3038  // phpcs:enable
3039  global $user;
3040 
3041  if ($this->statut >= self::STATUS_DRAFT)
3042  {
3043  $error=0;
3044 
3045  $this->db->begin();
3046 
3047  $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal';
3048  $sql .= ' SET fk_input_reason = '.$demand_reason_id;
3049  $sql .= ' WHERE rowid='.$this->id;
3050 
3051  dol_syslog(__METHOD__.' demand_reason('.$demand_reason_id.')', LOG_DEBUG);
3052  $resql=$this->db->query($sql);
3053  if (!$resql)
3054  {
3055  $this->errors[]=$this->db->error();
3056  $error++;
3057  }
3058 
3059  if (! $error)
3060  {
3061  $this->oldcopy= clone $this;
3062  $this->demand_reason_id = $demand_reason_id;
3063  }
3064 
3065  if (! $notrigger && empty($error))
3066  {
3067  // Call trigger
3068  $result=$this->call_trigger('PROPAL_MODIFY',$user);
3069  if ($result < 0) $error++;
3070  // End call triggers
3071  }
3072 
3073  if (! $error)
3074  {
3075  $this->db->commit();
3076  return 1;
3077  }
3078  else
3079  {
3080  foreach($this->errors as $errmsg)
3081  {
3082  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
3083  $this->error.=($this->error?', '.$errmsg:$errmsg);
3084  }
3085  $this->db->rollback();
3086  return -1*$error;
3087  }
3088  }
3089  else
3090  {
3091  $error_str='Propal status do not meet requirement '.$this->statut;
3092  dol_syslog(__METHOD__.$error_str, LOG_ERR);
3093  $this->error=$error_str;
3094  $this->errors[]= $this->error;
3095  return -2;
3096  }
3097  }
3098 
3099 
3106  function info($id)
3107  {
3108  $sql = "SELECT c.rowid, ";
3109  $sql.= " c.datec, c.date_valid as datev, c.date_cloture as dateo,";
3110  $sql.= " c.fk_user_author, c.fk_user_valid, c.fk_user_cloture";
3111  $sql.= " FROM ".MAIN_DB_PREFIX."propal as c";
3112  $sql.= " WHERE c.rowid = ".$id;
3113 
3114  $result = $this->db->query($sql);
3115 
3116  if ($result)
3117  {
3118  if ($this->db->num_rows($result))
3119  {
3120  $obj = $this->db->fetch_object($result);
3121 
3122  $this->id = $obj->rowid;
3123 
3124  $this->date_creation = $this->db->jdate($obj->datec);
3125  $this->date_validation = $this->db->jdate($obj->datev);
3126  $this->date_cloture = $this->db->jdate($obj->dateo);
3127 
3128  $cuser = new User($this->db);
3129  $cuser->fetch($obj->fk_user_author);
3130  $this->user_creation = $cuser;
3131 
3132  if ($obj->fk_user_valid)
3133  {
3134  $vuser = new User($this->db);
3135  $vuser->fetch($obj->fk_user_valid);
3136  $this->user_validation = $vuser;
3137  }
3138 
3139  if ($obj->fk_user_cloture)
3140  {
3141  $cluser = new User($this->db);
3142  $cluser->fetch($obj->fk_user_cloture);
3143  $this->user_cloture = $cluser;
3144  }
3145  }
3146  $this->db->free($result);
3147  }
3148  else
3149  {
3150  dol_print_error($this->db);
3151  }
3152  }
3153 
3154 
3161  function getLibStatut($mode=0)
3162  {
3163  return $this->LibStatut($this->statut, $mode);
3164  }
3165 
3166  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3174  function LibStatut($statut,$mode=1)
3175  {
3176  // phpcs:enable
3177  global $conf;
3178 
3179  // Init/load array of translation of status
3180  if (empty($this->labelstatut) || empty($this->labelstatut_short))
3181  {
3182  global $langs;
3183  $langs->load("propal");
3184  $this->labelstatut[0]=$langs->trans("PropalStatusDraft");
3185  $this->labelstatut[1]=$langs->trans("PropalStatusValidated");
3186  $this->labelstatut[2]=$langs->trans("PropalStatusSigned");
3187  $this->labelstatut[3]=$langs->trans("PropalStatusNotSigned");
3188  $this->labelstatut[4]=$langs->trans("PropalStatusBilled");
3189  $this->labelstatut_short[0]=$langs->trans("PropalStatusDraftShort");
3190  $this->labelstatut_short[1]=$langs->trans("PropalStatusValidatedShort");
3191  $this->labelstatut_short[2]=$langs->trans("PropalStatusSignedShort");
3192  $this->labelstatut_short[3]=$langs->trans("PropalStatusNotSignedShort");
3193  $this->labelstatut_short[4]=$langs->trans("PropalStatusBilledShort");
3194  }
3195 
3196  $statuttrans='';
3197  if ($statut==self::STATUS_DRAFT) $statuttrans='statut0';
3198  elseif ($statut==self::STATUS_VALIDATED) $statuttrans='statut1';
3199  elseif ($statut==self::STATUS_SIGNED) $statuttrans='statut3';
3200  elseif ($statut==self::STATUS_NOTSIGNED) $statuttrans='statut5';
3201  elseif ($statut==self::STATUS_BILLED) $statuttrans='statut6';
3202 
3203  if ($mode == 0) return $this->labelstatut[$statut];
3204  elseif ($mode == 1) return $this->labelstatut_short[$statut];
3205  elseif ($mode == 2) return img_picto($this->labelstatut_short[$statut], $statuttrans).' '.$this->labelstatut_short[$statut];
3206  elseif ($mode == 3) return img_picto($this->labelstatut[$statut], $statuttrans);
3207  elseif ($mode == 4) return img_picto($this->labelstatut[$statut],$statuttrans).' '.$this->labelstatut[$statut];
3208  elseif ($mode == 5) return '<span class="hideonsmartphone">'.$this->labelstatut_short[$statut].' </span>'.img_picto($this->labelstatut[$statut],$statuttrans);
3209  elseif ($mode == 6) return '<span class="hideonsmartphone">'.$this->labelstatut[$statut].' </span>'.img_picto($this->labelstatut[$statut],$statuttrans);
3210  }
3211 
3212 
3213  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3221  function load_board($user,$mode)
3222  {
3223  // phpcs:enable
3224  global $conf, $langs;
3225 
3226  $clause = " WHERE";
3227 
3228  $sql = "SELECT p.rowid, p.ref, p.datec as datec, p.fin_validite as datefin, p.total_ht";
3229  $sql.= " FROM ".MAIN_DB_PREFIX."propal as p";
3230  if (!$user->rights->societe->client->voir && !$user->societe_id)
3231  {
3232  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc";
3233  $sql.= " WHERE sc.fk_user = " .$user->id;
3234  $clause = " AND";
3235  }
3236  $sql.= $clause." p.entity IN (".getEntity('propal').")";
3237  if ($mode == 'opened') $sql.= " AND p.fk_statut = ".self::STATUS_VALIDATED;
3238  if ($mode == 'signed') $sql.= " AND p.fk_statut = ".self::STATUS_SIGNED;
3239  if ($user->societe_id) $sql.= " AND p.fk_soc = ".$user->societe_id;
3240 
3241  $resql=$this->db->query($sql);
3242  if ($resql)
3243  {
3244  $langs->load("propal");
3245  $now=dol_now();
3246 
3247  $delay_warning = 0;
3248  $statut = 0;
3249  $label = '';
3250  if ($mode == 'opened') {
3251  $delay_warning=$conf->propal->cloture->warning_delay;
3252  $statut = self::STATUS_VALIDATED;
3253  $label = $langs->trans("PropalsToClose");
3254  }
3255  if ($mode == 'signed') {
3256  $delay_warning=$conf->propal->facturation->warning_delay;
3257  $statut = self::STATUS_SIGNED;
3258  $label = $langs->trans("PropalsToBill"); // We set here bill but may be billed or ordered
3259  }
3260 
3261  $response = new WorkboardResponse();
3262  $response->warning_delay = $delay_warning/60/60/24;
3263  $response->label = $label;
3264  $response->url = DOL_URL_ROOT.'/comm/propal/list.php?viewstatut='.$statut.'&mainmenu=commercial&leftmenu=propals';
3265  $response->url_late = DOL_URL_ROOT.'/comm/propal/list.php?viewstatut='.$statut.'&mainmenu=commercial&leftmenu=propals&sortfield=p.datep&sortorder=asc';
3266  $response->img = img_object('',"propal");
3267 
3268  // This assignment in condition is not a bug. It allows walking the results.
3269  while ($obj=$this->db->fetch_object($resql))
3270  {
3271  $response->nbtodo++;
3272  $response->total+=$obj->total_ht;
3273 
3274  if ($mode == 'opened')
3275  {
3276  $datelimit = $this->db->jdate($obj->datefin);
3277  if ($datelimit < ($now - $delay_warning))
3278  {
3279  $response->nbtodolate++;
3280  }
3281  }
3282  // TODO Definir regle des propales a facturer en retard
3283  // if ($mode == 'signed' && ! count($this->FactureListeArray($obj->rowid))) $this->nbtodolate++;
3284  }
3285 
3286  return $response;
3287  }
3288  else
3289  {
3290  $this->error=$this->db->error();
3291  return -1;
3292  }
3293  }
3294 
3295 
3303  function initAsSpecimen()
3304  {
3305  global $langs;
3306 
3307  // Load array of products prodids
3308  $num_prods = 0;
3309  $prodids = array();
3310  $sql = "SELECT rowid";
3311  $sql.= " FROM ".MAIN_DB_PREFIX."product";
3312  $sql.= " WHERE entity IN (".getEntity('product').")";
3313  $resql = $this->db->query($sql);
3314  if ($resql)
3315  {
3316  $num_prods = $this->db->num_rows($resql);
3317  $i = 0;
3318  while ($i < $num_prods)
3319  {
3320  $i++;
3321  $row = $this->db->fetch_row($resql);
3322  $prodids[$i] = $row[0];
3323  }
3324  }
3325 
3326  // Initialise parametres
3327  $this->id=0;
3328  $this->ref = 'SPECIMEN';
3329  $this->ref_client='NEMICEPS';
3330  $this->specimen=1;
3331  $this->socid = 1;
3332  $this->date = time();
3333  $this->fin_validite = $this->date+3600*24*30;
3334  $this->cond_reglement_id = 1;
3335  $this->cond_reglement_code = 'RECEP';
3336  $this->mode_reglement_id = 7;
3337  $this->mode_reglement_code = 'CHQ';
3338  $this->availability_id = 1;
3339  $this->availability_code = 'AV_NOW';
3340  $this->demand_reason_id = 1;
3341  $this->demand_reason_code = 'SRC_00';
3342  $this->note_public='This is a comment (public)';
3343  $this->note_private='This is a comment (private)';
3344  // Lines
3345  $nbp = 5;
3346  $xnbp = 0;
3347  while ($xnbp < $nbp)
3348  {
3349  $line=new PropaleLigne($this->db);
3350  $line->desc=$langs->trans("Description")." ".$xnbp;
3351  $line->qty=1;
3352  $line->subprice=100;
3353  $line->price=100;
3354  $line->tva_tx=20;
3355  $line->localtax1_tx=0;
3356  $line->localtax2_tx=0;
3357  if ($xnbp == 2)
3358  {
3359  $line->total_ht=50;
3360  $line->total_ttc=60;
3361  $line->total_tva=10;
3362  $line->remise_percent=50;
3363  }
3364  else
3365  {
3366  $line->total_ht=100;
3367  $line->total_ttc=120;
3368  $line->total_tva=20;
3369  $line->remise_percent=00;
3370  }
3371 
3372  if ($num_prods > 0)
3373  {
3374  $prodid = mt_rand(1, $num_prods);
3375  $line->fk_product=$prodids[$prodid];
3376  $line->product_ref='SPECIMEN';
3377  }
3378 
3379  $this->lines[$xnbp]=$line;
3380 
3381  $this->total_ht += $line->total_ht;
3382  $this->total_tva += $line->total_tva;
3383  $this->total_ttc += $line->total_ttc;
3384 
3385  $xnbp++;
3386  }
3387  }
3388 
3389  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3395  function load_state_board()
3396  {
3397  // phpcs:enable
3398  global $user;
3399 
3400  $this->nb=array();
3401  $clause = "WHERE";
3402 
3403  $sql = "SELECT count(p.rowid) as nb";
3404  $sql.= " FROM ".MAIN_DB_PREFIX."propal as p";
3405  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
3406  if (!$user->rights->societe->client->voir && !$user->societe_id)
3407  {
3408  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
3409  $sql.= " WHERE sc.fk_user = " .$user->id;
3410  $clause = "AND";
3411  }
3412  $sql.= " ".$clause." p.entity IN (".getEntity('propal').")";
3413 
3414  $resql=$this->db->query($sql);
3415  if ($resql)
3416  {
3417  // This assignment in condition is not a bug. It allows walking the results.
3418  while ($obj=$this->db->fetch_object($resql))
3419  {
3420  $this->nb["proposals"]=$obj->nb;
3421  }
3422  $this->db->free($resql);
3423  return 1;
3424  }
3425  else
3426  {
3427  dol_print_error($this->db);
3428  $this->error=$this->db->error();
3429  return -1;
3430  }
3431  }
3432 
3433 
3441  function getNextNumRef($soc)
3442  {
3443  global $conf,$langs;
3444  $langs->load("propal");
3445 
3446  $classname = $conf->global->PROPALE_ADDON;
3447 
3448  if (! empty($classname))
3449  {
3450  $mybool=false;
3451 
3452  $file = $classname.".php";
3453 
3454  // Include file with class
3455  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
3456  foreach ($dirmodels as $reldir) {
3457 
3458  $dir = dol_buildpath($reldir."core/modules/propale/");
3459 
3460  // Load file with numbering class (if found)
3461  $mybool|=@include_once $dir.$file;
3462  }
3463 
3464  if (! $mybool)
3465  {
3466  dol_print_error('',"Failed to include file ".$file);
3467  return '';
3468  }
3469 
3470  $obj = new $classname();
3471  $numref = "";
3472  $numref = $obj->getNextValue($soc,$this);
3473 
3474  if ($numref != "")
3475  {
3476  return $numref;
3477  }
3478  else
3479  {
3480  $this->error=$obj->error;
3481  //dol_print_error($db,"Propale::getNextNumRef ".$obj->error);
3482  return "";
3483  }
3484  }
3485  else
3486  {
3487  $langs->load("errors");
3488  print $langs->trans("Error")." ".$langs->trans("ErrorModuleSetupNotComplete");
3489  return "";
3490  }
3491  }
3492 
3503  function getNomUrl($withpicto=0, $option='', $get_params='', $notooltip=0, $save_lastsearch_value=-1)
3504  {
3505  global $langs, $conf, $user;
3506 
3507  if (! empty($conf->dol_no_mouse_hover)) $notooltip=1; // Force disable tooltips
3508 
3509  $result='';
3510  $label='';
3511  $url='';
3512 
3513  if ($user->rights->propal->lire)
3514  {
3515  $label = '<u>' . $langs->trans("ShowPropal") . '</u>';
3516  if (! empty($this->ref))
3517  $label.= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
3518  if (! empty($this->ref_client))
3519  $label.= '<br><b>'.$langs->trans('RefCustomer').':</b> '.$this->ref_client;
3520  if (! empty($this->total_ht))
3521  $label.= '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
3522  if (! empty($this->total_tva))
3523  $label.= '<br><b>' . $langs->trans('VAT') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
3524  if (! empty($this->total_ttc))
3525  $label.= '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
3526  if ($option == '') {
3527  $url = DOL_URL_ROOT.'/comm/propal/card.php?id='.$this->id. $get_params;
3528  }
3529  if ($option == 'compta') { // deprecated
3530  $url = DOL_URL_ROOT.'/comm/propal/card.php?id='.$this->id. $get_params;
3531  }
3532  if ($option == 'expedition') {
3533  $url = DOL_URL_ROOT.'/expedition/propal.php?id='.$this->id. $get_params;
3534  }
3535  if ($option == 'document') {
3536  $url = DOL_URL_ROOT.'/comm/propal/document.php?id='.$this->id. $get_params;
3537  }
3538 
3539  if ($option != 'nolink')
3540  {
3541  // Add param to save lastsearch_values or not
3542  $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
3543  if ($save_lastsearch_value == -1 && preg_match('/list\.php/',$_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
3544  if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
3545  }
3546  }
3547 
3548  $linkclose='';
3549  if (empty($notooltip) && $user->rights->propal->lire)
3550  {
3551  if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
3552  {
3553  $label=$langs->trans("ShowPropal");
3554  $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
3555  }
3556  $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
3557  $linkclose.=' class="classfortooltip"';
3558  }
3559 
3560  $linkstart = '<a href="'.$url.'"';
3561  $linkstart.=$linkclose.'>';
3562  $linkend='</a>';
3563 
3564  $result .= $linkstart;
3565  if ($withpicto) $result.=img_object(($notooltip?'':$label), $this->picto, ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
3566  if ($withpicto != 2) $result.= $this->ref;
3567  $result .= $linkend;
3568 
3569  return $result;
3570  }
3571 
3577  function getLinesArray()
3578  {
3579  return $this->fetch_lines();
3580  }
3581 
3593  public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
3594  {
3595  global $conf,$langs;
3596 
3597  $langs->load("propale");
3598 
3599  if (! dol_strlen($modele)) {
3600 
3601  $modele = 'azur';
3602 
3603  if ($this->modelpdf) {
3604  $modele = $this->modelpdf;
3605  } elseif (! empty($conf->global->PROPALE_ADDON_PDF)) {
3606  $modele = $conf->global->PROPALE_ADDON_PDF;
3607  }
3608  }
3609 
3610  $modelpath = "core/modules/propale/doc/";
3611 
3612  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref,$moreparams);
3613  }
3614 
3623  public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
3624  {
3625  $tables = array(
3626  'propal'
3627  );
3628 
3629  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
3630  }
3631 }
3632 
3633 
3638 {
3642  public $element='propaldet';
3643 
3647  public $table_element='propaldet';
3648 
3649  var $oldline;
3650 
3651  // From llx_propaldet
3652  var $fk_propal;
3653  var $fk_parent_line;
3654  var $desc; // Description ligne
3655  var $fk_product; // Id produit predefini
3666  var $product_type = Product::TYPE_PRODUCT;
3667 
3668  var $qty;
3669  var $tva_tx;
3670  var $subprice;
3671  var $remise_percent;
3672  var $fk_remise_except;
3673 
3674  var $rang = 0;
3675 
3676  var $fk_fournprice;
3677  var $pa_ht;
3678  var $marge_tx;
3679  var $marque_tx;
3680 
3681  var $special_code; // Tag for special lines (exlusive tags)
3682  // 1: frais de port
3683  // 2: ecotaxe
3684  // 3: option line (when qty = 0)
3685 
3686  var $info_bits = 0; // Liste d'options cumulables:
3687  // Bit 0: 0 si TVA normal - 1 si TVA NPR
3688  // Bit 1: 0 ligne normale - 1 si ligne de remise fixe
3689 
3690  var $total_ht; // Total HT de la ligne toute quantite et incluant la remise ligne
3691  var $total_tva; // Total TVA de la ligne toute quantite et incluant la remise ligne
3692  var $total_ttc; // Total TTC de la ligne toute quantite et incluant la remise ligne
3693 
3698  var $remise;
3703  var $price;
3704 
3705  // From llx_product
3710  var $ref;
3715  public $product_ref;
3725  public $product_label;
3730  public $product_desc;
3731 
3732  var $localtax1_tx; // Local tax 1
3733  var $localtax2_tx; // Local tax 2
3734  var $localtax1_type; // Local tax 1 type
3735  var $localtax2_type; // Local tax 2 type
3736  var $total_localtax1; // Line total local tax 1
3737  var $total_localtax2; // Line total local tax 2
3738 
3739  var $date_start;
3740  var $date_end;
3741 
3742  var $skip_update_total; // Skip update price total for special lines
3743 
3744  // Multicurrency
3745  var $fk_multicurrency;
3746  var $multicurrency_code;
3747  var $multicurrency_subprice;
3748  var $multicurrency_total_ht;
3749  var $multicurrency_total_tva;
3750  var $multicurrency_total_ttc;
3751 
3757  function __construct($db)
3758  {
3759  $this->db= $db;
3760  }
3761 
3768  function fetch($rowid)
3769  {
3770  $sql = 'SELECT pd.rowid, pd.fk_propal, pd.fk_parent_line, pd.fk_product, pd.label as custom_label, pd.description, pd.price, pd.qty, pd.vat_src_code, pd.tva_tx,';
3771  $sql.= ' pd.remise, pd.remise_percent, pd.fk_remise_except, pd.subprice,';
3772  $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,';
3773  $sql.= ' pd.fk_unit,';
3774  $sql.= ' pd.localtax1_tx, pd.localtax2_tx, pd.total_localtax1, pd.total_localtax2,';
3775  $sql.= ' pd.fk_multicurrency, pd.multicurrency_code, pd.multicurrency_subprice, pd.multicurrency_total_ht, pd.multicurrency_total_tva, pd.multicurrency_total_ttc,';
3776  $sql.= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,';
3777  $sql.= ' pd.date_start, pd.date_end, pd.product_type';
3778  $sql.= ' FROM '.MAIN_DB_PREFIX.'propaldet as pd';
3779  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pd.fk_product = p.rowid';
3780  $sql.= ' WHERE pd.rowid = '.$rowid;
3781 
3782  $result = $this->db->query($sql);
3783  if ($result)
3784  {
3785  $objp = $this->db->fetch_object($result);
3786 
3787  if ($objp)
3788  {
3789  $this->id = $objp->rowid;
3790  $this->rowid = $objp->rowid; // deprecated
3791  $this->fk_propal = $objp->fk_propal;
3792  $this->fk_parent_line = $objp->fk_parent_line;
3793  $this->label = $objp->custom_label;
3794  $this->desc = $objp->description;
3795  $this->qty = $objp->qty;
3796  $this->price = $objp->price; // deprecated
3797  $this->subprice = $objp->subprice;
3798  $this->vat_src_code = $objp->vat_src_code;
3799  $this->tva_tx = $objp->tva_tx;
3800  $this->remise = $objp->remise; // deprecated
3801  $this->remise_percent = $objp->remise_percent;
3802  $this->fk_remise_except = $objp->fk_remise_except;
3803  $this->fk_product = $objp->fk_product;
3804  $this->info_bits = $objp->info_bits;
3805 
3806  $this->total_ht = $objp->total_ht;
3807  $this->total_tva = $objp->total_tva;
3808  $this->total_ttc = $objp->total_ttc;
3809 
3810  $this->fk_fournprice = $objp->fk_fournprice;
3811 
3812  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht);
3813  $this->pa_ht = $marginInfos[0];
3814  $this->marge_tx = $marginInfos[1];
3815  $this->marque_tx = $marginInfos[2];
3816 
3817  $this->special_code = $objp->special_code;
3818  $this->product_type = $objp->product_type;
3819  $this->rang = $objp->rang;
3820 
3821  $this->ref = $objp->product_ref; // deprecated
3822  $this->product_ref = $objp->product_ref;
3823  $this->libelle = $objp->product_label; // deprecated
3824  $this->product_label = $objp->product_label;
3825  $this->product_desc = $objp->product_desc;
3826  $this->fk_unit = $objp->fk_unit;
3827 
3828  $this->date_start = $this->db->jdate($objp->date_start);
3829  $this->date_end = $this->db->jdate($objp->date_end);
3830 
3831  // Multicurrency
3832  $this->fk_multicurrency = $objp->fk_multicurrency;
3833  $this->multicurrency_code = $objp->multicurrency_code;
3834  $this->multicurrency_subprice = $objp->multicurrency_subprice;
3835  $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
3836  $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
3837  $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
3838 
3839  $this->fetch_optionals();
3840 
3841  $this->db->free($result);
3842 
3843  return 1;
3844  }
3845  else
3846  {
3847  return 0;
3848  }
3849  }
3850  else
3851  {
3852  return -1;
3853  }
3854  }
3855 
3862  function insert($notrigger=0)
3863  {
3864  global $conf,$user;
3865 
3866  $error=0;
3867 
3868  dol_syslog(get_class($this)."::insert rang=".$this->rang);
3869 
3870  $pa_ht_isemptystring = (empty($this->pa_ht) && $this->pa_ht == ''); // If true, we can use a default value. If this->pa_ht = '0', we must use '0'.
3871 
3872  // Clean parameters
3873  if (empty($this->tva_tx)) $this->tva_tx=0;
3874  if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
3875  if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
3876  if (empty($this->localtax1_type)) $this->localtax1_type=0;
3877  if (empty($this->localtax2_type)) $this->localtax2_type=0;
3878  if (empty($this->total_localtax1)) $this->total_localtax1=0;
3879  if (empty($this->total_localtax2)) $this->total_localtax2=0;
3880  if (empty($this->rang)) $this->rang=0;
3881  if (empty($this->remise)) $this->remise=0;
3882  if (empty($this->remise_percent) || ! is_numeric($this->remise_percent)) $this->remise_percent=0;
3883  if (empty($this->info_bits)) $this->info_bits=0;
3884  if (empty($this->special_code)) $this->special_code=0;
3885  if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
3886  if (empty($this->fk_fournprice)) $this->fk_fournprice=0;
3887  if (! is_numeric($this->qty)) $this->qty = 0;
3888  if (empty($this->pa_ht)) $this->pa_ht=0;
3889  if (empty($this->multicurrency_subprice)) $this->multicurrency_subprice=0;
3890  if (empty($this->multicurrency_total_ht)) $this->multicurrency_total_ht=0;
3891  if (empty($this->multicurrency_total_tva)) $this->multicurrency_total_tva=0;
3892  if (empty($this->multicurrency_total_ttc)) $this->multicurrency_total_ttc=0;
3893 
3894  // if buy price not defined, define buyprice as configured in margin admin
3895  if ($this->pa_ht == 0 && $pa_ht_isemptystring)
3896  {
3897  if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0)
3898  {
3899  return $result;
3900  }
3901  else
3902  {
3903  $this->pa_ht = $result;
3904  }
3905  }
3906 
3907  // Check parameters
3908  if ($this->product_type < 0) return -1;
3909 
3910  $this->db->begin();
3911 
3912  // Insert line into database
3913  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'propaldet';
3914  $sql.= ' (fk_propal, fk_parent_line, label, description, fk_product, product_type,';
3915  $sql.= ' fk_remise_except, qty, vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3916  $sql.= ' subprice, remise_percent, ';
3917  $sql.= ' info_bits, ';
3918  $sql.= ' total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, fk_product_fournisseur_price, buy_price_ht, special_code, rang,';
3919  $sql.= ' fk_unit,';
3920  $sql.= ' date_start, date_end';
3921  $sql.= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc)';
3922  $sql.= " VALUES (".$this->fk_propal.",";
3923  $sql.= " ".($this->fk_parent_line>0?"'".$this->db->escape($this->fk_parent_line)."'":"null").",";
3924  $sql.= " ".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null").",";
3925  $sql.= " '".$this->db->escape($this->desc)."',";
3926  $sql.= " ".($this->fk_product?"'".$this->db->escape($this->fk_product)."'":"null").",";
3927  $sql.= " '".$this->db->escape($this->product_type)."',";
3928  $sql.= " ".($this->fk_remise_except?"'".$this->db->escape($this->fk_remise_except)."'":"null").",";
3929  $sql.= " ".price2num($this->qty).",";
3930  $sql.= " ".(empty($this->vat_src_code)?"''":"'".$this->db->escape($this->vat_src_code)."'").",";
3931  $sql.= " ".price2num($this->tva_tx).",";
3932  $sql.= " ".price2num($this->localtax1_tx).",";
3933  $sql.= " ".price2num($this->localtax2_tx).",";
3934  $sql.= " '".$this->db->escape($this->localtax1_type)."',";
3935  $sql.= " '".$this->db->escape($this->localtax2_type)."',";
3936  $sql.= " ".(price2num($this->subprice)!==''?price2num($this->subprice):"null").",";
3937  $sql.= " ".price2num($this->remise_percent).",";
3938  $sql.= " ".(isset($this->info_bits)?"'".$this->db->escape($this->info_bits)."'":"null").",";
3939  $sql.= " ".price2num($this->total_ht).",";
3940  $sql.= " ".price2num($this->total_tva).",";
3941  $sql.= " ".price2num($this->total_localtax1).",";
3942  $sql.= " ".price2num($this->total_localtax2).",";
3943  $sql.= " ".price2num($this->total_ttc).",";
3944  $sql.= " ".(!empty($this->fk_fournprice)?"'".$this->db->escape($this->fk_fournprice)."'":"null").",";
3945  $sql.= " ".(isset($this->pa_ht)?"'".price2num($this->pa_ht)."'":"null").",";
3946  $sql.= ' '.$this->special_code.',';
3947  $sql.= ' '.$this->rang.',';
3948  $sql.= ' '.(!$this->fk_unit ? 'NULL' : $this->fk_unit).',';
3949  $sql.= " ".(! empty($this->date_start)?"'".$this->db->idate($this->date_start)."'":"null").',';
3950  $sql.= " ".(! empty($this->date_end)?"'".$this->db->idate($this->date_end)."'":"null");
3951  $sql.= ", ".($this->fk_multicurrency > 0?$this->fk_multicurrency:'null');
3952  $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
3953  $sql.= ", ".$this->multicurrency_subprice;
3954  $sql.= ", ".$this->multicurrency_total_ht;
3955  $sql.= ", ".$this->multicurrency_total_tva;
3956  $sql.= ", ".$this->multicurrency_total_ttc;
3957  $sql.= ')';
3958 
3959  dol_syslog(get_class($this).'::insert', LOG_DEBUG);
3960  $resql=$this->db->query($sql);
3961  if ($resql)
3962  {
3963  $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'propaldet');
3964 
3965  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
3966  {
3967  $this->id=$this->rowid;
3968  $result=$this->insertExtraFields();
3969  if ($result < 0)
3970  {
3971  $error++;
3972  }
3973  }
3974 
3975  if (! $error && ! $notrigger)
3976  {
3977  // Call trigger
3978  $result=$this->call_trigger('LINEPROPAL_INSERT',$user);
3979  if ($result < 0)
3980  {
3981  $this->db->rollback();
3982  return -1;
3983  }
3984  // End call triggers
3985  }
3986 
3987  $this->db->commit();
3988  return 1;
3989  }
3990  else
3991  {
3992  $this->error=$this->db->error()." sql=".$sql;
3993  $this->db->rollback();
3994  return -1;
3995  }
3996  }
3997 
4005  function delete(User $user, $notrigger=0)
4006  {
4007  global $conf;
4008 
4009  $error=0;
4010  $this->db->begin();
4011 
4012  $sql = "DELETE FROM ".MAIN_DB_PREFIX."propaldet WHERE rowid = ".$this->rowid;
4013  dol_syslog("PropaleLigne::delete", LOG_DEBUG);
4014  if ($this->db->query($sql) )
4015  {
4016 
4017  // Remove extrafields
4018  if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used
4019  {
4020  $this->id=$this->rowid;
4021  $result=$this->deleteExtraFields();
4022  if ($result < 0)
4023  {
4024  $error++;
4025  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
4026  }
4027  }
4028 
4029  if (! $error && ! $notrigger)
4030  {
4031  // Call trigger
4032  $result=$this->call_trigger('LINEPROPAL_DELETE',$user);
4033  if ($result < 0)
4034  {
4035  $this->db->rollback();
4036  return -1;
4037  }
4038  }
4039  // End call triggers
4040 
4041  $this->db->commit();
4042 
4043  return 1;
4044  }
4045  else
4046  {
4047  $this->error=$this->db->error()." sql=".$sql;
4048  $this->db->rollback();
4049  return -1;
4050  }
4051  }
4052 
4059  function update($notrigger=0)
4060  {
4061  global $conf,$user;
4062 
4063  $error=0;
4064 
4065  $pa_ht_isemptystring = (empty($this->pa_ht) && $this->pa_ht == ''); // If true, we can use a default value. If this->pa_ht = '0', we must use '0'.
4066 
4067  // Clean parameters
4068  if (empty($this->tva_tx)) $this->tva_tx=0;
4069  if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
4070  if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
4071  if (empty($this->total_localtax1)) $this->total_localtax1=0;
4072  if (empty($this->total_localtax2)) $this->total_localtax2=0;
4073  if (empty($this->localtax1_type)) $this->localtax1_type=0;
4074  if (empty($this->localtax2_type)) $this->localtax2_type=0;
4075  if (empty($this->marque_tx)) $this->marque_tx=0;
4076  if (empty($this->marge_tx)) $this->marge_tx=0;
4077  if (empty($this->price)) $this->price=0; // TODO A virer
4078  if (empty($this->remise)) $this->remise=0; // TODO A virer
4079  if (empty($this->remise_percent)) $this->remise_percent=0;
4080  if (empty($this->info_bits)) $this->info_bits=0;
4081  if (empty($this->special_code)) $this->special_code=0;
4082  if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
4083  if (empty($this->fk_fournprice)) $this->fk_fournprice=0;
4084  if (empty($this->subprice)) $this->subprice=0;
4085  if (empty($this->pa_ht)) $this->pa_ht=0;
4086 
4087  // if buy price not defined, define buyprice as configured in margin admin
4088  if ($this->pa_ht == 0 && $pa_ht_isemptystring)
4089  {
4090  if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0)
4091  {
4092  return $result;
4093  }
4094  else
4095  {
4096  $this->pa_ht = $result;
4097  }
4098  }
4099 
4100  $this->db->begin();
4101 
4102  // Mise a jour ligne en base
4103  $sql = "UPDATE ".MAIN_DB_PREFIX."propaldet SET";
4104  $sql.= " description='".$this->db->escape($this->desc)."'";
4105  $sql.= ", label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null");
4106  $sql.= ", product_type=".$this->product_type;
4107  $sql.= ", vat_src_code = '".(empty($this->vat_src_code)?'':$this->vat_src_code)."'";
4108  $sql.= ", tva_tx='".price2num($this->tva_tx)."'";
4109  $sql.= ", localtax1_tx=".price2num($this->localtax1_tx);
4110  $sql.= ", localtax2_tx=".price2num($this->localtax2_tx);
4111  $sql.= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
4112  $sql.= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
4113  $sql.= ", qty='".price2num($this->qty)."'";
4114  $sql.= ", subprice=".price2num($this->subprice)."";
4115  $sql.= ", remise_percent=".price2num($this->remise_percent)."";
4116  $sql.= ", price=".price2num($this->price).""; // TODO A virer
4117  $sql.= ", remise=".price2num($this->remise).""; // TODO A virer
4118  $sql.= ", info_bits='".$this->db->escape($this->info_bits)."'";
4119  if (empty($this->skip_update_total))
4120  {
4121  $sql.= ", total_ht=".price2num($this->total_ht)."";
4122  $sql.= ", total_tva=".price2num($this->total_tva)."";
4123  $sql.= ", total_ttc=".price2num($this->total_ttc)."";
4124  $sql.= ", total_localtax1=".price2num($this->total_localtax1)."";
4125  $sql.= ", total_localtax2=".price2num($this->total_localtax2)."";
4126  }
4127  $sql.= ", fk_product_fournisseur_price=".(! empty($this->fk_fournprice)?"'".$this->db->escape($this->fk_fournprice)."'":"null");
4128  $sql.= ", buy_price_ht=".price2num($this->pa_ht);
4129  if (strlen($this->special_code)) $sql.= ", special_code=".$this->special_code;
4130  $sql.= ", fk_parent_line=".($this->fk_parent_line>0?$this->fk_parent_line:"null");
4131  if (! empty($this->rang)) $sql.= ", rang=".$this->rang;
4132  $sql.= ", date_start=".(! empty($this->date_start)?"'".$this->db->idate($this->date_start)."'":"null");
4133  $sql.= ", date_end=".(! empty($this->date_end)?"'".$this->db->idate($this->date_end)."'":"null");
4134  $sql.= ", fk_unit=".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
4135 
4136  // Multicurrency
4137  $sql.= ", multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
4138  $sql.= ", multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
4139  $sql.= ", multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
4140  $sql.= ", multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
4141 
4142  $sql.= " WHERE rowid = ".$this->rowid;
4143 
4144  dol_syslog(get_class($this)."::update", LOG_DEBUG);
4145  $resql=$this->db->query($sql);
4146  if ($resql)
4147  {
4148  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
4149  {
4150  $this->id=$this->rowid;
4151  $result=$this->insertExtraFields();
4152  if ($result < 0)
4153  {
4154  $error++;
4155  }
4156  }
4157 
4158  if (! $error && ! $notrigger)
4159  {
4160  // Call trigger
4161  $result=$this->call_trigger('LINEPROPAL_UPDATE',$user);
4162  if ($result < 0)
4163  {
4164  $this->db->rollback();
4165  return -1;
4166  }
4167  // End call triggers
4168  }
4169 
4170  $this->db->commit();
4171  return 1;
4172  }
4173  else
4174  {
4175  $this->error=$this->db->error();
4176  $this->db->rollback();
4177  return -2;
4178  }
4179  }
4180 
4181  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4188  function update_total()
4189  {
4190  // phpcs:enable
4191  $this->db->begin();
4192 
4193  // Mise a jour ligne en base
4194  $sql = "UPDATE ".MAIN_DB_PREFIX."propaldet SET";
4195  $sql.= " total_ht=".price2num($this->total_ht,'MT')."";
4196  $sql.= ",total_tva=".price2num($this->total_tva,'MT')."";
4197  $sql.= ",total_ttc=".price2num($this->total_ttc,'MT')."";
4198  $sql.= " WHERE rowid = ".$this->rowid;
4199 
4200  dol_syslog("PropaleLigne::update_total", LOG_DEBUG);
4201 
4202  $resql=$this->db->query($sql);
4203  if ($resql)
4204  {
4205  $this->db->commit();
4206  return 1;
4207  }
4208  else
4209  {
4210  $this->error=$this->db->error();
4211  $this->db->rollback();
4212  return -2;
4213  }
4214  }
4215 }
print $object label
hash of file content (md5_file(dol_osencode($destfull))
Definition: edit.php:153
deleteline($lineid)
Delete detail line.
getNomUrl($withpicto=0, $option='', $get_params='', $notooltip=0, $save_lastsearch_value=-1)
Return clicable link of object (with eventually picto)
GETPOST($paramname, $check='none', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
getInvoiceArrayList()
Returns an array with the numbers of related invoices.
set_ref_client($user, $ref_client, $notrigger=0)
Set customer reference number.
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
static getIdFromCode(&$db, $code)
Get id of currency from code.
fetch($rowid)
Retrieve the propal line object.
getMarginInfos($pvht, $remise_percent, $tva_tx, $localtax1_tx, $localtax2_tx, $fk_pa, $paht)
Return an array with margins information of a line.
update($notrigger=0)
Update propal line object into DB.
LibStatut($statut, $mode=1)
Return label of a status (draft, validated, ...)
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
Delete all links between an object $this.
InvoiceArrayList($id)
Returns an array with id and ref of related invoices.
fetchObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $clause='OR', $alsosametype=1, $orderby='sourcetype', $loadalsoobjects=1)
Fetch array of objects linked to current object (object of enabled modules only). ...
reopen($user, $statut, $note='', $notrigger=0)
Reopen the commercial proposal.
__construct($db, $socid="", $propalid=0)
Constructor.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
set_draft($user, $notrigger=0)
Set draft status.
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
Class to manage Dolibarr database access.
set_echeance($user, $date_fin_validite, $notrigger=0)
Define end validity date.
set_availability($user, $id, $notrigger=0)
Set delivery.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
createFromClone($socid=0)
Load an object from its id and create a new one in database.
dol_print_error($db='', $error='', $errors=null)
Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remonte...
getLinesArray()
Retrieve an array of proposal lines.
dol_concatdesc($text1, $text2, $forxml=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
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.
insert($notrigger=0)
Insert object line propal in database.
fetch_thirdparty($force_thirdparty_id=0)
Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty.
update(User $user, $notrigger=0)
Update database.
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.
valid($user, $notrigger=0)
Set status to validated.
add_product($idproduct, $qty, $remise_percent=0)
Add line into array products $this->thirdparty should be loaded.
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
create($user, $notrigger=0)
Create commercial proposal into database this->ref can be set or empty.
set_demand_reason($user, $id, $notrigger=0)
Set source of demand.
const STATUS_NOTSIGNED
Not signed quote.
$table_ref_field
{}
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)
const STATUS_BILLED
Billed or processed quote.
if(! function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
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_SIGNED
Signed quote.
delete_linked_contact($source='', $code='')
Delete all links between an object $this and all its contacts.
static commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
set_remise_percent($user, $remise, $notrigger=0)
Set an overall discount on the proposal.
load_state_board()
Charge indicateurs this->nb de tableau de bord.
demand_reason($demand_reason_id, $notrigger=0)
Change source demand.
static replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
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
Class to manage commercial proposal lines.
fetch($rowid, $ref='')
Load a proposal from database and its ligne array.
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
liste_array($shortlist=0, $draft=0, $notcurrentuser=0, $socid=0, $limit=0, $offset=0, $sortfield='p.datep', $sortorder='DESC')
Return list of proposal (eventually filtered on user) into an array.
deleteExtraFields()
Delete all extra fields values for the current object.
set_remise_absolue($user, $remise, $notrigger=0)
Set an absolute overall discount on the proposal.
Class to manage translations.
if(GETPOST('cancel', 'alpha')) if(! GETPOST( 'confirmmassaction', 'alpha') &&$massaction !='presend' &&$massaction !='confirm_presend')
Draft customers invoices.
Definition: list.php:156
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_date($user, $date, $notrigger=0)
Define proposal date.
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...
defineBuyPrice($unitPrice=0.0, $discountPercent=0.0, $fk_product=0)
Get buy price to use for margin calculation.
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
const STATUS_DRAFT
Draft status.
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...
set_date_livraison($user, $date_livraison, $notrigger=0)
Set delivery date.
fetch_lines($only_product=0)
Load array lines.
__construct($db)
Class line Contructor.
updateline($rowid, $pu, $qty, $remise_percent, $txtva, $txlocaltax1=0.0, $txlocaltax2=0.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, $date_start='', $date_end='', $array_options=0, $fk_unit=null, $pu_ht_devise=0, $notrigger=0)
Update a proposal line.
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.
cloture($user, $statut, $note="", $notrigger=0)
Close the commercial proposal.
create_from($user)
Insert into DB a proposal object completely defined by its data members (ex, results from copy)...
const STATUS_VALIDATED
Validated status.
call_trigger($trigger_name, $user)
Call trigger based on this instance.
getNextNumRef($soc)
Returns the reference to the following non used Proposal used depending on the active numbering modul...
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
initAsSpecimen()
Initialise an instance with random values.
insert_discount($idremise)
Adding line of fixed discount in the proposal in DB.
add_object_linked($origin=null, $origin_id=null)
Add objects linked in llx_element_element.
getLibStatut($mode=0)
Return label of status of proposal (draft, validated, ...)
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='')
Show picto whatever it&#39;s its name (generic function)
update_total()
Update DB line fields total_xxx Used by migration.
availability($availability_id, $notrigger=0)
Change the delivery time.
classifyBilled(User $user, $notrigger=0)
Class invoiced the Propal.
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.
info($id)
Object Proposal Information.
addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0.0, $txlocaltax2=0.0, $fk_product=0, $remise_percent=0.0, $price_base_type='HT', $pu_ttc=0.0, $info_bits=0, $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=0, $pa_ht=0, $label='', $date_start='', $date_end='', $array_options=0, $fk_unit=null, $origin='', $origin_id=0, $pu_ht_devise=0, $fk_remise_except=0)
Add a proposal line into database (linked to product/service or not) The parameters are already suppo...
Parent class of all other business classes (invoices, contracts, proposals, orders, ...)
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
load_board($user, $mode)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Class to manage proposals.
static getIdAndTxFromCode(&$db, $code, $date_document='')
Get id and rate of currency from code.