dolibarr  7.0.0-beta
facture-rec.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2003-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2015 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2009-2012 Regis Houssin <regis.houssin@capnetworks.com>
5  * Copyright (C) 2010-2011 Juanjo Menent <jmenent@2byte.es>
6  * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
7  * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
8  * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
9  * Copyright (C) 2017 Frédéric France <frederic.france@netlogic.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <http://www.gnu.org/licenses/>.
23  */
24 
31 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
32 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
33 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
35 
36 
41 {
42  public $element='facturerec';
43  public $table_element='facture_rec';
44  public $table_element_line='facturedet_rec';
45  public $fk_element='fk_facture';
46  public $picto='bill';
47 
48  var $entity;
49  var $number;
50  var $date;
51  var $amount;
52  var $remise;
53  var $tva;
54  var $total;
55  var $db_table;
56  var $propalid;
57 
58  var $date_last_gen;
59  var $date_when;
60  var $nb_gen_done;
61  var $nb_gen_max;
62 
63  var $frequency;
64  var $unit_frequency;
65 
66  var $rang;
67  var $special_code;
68 
69  var $usenewprice=0;
70 
76  function __construct($db)
77  {
78  $this->db = $db;
79  }
80 
88  function create($user, $facid)
89  {
90  global $conf;
91 
92  $error=0;
93  $now=dol_now();
94 
95  // Clean parameters
96  $this->titre=trim($this->titre);
97  $this->usenewprice=empty($this->usenewprice)?0:$this->usenewprice;
98 
99  // No frequency defined then no next date to execution
100  if (empty($this->frequency))
101  {
102  $this->frequency=0;
103  $this->date_when=NULL;
104  }
105 
106 
107  $this->frequency=abs($this->frequency);
108  $this->nb_gen_done=0;
109  $this->nb_gen_max=empty($this->nb_gen_max)?0:$this->nb_gen_max;
110  $this->auto_validate=empty($this->auto_validate)?0:$this->auto_validate;
111  $this->generate_pdf = empty($this->generate_pdf)?0:$this->generate_pdf;
112 
113  $this->db->begin();
114 
115  // Charge facture modele
116  $facsrc=new Facture($this->db);
117  $result=$facsrc->fetch($facid);
118  if ($result > 0)
119  {
120  // On positionne en mode brouillon la facture
121  $this->brouillon = 1;
122 
123  $sql = "INSERT INTO ".MAIN_DB_PREFIX."facture_rec (";
124  $sql.= "titre";
125  $sql.= ", fk_soc";
126  $sql.= ", entity";
127  $sql.= ", datec";
128  $sql.= ", amount";
129  $sql.= ", remise";
130  $sql.= ", note_private";
131  $sql.= ", note_public";
132  $sql.= ", modelpdf";
133  $sql.= ", fk_user_author";
134  $sql.= ", fk_projet";
135  $sql.= ", fk_account";
136  $sql.= ", fk_cond_reglement";
137  $sql.= ", fk_mode_reglement";
138  $sql.= ", usenewprice";
139  $sql.= ", frequency";
140  $sql.= ", unit_frequency";
141  $sql.= ", date_when";
142  $sql.= ", date_last_gen";
143  $sql.= ", nb_gen_done";
144  $sql.= ", nb_gen_max";
145  $sql.= ", auto_validate";
146  $sql.= ", generate_pdf";
147  $sql.= ", fk_multicurrency";
148  $sql.= ", multicurrency_code";
149  $sql.= ", multicurrency_tx";
150  $sql.= ") VALUES (";
151  $sql.= "'".$this->db->escape($this->titre)."'";
152  $sql.= ", ".$facsrc->socid;
153  $sql.= ", ".$conf->entity;
154  $sql.= ", '".$this->db->idate($now)."'";
155  $sql.= ", ".(!empty($facsrc->amount)?$facsrc->amount:'0');
156  $sql.= ", ".(!empty($facsrc->remise)?$this->remise:'0');
157  $sql.= ", ".(!empty($this->note_private)?("'".$this->db->escape($this->note_private)."'"):"NULL");
158  $sql.= ", ".(!empty($this->note_public)?("'".$this->db->escape($this->note_public)."'"):"NULL");
159  $sql.= ", ".(!empty($this->modelpdf)?("'".$this->db->escape($this->modelpdf)."'"):"NULL");
160  $sql.= ", '".$this->db->escape($user->id)."'";
161  $sql.= ", ".(! empty($facsrc->fk_project)?"'".$facsrc->fk_project."'":"null");
162  $sql.= ", ".(! empty($facsrc->fk_account)?"'".$facsrc->fk_account."'":"null");
163  $sql.= ", ".($facsrc->cond_reglement_id > 0 ? $this->db->escape($facsrc->cond_reglement_id) : "null");
164  $sql.= ", ".($facsrc->mode_reglement_id > 0 ? $this->db->escape($facsrc->mode_reglement_id) : "null");
165  $sql.= ", ".$this->usenewprice;
166  $sql.= ", ".$this->frequency;
167  $sql.= ", '".$this->db->escape($this->unit_frequency)."'";
168  $sql.= ", ".(!empty($this->date_when)?"'".$this->db->idate($this->date_when)."'":'NULL');
169  $sql.= ", ".(!empty($this->date_last_gen)?"'".$this->db->idate($this->date_last_gen)."'":'NULL');
170  $sql.= ", ".$this->nb_gen_done;
171  $sql.= ", ".$this->nb_gen_max;
172  $sql.= ", ".$this->auto_validate;
173  $sql.= ", ".$this->generate_pdf;
174  $sql.= ", ".$facsrc->fk_multicurrency;
175  $sql.= ", '".$facsrc->multicurrency_code."'";
176  $sql.= ", ".$facsrc->multicurrency_tx;
177  $sql.= ")";
178 
179  if ($this->db->query($sql))
180  {
181  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."facture_rec");
182 
183  // Fields used into addline later
184  $this->fk_multicurrency = $facsrc->fk_multicurrency;
185  $this->multicurrency_code = $facsrc->multicurrency_code;
186  $this->multicurrency_tx = $facsrc->multicurrency_tx;
187 
188  // Add lines
189  $num=count($facsrc->lines);
190  for ($i = 0; $i < $num; $i++)
191  {
192  $tva_tx = $facsrc->lines[$i]->tva_tx;
193  if (! empty($facsrc->lines[$i]->vat_src_code) && ! preg_match('/\(/', $tva_tx)) $tva_tx .= ' ('.$facsrc->lines[$i]->vat_src_code.')';
194 
195  $result_insert = $this->addline(
196  $facsrc->lines[$i]->desc,
197  $facsrc->lines[$i]->subprice,
198  $facsrc->lines[$i]->qty,
199  $tva_tx,
200  $facsrc->lines[$i]->localtax1_tx,
201  $facsrc->lines[$i]->localtax2_tx,
202  $facsrc->lines[$i]->fk_product,
203  $facsrc->lines[$i]->remise_percent,
204  'HT',
205  0,
206  '',
207  0,
208  $facsrc->lines[$i]->product_type,
209  $facsrc->lines[$i]->rang,
210  $facsrc->lines[$i]->special_code,
211  $facsrc->lines[$i]->label,
212  $facsrc->lines[$i]->fk_unit,
213  $facsrc->lines[$i]->multicurrency_subprice
214  );
215 
216  if ($result_insert < 0)
217  {
218  $error++;
219  }
220  }
221 
222  if (! empty($this->linkedObjectsIds) && empty($this->linked_objects)) // To use new linkedObjectsIds instead of old linked_objects
223  {
224  $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
225  }
226 
227  // Add object linked
228  if (! $error && $this->id && is_array($this->linked_objects) && ! empty($this->linked_objects))
229  {
230  foreach($this->linked_objects as $origin => $tmp_origin_id)
231  {
232  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, ...))
233  {
234  foreach($tmp_origin_id as $origin_id)
235  {
236  $ret = $this->add_object_linked($origin, $origin_id);
237  if (! $ret)
238  {
239  $this->error=$this->db->lasterror();
240  $error++;
241  }
242  }
243  }
244  else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
245  {
246  $origin_id = $tmp_origin_id;
247  $ret = $this->add_object_linked($origin, $origin_id);
248  if (! $ret)
249  {
250  $this->error=$this->db->lasterror();
251  $error++;
252  }
253  }
254  }
255  }
256 
257  if ($error)
258  {
259  $this->db->rollback();
260  }
261  else
262  {
263  $this->db->commit();
264  return $this->id;
265  }
266  }
267  else
268  {
269  $this->error=$this->db->lasterror();
270  $this->db->rollback();
271  return -2;
272  }
273  }
274  else
275  {
276  $this->db->rollback();
277  return -1;
278  }
279  }
280 
281 
291  function fetch($rowid, $ref='', $ref_ext='', $ref_int='')
292  {
293  $sql = 'SELECT f.rowid, f.entity, f.titre, f.suspended, f.fk_soc, f.amount, f.tva, f.localtax1, f.localtax2, f.total, f.total_ttc';
294  $sql.= ', f.remise_percent, f.remise_absolue, f.remise';
295  $sql.= ', f.date_lim_reglement as dlr';
296  $sql.= ', f.note_private, f.note_public, f.fk_user_author';
297  $sql.= ', f.modelpdf';
298  $sql.= ', f.fk_mode_reglement, f.fk_cond_reglement, f.fk_projet';
299  $sql.= ', f.fk_account';
300  $sql.= ', f.frequency, f.unit_frequency, f.date_when, f.date_last_gen, f.nb_gen_done, f.nb_gen_max, f.usenewprice, f.auto_validate';
301  $sql.= ', f.generate_pdf';
302  $sql.= ", f.fk_multicurrency, f.multicurrency_code, f.multicurrency_tx, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc";
303  $sql.= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
304  $sql.= ', c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc';
305  //$sql.= ', el.fk_source';
306  $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_rec as f';
307  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as c ON f.fk_cond_reglement = c.rowid AND c.entity IN ('.getEntity('c_payment_term').')';
308  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON f.fk_mode_reglement = p.id AND p.entity IN ('.getEntity('c_paiement').')';
309  //$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture'";
310  $sql.= ' WHERE f.entity IN ('.getEntity('facture').')';
311  if ($rowid) $sql.= ' AND f.rowid='.$rowid;
312  elseif ($ref) $sql.= " AND f.titre='".$this->db->escape($ref)."'";
313  /* This field are not used for template invoice
314  if ($ref_ext) $sql.= " AND f.ref_ext='".$this->db->escape($ref_ext)."'";
315  if ($ref_int) $sql.= " AND f.ref_int='".$this->db->escape($ref_int)."'";
316  */
317 
318  $result = $this->db->query($sql);
319  if ($result)
320  {
321  if ($this->db->num_rows($result))
322  {
323  $obj = $this->db->fetch_object($result);
324 
325  $this->id = $obj->rowid;
326  $this->entity = $obj->entity;
327  $this->titre = $obj->titre;
328  $this->ref = $obj->titre;
329  $this->ref_client = $obj->ref_client;
330  $this->suspended = $obj->suspended;
331  $this->type = $obj->type;
332  $this->datep = $obj->dp;
333  $this->date = $obj->df;
334  $this->amount = $obj->amount;
335  $this->remise_percent = $obj->remise_percent;
336  $this->remise_absolue = $obj->remise_absolue;
337  $this->remise = $obj->remise;
338  $this->total_ht = $obj->total;
339  $this->total_tva = $obj->tva;
340  $this->total_localtax1 = $obj->localtax1;
341  $this->total_localtax2 = $obj->localtax2;
342  $this->total_ttc = $obj->total_ttc;
343  $this->paye = $obj->paye;
344  $this->close_code = $obj->close_code;
345  $this->close_note = $obj->close_note;
346  $this->socid = $obj->fk_soc;
347  $this->date_lim_reglement = $this->db->jdate($obj->dlr);
348  $this->mode_reglement_id = $obj->fk_mode_reglement;
349  $this->mode_reglement_code = $obj->mode_reglement_code;
350  $this->mode_reglement = $obj->mode_reglement_libelle;
351  $this->cond_reglement_id = $obj->fk_cond_reglement;
352  $this->cond_reglement_code = $obj->cond_reglement_code;
353  $this->cond_reglement = $obj->cond_reglement_libelle;
354  $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
355  $this->fk_project = $obj->fk_projet;
356  $this->fk_account = $obj->fk_account;
357  $this->fk_facture_source = $obj->fk_facture_source;
358  $this->note_private = $obj->note_private;
359  $this->note_public = $obj->note_public;
360  $this->user_author = $obj->fk_user_author;
361  $this->modelpdf = $obj->modelpdf;
362  $this->rang = $obj->rang;
363  $this->special_code = $obj->special_code;
364  $this->frequency = $obj->frequency;
365  $this->unit_frequency = $obj->unit_frequency;
366  $this->date_when = $this->db->jdate($obj->date_when);
367  $this->date_last_gen = $this->db->jdate($obj->date_last_gen);
368  $this->nb_gen_done = $obj->nb_gen_done;
369  $this->nb_gen_max = $obj->nb_gen_max;
370  $this->usenewprice = $obj->usenewprice;
371  $this->auto_validate = $obj->auto_validate;
372  $this->generate_pdf = $obj->generate_pdf;
373 
374  // Multicurrency
375  $this->fk_multicurrency = $obj->fk_multicurrency;
376  $this->multicurrency_code = $obj->multicurrency_code;
377  $this->multicurrency_tx = $obj->multicurrency_tx;
378  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
379  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
380  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
381 
382  if ($this->statut == self::STATUS_DRAFT) $this->brouillon = 1;
383 
384  // Retreive all extrafield for thirdparty
385  // fetch optionals attributes and labels
386  require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php');
387  $extrafields=new ExtraFields($this->db);
388  $extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true);
389  $this->fetch_optionals($this->id,$extralabels);
390 
391  /*
392  * Lines
393  */
394  $result=$this->fetch_lines();
395  if ($result < 0)
396  {
397  $this->error=$this->db->lasterror();
398  return -3;
399  }
400  return 1;
401  }
402  else
403  {
404  $this->error='Bill with id '.$rowid.' or ref '.$ref.' not found sql='.$sql;
405  dol_syslog('Facture::Fetch Error '.$this->error, LOG_ERR);
406  return -2;
407  }
408  }
409  else
410  {
411  $this->error=$this->db->error();
412  return -1;
413  }
414  }
415 
416 
422  function getLinesArray()
423  {
424  return $this->fetch_lines();
425  }
426 
427 
433  function fetch_lines()
434  {
435  $this->lines=array();
436 
437  // Retreive all extrafield for line
438  // fetch optionals attributes and labels
439  require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php');
440  $extrafieldsline=new ExtraFields($this->db);
441  $extrafieldsline=$extrafieldsline->fetch_name_optionals_label('facturedet_rec',true);
442 
443  $sql = 'SELECT l.rowid, l.fk_product, l.product_type, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.vat_src_code, l.tva_tx, ';
444  $sql.= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
445  $sql.= ' l.info_bits, l.total_ht, l.total_tva, l.total_ttc,';
446  //$sql.= ' l.situation_percent, l.fk_prev_id,';
447  //$sql.= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise_percent, l.fk_remise_except, l.subprice,';
448  $sql.= ' l.rang, l.special_code,';
449  //$sql.= ' l.info_bits, l.total_ht, l.total_tva, l.total_localtax1, l.total_localtax2, l.total_ttc, l.fk_code_ventilation, l.fk_product_fournisseur_price as fk_fournprice, l.buy_price_ht as pa_ht,';
450  $sql.= ' l.fk_unit, l.fk_contract_line,';
451  $sql.= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
452  $sql.= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
453  $sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet_rec as l';
454  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
455  $sql.= ' WHERE l.fk_facture = '.$this->id;
456  $sql.= ' ORDER BY l.rang';
457 
458  dol_syslog('FactureRec::fetch_lines', LOG_DEBUG);
459  $result = $this->db->query($sql);
460  if ($result)
461  {
462  $num = $this->db->num_rows($result);
463  $i = 0;
464  while ($i < $num)
465  {
466  $objp = $this->db->fetch_object($result);
467  $line = new FactureLigneRec($this->db);
468 
469  $line->id = $objp->rowid;
470  $line->rowid = $objp->rowid;
471  $line->label = $objp->custom_label; // Label line
472  $line->desc = $objp->description; // Description line
473  $line->description = $objp->description; // Description line
474  $line->product_type = $objp->product_type; // Type of line
475  $line->ref = $objp->product_ref; // Ref product
476  $line->product_ref = $objp->product_ref; // Ref product
477  $line->libelle = $objp->product_label; // deprecated
478  $line->product_label = $objp->product_label; // Label product
479  $line->product_desc = $objp->product_desc; // Description product
480  $line->fk_product_type = $objp->fk_product_type; // Type of product
481  $line->qty = $objp->qty;
482  $line->subprice = $objp->subprice;
483 
484  $line->vat_src_code = $objp->vat_src_code;
485  $line->tva_tx = $objp->tva_tx;
486  $line->localtax1_tx = $objp->localtax1_tx;
487  $line->localtax2_tx = $objp->localtax2_tx;
488  $line->localtax1_type = $objp->localtax1_type;
489  $line->localtax2_type = $objp->localtax2_type;
490  $line->remise_percent = $objp->remise_percent;
491  $line->fk_remise_except = $objp->fk_remise_except;
492  $line->fk_product = $objp->fk_product;
493  $line->info_bits = $objp->info_bits;
494  $line->total_ht = $objp->total_ht;
495  $line->total_tva = $objp->total_tva;
496  $line->total_ttc = $objp->total_ttc;
497  $line->code_ventilation = $objp->fk_code_ventilation;
498  $line->rang = $objp->rang;
499  $line->special_code = $objp->special_code;
500  $line->fk_unit = $objp->fk_unit;
501  $line->fk_contract_line = $objp->fk_contract_line;
502 
503  // Ne plus utiliser
504  $line->price = $objp->price;
505  $line->remise = $objp->remise;
506 
507  $extralabelsline = $line->fetch_optionals($line->id,$extrafieldsline);
508 
509  // Multicurrency
510  $line->fk_multicurrency = $objp->fk_multicurrency;
511  $line->multicurrency_code = $objp->multicurrency_code;
512  $line->multicurrency_subprice = $objp->multicurrency_subprice;
513  $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
514  $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
515  $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
516 
517  $this->lines[$i] = $line;
518 
519  $i++;
520  }
521 
522  $this->db->free($result);
523  return 1;
524  }
525  else
526  {
527  $this->error=$this->db->lasterror();
528  return -3;
529  }
530  }
531 
532 
541  function delete(User $user, $notrigger=0, $idwarehouse=-1)
542  {
543  $rowid=$this->id;
544 
545  dol_syslog(get_class($this)."::delete rowid=".$rowid, LOG_DEBUG);
546 
547  $error=0;
548  $this->db->begin();
549 
550  $sql = "DELETE FROM ".MAIN_DB_PREFIX."facturedet_rec WHERE fk_facture = ".$rowid;
551  dol_syslog($sql);
552  if ($this->db->query($sql))
553  {
554  $sql = "DELETE FROM ".MAIN_DB_PREFIX."facture_rec WHERE rowid = ".$rowid;
555  dol_syslog($sql);
556  if ($this->db->query($sql))
557  {
558  // Delete linked object
559  $res = $this->deleteObjectLinked();
560  if ($res < 0) $error=-3;
561  }
562  else
563  {
564  $this->error=$this->db->lasterror();
565  $error=-1;
566  }
567  }
568  else
569  {
570  $this->error=$this->db->lasterror();
571  $error=-2;
572  }
573 
574  if (! $error)
575  {
576  $this->db->commit();
577  return 1;
578  }
579  else
580  {
581  $this->db->rollback();
582  return $error;
583  }
584  }
585 
586 
610  function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $info_bits=0, $fk_remise_except='', $pu_ttc=0, $type=0, $rang=-1, $special_code=0, $label='', $fk_unit=null, $pu_ht_devise=0)
611  {
612  global $mysoc;
613 
614  $facid=$this->id;
615 
616  dol_syslog(get_class($this)."::addline facid=$facid,desc=$desc,pu_ht=$pu_ht,qty=$qty,txtva=$txtva,txlocaltax1=$txlocaltax1,txlocaltax2=$txlocaltax2,fk_product=$fk_product,remise_percent=$remise_percent,info_bits=$info_bits,fk_remise_except=$fk_remise_except,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type,fk_unit=$fk_unit,pu_ht_devise=$pu_ht_devise", LOG_DEBUG);
617  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
618 
619  // Check parameters
620  if ($type < 0) return -1;
621 
622  $localtaxes_type=getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
623 
624  // Clean vat code
625  $vat_src_code='';
626  if (preg_match('/\((.*)\)/', $txtva, $reg))
627  {
628  $vat_src_code = $reg[1];
629  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
630  }
631 
632  if ($this->brouillon)
633  {
634  // Clean parameters
635  $remise_percent=price2num($remise_percent);
636  if (empty($remise_percent)) $remise_percent=0;
637  $qty=price2num($qty);
638  if (! $info_bits) $info_bits=0;
639  $pu_ht = price2num($pu_ht);
640  $pu_ttc = price2num($pu_ttc);
641  $txtva = price2num($txtva);
642  $txlocaltax1 = price2num($txlocaltax1);
643  $txlocaltax2 = price2num($txlocaltax2);
644  if (empty($txtva)) $txtva=0;
645  if (empty($txlocaltax1)) $txlocaltax1=0;
646  if (empty($txlocaltax2)) $txlocaltax2=0;
647 
648  if ($price_base_type=='HT')
649  {
650  $pu=$pu_ht;
651  }
652  else
653  {
654  $pu=$pu_ttc;
655  }
656 
657  // Calcul du total TTC et de la TVA pour la ligne a partir de
658  // qty, pu, remise_percent et txtva
659  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
660  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
661 
662  $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);
663  $total_ht = $tabprice[0];
664  $total_tva = $tabprice[1];
665  $total_ttc = $tabprice[2];
666  $total_localtax1=$tabprice[9];
667  $total_localtax2=$tabprice[10];
668  $pu_ht = $tabprice[3];
669 
670  // MultiCurrency
671  $multicurrency_total_ht = $tabprice[16];
672  $multicurrency_total_tva = $tabprice[17];
673  $multicurrency_total_ttc = $tabprice[18];
674  $pu_ht_devise = $tabprice[19];
675 
676  $product_type=$type;
677  if ($fk_product)
678  {
679  $product=new Product($this->db);
680  $result=$product->fetch($fk_product);
681  $product_type=$product->type;
682  }
683 
684  $sql = "INSERT INTO ".MAIN_DB_PREFIX."facturedet_rec (";
685  $sql.= "fk_facture";
686  $sql.= ", label";
687  $sql.= ", description";
688  $sql.= ", price";
689  $sql.= ", qty";
690  $sql.= ", tva_tx";
691  $sql.= ", vat_src_code";
692  $sql.= ", localtax1_tx";
693  $sql.= ", localtax1_type";
694  $sql.= ", localtax2_tx";
695  $sql.= ", localtax2_type";
696  $sql.= ", fk_product";
697  $sql.= ", product_type";
698  $sql.= ", remise_percent";
699  $sql.= ", subprice";
700  $sql.= ", remise";
701  $sql.= ", total_ht";
702  $sql.= ", total_tva";
703  $sql.= ", total_localtax1";
704  $sql.= ", total_localtax2";
705  $sql.= ", total_ttc";
706  $sql.= ", rang";
707  $sql.= ", special_code";
708  $sql.= ", fk_unit";
709  $sql.= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
710  $sql.= ") VALUES (";
711  $sql.= "'".$facid."'";
712  $sql.= ", ".(! empty($label)?"'".$this->db->escape($label)."'":"null");
713  $sql.= ", '".$this->db->escape($desc)."'";
714  $sql.= ", ".price2num($pu_ht);
715  $sql.= ", ".price2num($qty);
716  $sql.= ", ".price2num($txtva);
717  $sql.= ", '".$this->db->escape($vat_src_code)."'";
718  $sql.= ", ".price2num($txlocaltax1);
719  $sql.= ", '".$this->db->escape($localtaxes_type[0])."'";
720  $sql.= ", ".price2num($txlocaltax2);
721  $sql.= ", '".$this->db->escape($localtaxes_type[2])."'";
722  $sql.= ", ".(! empty($fk_product)?"'".$fk_product."'":"null");
723  $sql.= ", ".$product_type;
724  $sql.= ", ".price2num($remise_percent);
725  $sql.= ", ".price2num($pu_ht);
726  $sql.= ", null";
727  $sql.= ", ".price2num($total_ht);
728  $sql.= ", ".price2num($total_tva);
729  $sql.= ", ".price2num($total_localtax1);
730  $sql.= ", ".price2num($total_localtax2);
731  $sql.= ", ".price2num($total_ttc);
732  $sql.= ", ".$rang;
733  $sql.= ", ".$special_code;
734  $sql.= ", ".($fk_unit?"'".$this->db->escape($fk_unit)."'":"null");
735  $sql.= ", ".(int) $this->fk_multicurrency;
736  $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
737  $sql.= ", ".price2num($pu_ht_devise);
738  $sql.= ", ".price2num($multicurrency_total_ht);
739  $sql.= ", ".price2num($multicurrency_total_tva);
740  $sql.= ", ".price2num($multicurrency_total_ttc);
741  $sql.= ")";
742 
743  dol_syslog(get_class($this)."::addline", LOG_DEBUG);
744  if ($this->db->query($sql))
745  {
746  $lineId = $this->db->last_insert_id(MAIN_DB_PREFIX."facturedet_rec");
747  $this->id=$facid;
748  $this->update_price();
749  return $lineId;
750  }
751  else
752  {
753  $this->error=$this->db->lasterror();
754  return -1;
755  }
756  }
757  }
758 
784  function updateline($rowid, $desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $info_bits=0, $fk_remise_except='', $pu_ttc=0, $type=0, $rang=-1, $special_code=0, $label='', $fk_unit=null, $pu_ht_devise = 0, $notrigger=0)
785  {
786  global $mysoc;
787 
788  $facid=$this->id;
789 
790  dol_syslog(get_class($this)."::updateline facid=".$facid." rowid=$rowid, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, txlocaltax1=$txlocaltax1, txlocaltax2=$txlocaltax2, fk_product=$fk_product, remise_percent=$remise_percent, info_bits=$info_bits, fk_remise_except=$fk_remise_except, price_base_type=$price_base_type, pu_ttc=$pu_ttc, type=$type, fk_unit=$fk_unit, pu_ht_devise=$pu_ht_devise", LOG_DEBUG);
791  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
792 
793  // Clean parameters
794  if (empty($remise_percent)) $remise_percent = 0;
795 
796  // Check parameters
797  if ($type < 0) return -1;
798 
799  $localtaxes_type=getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
800 
801  // Clean vat code
802  $vat_src_code='';
803  if (preg_match('/\((.*)\)/', $txtva, $reg))
804  {
805  $vat_src_code = $reg[1];
806  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
807  }
808 
809  if ($this->brouillon)
810  {
811  // Clean parameters
812  $remise_percent=price2num($remise_percent);
813  $qty=price2num($qty);
814  if (! $info_bits) $info_bits=0;
815  $pu_ht=price2num($pu_ht);
816  $pu_ttc=price2num($pu_ttc);
817  $txtva=price2num($txtva);
818  $txlocaltax1 = price2num($txlocaltax1);
819  $txlocaltax2 = price2num($txlocaltax2);
820  if (empty($txlocaltax1)) $txlocaltax1=0;
821  if (empty($txlocaltax2)) $txlocaltax2=0;
822 
823  if (empty($this->multicurrency_subprice)) $this->multicurrency_subprice=0;
824  if (empty($this->multicurrency_total_ht)) $this->multicurrency_total_ht=0;
825  if (empty($this->multicurrency_total_tva)) $this->multicurrency_total_tva=0;
826  if (empty($this->multicurrency_total_ttc)) $this->multicurrency_total_ttc=0;
827 
828  if ($price_base_type=='HT')
829  {
830  $pu=$pu_ht;
831  }
832  else
833  {
834  $pu=$pu_ttc;
835  }
836 
837  // Calcul du total TTC et de la TVA pour la ligne a partir de
838  // qty, pu, remise_percent et txtva
839  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
840  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
841  $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);
842 
843  $total_ht = $tabprice[0];
844  $total_tva = $tabprice[1];
845  $total_ttc = $tabprice[2];
846  $total_localtax1=$tabprice[9];
847  $total_localtax2=$tabprice[10];
848  $pu_ht = $tabprice[3];
849  $pu_tva = $tabprice[4];
850  $pu_ttc = $tabprice[5];
851 
852  // MultiCurrency
853  $multicurrency_total_ht = $tabprice[16];
854  $multicurrency_total_tva = $tabprice[17];
855  $multicurrency_total_ttc = $tabprice[18];
856  $pu_ht_devise = $tabprice[19];
857 
858  $product_type=$type;
859  if ($fk_product)
860  {
861  $product=new Product($this->db);
862  $result=$product->fetch($fk_product);
863  $product_type=$product->type;
864  }
865 
866  $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET ";
867  $sql.= "fk_facture = '".$facid."'";
868  $sql.= ", label=".(! empty($label)?"'".$this->db->escape($label)."'":"null");
869  $sql.= ", description='".$this->db->escape($desc)."'";
870  $sql.= ", price=".price2num($pu_ht);
871  $sql.= ", qty=".price2num($qty);
872  $sql.= ", tva_tx=".price2num($txtva);
873  $sql.= ", vat_src_code='".$this->db->escape($vat_src_code)."'";
874  $sql.= ", localtax1_tx=".$txlocaltax1;
875  $sql.= ", localtax1_type='".$this->db->escape($localtaxes_type[0])."'";
876  $sql.= ", localtax2_tx=".$txlocaltax2;
877  $sql.= ", localtax2_type='".$this->db->escape($localtaxes_type[2])."'";
878  $sql.= ", fk_product=".(! empty($fk_product)?"'".$fk_product."'":"null");
879  $sql.= ", product_type=".$product_type;
880  $sql.= ", remise_percent='".price2num($remise_percent)."'";
881  $sql.= ", subprice='".price2num($pu_ht)."'";
882  $sql.= ", total_ht='".price2num($total_ht)."'";
883  $sql.= ", total_tva='".price2num($total_tva)."'";
884  $sql.= ", total_localtax1='".price2num($total_localtax1)."'";
885  $sql.= ", total_localtax2='".price2num($total_localtax2)."'";
886  $sql.= ", total_ttc='".price2num($total_ttc)."'";
887  $sql.= ", rang=".$rang;
888  $sql.= ", special_code=".$special_code;
889  $sql.= ", fk_unit=".($fk_unit?"'".$this->db->escape($fk_unit)."'":"null");
890  $sql.= ', multicurrency_subprice = '.$pu_ht_devise;
891  $sql.= ', multicurrency_total_ht = '.$multicurrency_total_ht;
892  $sql.= ', multicurrency_total_tva = '.$multicurrency_total_tva;
893  $sql.= ', multicurrency_total_ttc = '.$multicurrency_total_ttc;
894  $sql.= " WHERE rowid = ".$rowid;
895 
896  dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
897  if ($this->db->query($sql))
898  {
899  $this->id=$facid;
900  $this->update_price();
901  return 1;
902  }
903  else
904  {
905  $this->error=$this->db->lasterror();
906  return -1;
907  }
908  }
909  }
910 
911 
917  function getNextDate()
918  {
919  if (empty($this->date_when)) return false;
920  return dol_time_plus_duree($this->date_when, $this->frequency, $this->unit_frequency);
921  }
922 
928  function isMaxNbGenReached()
929  {
930  $ret = false;
931  if ($this->nb_gen_max > 0 && ($this->nb_gen_done >= $this->nb_gen_max)) $ret = true;
932  return $ret;
933  }
934 
941  function strikeIfMaxNbGenReached($ret)
942  {
943  // Special case to strike the date
944  return ($this->isMaxNbGenReached()?'<strike>':'').$ret.($this->isMaxNbGenReached()?'</strike>':'');
945  }
946 
956  {
957  global $conf, $langs, $db, $user;
958 
959  $langs->load("bills");
960 
961  $nb_create=0;
962 
963  $now = dol_now();
964  $tmparray=dol_getdate($now);
965  $today = dol_mktime(23,59,59,$tmparray['mon'],$tmparray['mday'],$tmparray['year']); // Today is last second of current day
966 
967  dol_syslog("createRecurringInvoices");
968  $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'facture_rec';
969  $sql.= ' WHERE frequency > 0'; // A recurring invoice is an invoice with a frequency
970  $sql.= " AND (date_when IS NULL OR date_when <= '".$db->idate($today)."')";
971  $sql.= ' AND (nb_gen_done < nb_gen_max OR nb_gen_max = 0)';
972  $sql.= ' AND suspended = 0';
973  $sql.= $db->order('entity', 'ASC');
974  //print $sql;exit;
975 
976  $resql = $db->query($sql);
977  if ($resql)
978  {
979  $i=0;
980  $num = $db->num_rows($resql);
981 
982  if ($num) $this->output.=$langs->trans("FoundXQualifiedRecurringInvoiceTemplate", $num)."\n";
983  else $this->output.=$langs->trans("NoQualifiedRecurringInvoiceTemplateFound");
984 
985  $saventity = $conf->entity;
986 
987  while ($i < $num) // Loop on each template invoice
988  {
989  $line = $db->fetch_object($resql);
990 
991  $db->begin();
992 
993  $facturerec = new FactureRec($db);
994  $facturerec->fetch($line->rowid);
995 
996  // Set entity context
997  $conf->entity = $facturerec->entity;
998 
999  dol_syslog("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref.", entity=".$facturerec->entity);
1000 
1001  $error=0;
1002 
1003  $facture = new Facture($db);
1004  $facture->fac_rec = $facturerec->id; // We will create $facture from this recurring invoice
1005  $facture->fk_fac_rec_source = $facturerec->id; // We will create $facture from this recurring invoice
1006 
1007  $facture->type = self::TYPE_STANDARD;
1008  $facture->brouillon = 1;
1009  $facture->date = $facturerec->date_when; // We could also use dol_now here but we prefer date_when so invoice has real date when we would like even if we generate later.
1010  $facture->socid = $facturerec->socid;
1011 
1012  $invoiceidgenerated = $facture->create($user);
1013  if ($invoiceidgenerated <= 0)
1014  {
1015  $this->errors = $facture->errors;
1016  $this->error = $facture->error;
1017  $error++;
1018  }
1019  if (! $error && $facturerec->auto_validate)
1020  {
1021  $result = $facture->validate($user);
1022  if ($result <= 0)
1023  {
1024  $this->errors = $facture->errors;
1025  $this->error = $facture->error;
1026  $error++;
1027  }
1028  }
1029  if (! $error && $facturerec->generate_pdf)
1030  {
1031  $result = $facture->generateDocument($facturerec->modelpdf, $langs);
1032  if ($result <= 0)
1033  {
1034  $this->errors = $facture->errors;
1035  $this->error = $facture->error;
1036  $error++;
1037  }
1038  }
1039 
1040  if (! $error && $invoiceidgenerated >= 0)
1041  {
1042  $db->commit("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref);
1043  dol_syslog("createRecurringInvoices Process invoice template ".$facturerec->ref." is finished with a success generation");
1044  $nb_create++;
1045  $this->output.=$langs->trans("InvoiceGeneratedFromTemplate", $facture->ref, $facturerec->ref)."\n";
1046  }
1047  else
1048  {
1049  $db->rollback("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref);
1050  }
1051 
1052  $i++;
1053  }
1054 
1055  $conf->entity = $saventity; // Restore entity context
1056  }
1057  else dol_print_error($db);
1058 
1059  $this->output=trim($this->output);
1060 
1061  return $error?$error:0;
1062  }
1063 
1076  function getNomUrl($withpicto=0,$option='',$max=0,$short=0,$moretitle='',$notooltip='',$save_lastsearch_value=-1)
1077  {
1078  global $langs;
1079 
1080  $result='';
1081  $label=$langs->trans("ShowInvoice").': '.$this->ref;
1082 
1083  $url = DOL_URL_ROOT.'/compta/facture/fiche-rec.php?facid='.$this->id;
1084 
1085  if ($short) return $url;
1086 
1087  if ($option != 'nolink')
1088  {
1089  // Add param to save lastsearch_values or not
1090  $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
1091  if ($save_lastsearch_value == -1 && preg_match('/list\.php/',$_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
1092  if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
1093  }
1094 
1095  $linkstart = '<a href="'.$url.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
1096  $linkend='</a>';
1097 
1098  $result .= $linkstart;
1099  if ($withpicto) $result.=img_object(($notooltip?'':$label), ($this->picto?$this->picto:'generic'), ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
1100  if ($withpicto != 2) $result.= $this->ref;
1101  $result .= $linkend;
1102 
1103  return $result;
1104  }
1105 
1113  function getLibStatut($mode=0, $alreadypaid=-1)
1114  {
1115 
1116  return $this->LibStatut($this->frequency?1:0, $this->suspended, $mode, $alreadypaid, empty($this->type)?0:$this->type);
1117  }
1118 
1129  function LibStatut($recur, $status, $mode=0, $alreadypaid=-1, $type=0)
1130  {
1131  global $langs;
1132  $langs->load('bills');
1133 
1134  //print "$recur,$status,$mode,$alreadypaid,$type";
1135  if ($mode == 0)
1136  {
1137  $prefix='';
1138  if ($recur)
1139  {
1140  if ($status == 1) return $langs->trans('Disabled'); // credit note
1141  else return $langs->trans('Active');
1142  }
1143  else return $langs->trans("Draft");
1144  }
1145  if ($mode == 1)
1146  {
1147  $prefix='Short';
1148  if ($recur)
1149  {
1150  if ($status == 1) return $langs->trans('Disabled');
1151  else return $langs->trans('Active');
1152  }
1153  else return $langs->trans("Draft");
1154  }
1155  if ($mode == 2)
1156  {
1157  if ($recur)
1158  {
1159  if ($status == 1) return img_picto($langs->trans('Disabled'),'statut6').' '.$langs->trans('Disabled');
1160  else return img_picto($langs->trans('Active'),'statut4').' '.$langs->trans('Active');
1161  }
1162  else return img_picto($langs->trans('Draft'),'statut0').' '.$langs->trans('Draft');
1163  }
1164  if ($mode == 3)
1165  {
1166  if ($recur)
1167  {
1168  $prefix='Short';
1169  if ($status == 1) return img_picto($langs->trans('Disabled'),'statut6');
1170  else return img_picto($langs->trans('Active'),'statut4');
1171  }
1172  else return img_picto($langs->trans('Draft'),'statut0');
1173  }
1174  if ($mode == 4)
1175  {
1176  $prefix='';
1177  if ($recur)
1178  {
1179  if ($status == 1) return img_picto($langs->trans('Disabled'),'statut6').' '.$langs->trans('Disabled');
1180  else return img_picto($langs->trans('Active'),'statut4').' '.$langs->trans('Active');
1181  }
1182  else return img_picto($langs->trans('Draft'),'statut0').' '.$langs->trans('Draft');
1183  }
1184  if ($mode == 5 || $mode == 6)
1185  {
1186  $prefix='';
1187  if ($mode == 5) $prefix='Short';
1188  if ($recur)
1189  {
1190  if ($status == 1) return '<span class="xhideonsmartphone">'.$langs->trans('Disabled').' </span>'.img_picto($langs->trans('Disabled'),'statut6');
1191  else return '<span class="xhideonsmartphone">'.$langs->trans('Active').' </span>'.img_picto($langs->trans('Active'),'statut4');
1192  }
1193  else return $langs->trans('Draft').' '.img_picto($langs->trans('Active'),'statut0');
1194  }
1195  }
1196 
1205  function initAsSpecimen($option='')
1206  {
1207  global $user,$langs,$conf;
1208 
1209  $now=dol_now();
1210  $arraynow=dol_getdate($now);
1211  $nownotime=dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
1212 
1213  // Load array of products prodids
1214  $num_prods = 0;
1215  $prodids = array();
1216 
1217  $sql = "SELECT rowid";
1218  $sql.= " FROM ".MAIN_DB_PREFIX."product";
1219  $sql.= " WHERE entity IN (".getEntity('product').")";
1220  $resql = $this->db->query($sql);
1221  if ($resql)
1222  {
1223  $num_prods = $this->db->num_rows($resql);
1224  $i = 0;
1225  while ($i < $num_prods)
1226  {
1227  $i++;
1228  $row = $this->db->fetch_row($resql);
1229  $prodids[$i] = $row[0];
1230  }
1231  }
1232 
1233  // Initialize parameters
1234  $this->id=0;
1235  $this->ref = 'SPECIMEN';
1236  $this->specimen=1;
1237  $this->socid = 1;
1238  $this->date = $nownotime;
1239  $this->date_lim_reglement = $nownotime + 3600 * 24 *30;
1240  $this->cond_reglement_id = 1;
1241  $this->cond_reglement_code = 'RECEP';
1242  $this->date_lim_reglement=$this->calculate_date_lim_reglement();
1243  $this->mode_reglement_id = 0; // Not forced to show payment mode CHQ + VIR
1244  $this->mode_reglement_code = ''; // Not forced to show payment mode CHQ + VIR
1245  $this->note_public='This is a comment (public)';
1246  $this->note_private='This is a comment (private)';
1247  $this->note='This is a comment (private)';
1248  $this->fk_incoterms=0;
1249  $this->location_incoterms='';
1250 
1251  if (empty($option) || $option != 'nolines')
1252  {
1253  // Lines
1254  $nbp = 5;
1255  $xnbp = 0;
1256  while ($xnbp < $nbp)
1257  {
1258  $line=new FactureLigne($this->db);
1259  $line->desc=$langs->trans("Description")." ".$xnbp;
1260  $line->qty=1;
1261  $line->subprice=100;
1262  $line->tva_tx=19.6;
1263  $line->localtax1_tx=0;
1264  $line->localtax2_tx=0;
1265  $line->remise_percent=0;
1266  if ($xnbp == 1) // Qty is negative (product line)
1267  {
1268  $prodid = mt_rand(1, $num_prods);
1269  $line->fk_product=$prodids[$prodid];
1270  $line->qty=-1;
1271  $line->total_ht=-100;
1272  $line->total_ttc=-119.6;
1273  $line->total_tva=-19.6;
1274  }
1275  else if ($xnbp == 2) // UP is negative (free line)
1276  {
1277  $line->subprice=-100;
1278  $line->total_ht=-100;
1279  $line->total_ttc=-119.6;
1280  $line->total_tva=-19.6;
1281  $line->remise_percent=0;
1282  }
1283  else if ($xnbp == 3) // Discount is 50% (product line)
1284  {
1285  $prodid = mt_rand(1, $num_prods);
1286  $line->fk_product=$prodids[$prodid];
1287  $line->total_ht=50;
1288  $line->total_ttc=59.8;
1289  $line->total_tva=9.8;
1290  $line->remise_percent=50;
1291  }
1292  else // (product line)
1293  {
1294  $prodid = mt_rand(1, $num_prods);
1295  $line->fk_product=$prodids[$prodid];
1296  $line->total_ht=100;
1297  $line->total_ttc=119.6;
1298  $line->total_tva=19.6;
1299  $line->remise_percent=00;
1300  }
1301 
1302  $this->lines[$xnbp]=$line;
1303  $xnbp++;
1304 
1305  $this->total_ht += $line->total_ht;
1306  $this->total_tva += $line->total_tva;
1307  $this->total_ttc += $line->total_ttc;
1308  }
1309  $this->revenuestamp = 0;
1310 
1311  // Add a line "offered"
1312  $line=new FactureLigne($this->db);
1313  $line->desc=$langs->trans("Description")." (offered line)";
1314  $line->qty=1;
1315  $line->subprice=100;
1316  $line->tva_tx=19.6;
1317  $line->localtax1_tx=0;
1318  $line->localtax2_tx=0;
1319  $line->remise_percent=100;
1320  $line->total_ht=0;
1321  $line->total_ttc=0; // 90 * 1.196
1322  $line->total_tva=0;
1323  $prodid = mt_rand(1, $num_prods);
1324  $line->fk_product=$prodids[$prodid];
1325 
1326  $this->lines[$xnbp]=$line;
1327  $xnbp++;
1328  }
1329 
1330  $this->usenewprice = 1;
1331  }
1332 
1341  public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
1342  {
1343  $tables = array(
1344  'facture_rec'
1345  );
1346 
1347  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
1348  }
1349 
1357  function setFrequencyAndUnit($frequency,$unit)
1358  {
1359  if (! $this->table_element)
1360  {
1361  dol_syslog(get_class($this)."::setFrequencyAndUnit was called on objet with property table_element not defined",LOG_ERR);
1362  return -1;
1363  }
1364 
1365  if (!empty($frequency) && empty($unit))
1366  {
1367  dol_syslog(get_class($this)."::setFrequencyAndUnit was called on objet with params frequency defined but unit not defined",LOG_ERR);
1368  return -2;
1369  }
1370 
1371  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1372  $sql.= ' SET frequency = '.($frequency?$this->db->escape($frequency):'null');
1373  if (!empty($unit))
1374  {
1375  $sql.= ', unit_frequency = \''.$this->db->escape($unit).'\'';
1376  }
1377  $sql.= ' WHERE rowid = '.$this->id;
1378 
1379  dol_syslog(get_class($this)."::setFrequencyAndUnit", LOG_DEBUG);
1380  if ($this->db->query($sql))
1381  {
1382  $this->frequency = $frequency;
1383  if (!empty($unit)) $this->unit_frequency = $unit;
1384  return 1;
1385  }
1386  else
1387  {
1388  dol_print_error($this->db);
1389  return -1;
1390  }
1391  }
1392 
1400  function setNextDate($date, $increment_nb_gen_done=0)
1401  {
1402  if (! $this->table_element)
1403  {
1404  dol_syslog(get_class($this)."::setNextDate was called on objet with property table_element not defined",LOG_ERR);
1405  return -1;
1406  }
1407  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1408  $sql.= " SET date_when = ".($date ? "'".$this->db->idate($date)."'" : "null");
1409  if ($increment_nb_gen_done>0) $sql.= ', nb_gen_done = nb_gen_done + 1';
1410  $sql.= ' WHERE rowid = '.$this->id;
1411 
1412  dol_syslog(get_class($this)."::setNextDate", LOG_DEBUG);
1413  if ($this->db->query($sql))
1414  {
1415  $this->date_when = $date;
1416  if ($increment_nb_gen_done>0) $this->nb_gen_done++;
1417  return 1;
1418  }
1419  else
1420  {
1421  dol_print_error($this->db);
1422  return -1;
1423  }
1424  }
1425 
1432  function setMaxPeriod($nb)
1433  {
1434  if (! $this->table_element)
1435  {
1436  dol_syslog(get_class($this)."::setMaxPeriod was called on objet with property table_element not defined",LOG_ERR);
1437  return -1;
1438  }
1439 
1440  if (empty($nb)) $nb=0;
1441 
1442  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1443  $sql.= ' SET nb_gen_max = '.$nb;
1444  $sql.= ' WHERE rowid = '.$this->id;
1445 
1446  dol_syslog(get_class($this)."::setMaxPeriod", LOG_DEBUG);
1447  if ($this->db->query($sql))
1448  {
1449  $this->nb_gen_max = $nb;
1450  return 1;
1451  }
1452  else
1453  {
1454  dol_print_error($this->db);
1455  return -1;
1456  }
1457  }
1458 
1465  function setAutoValidate($validate)
1466  {
1467  if (! $this->table_element)
1468  {
1469  dol_syslog(get_class($this)."::setAutoValidate was called on objet with property table_element not defined",LOG_ERR);
1470  return -1;
1471  }
1472 
1473  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1474  $sql.= ' SET auto_validate = '.$validate;
1475  $sql.= ' WHERE rowid = '.$this->id;
1476 
1477  dol_syslog(get_class($this)."::setAutoValidate", LOG_DEBUG);
1478  if ($this->db->query($sql))
1479  {
1480  $this->auto_validate = $validate;
1481  return 1;
1482  }
1483  else
1484  {
1485  dol_print_error($this->db);
1486  return -1;
1487  }
1488  }
1489 
1496  function setGeneratePdf($validate)
1497  {
1498  if (! $this->table_element)
1499  {
1500  dol_syslog(get_class($this)."::setGeneratePdf was called on objet with property table_element not defined",LOG_ERR);
1501  return -1;
1502  }
1503 
1504  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1505  $sql.= ' SET generate_pdf = '.$validate;
1506  $sql.= ' WHERE rowid = '.$this->id;
1507 
1508  dol_syslog(get_class($this)."::setGeneratePdf", LOG_DEBUG);
1509  if ($this->db->query($sql))
1510  {
1511  $this->generate_pdf = $validate;
1512  return 1;
1513  }
1514  else
1515  {
1516  dol_print_error($this->db);
1517  return -1;
1518  }
1519  }
1520 
1527  function setModelPdf($model)
1528  {
1529  if (! $this->table_element)
1530  {
1531  dol_syslog(get_class($this)."::setModelPdf was called on objet with property table_element not defined",LOG_ERR);
1532  return -1;
1533  }
1534 
1535  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1536  $sql.= ' SET modelpdf = "' . $model . '"';
1537  $sql.= ' WHERE rowid = '.$this->id;
1538 
1539  dol_syslog(get_class($this)."::setModelPdf", LOG_DEBUG);
1540  if ($this->db->query($sql))
1541  {
1542  $this->modelpdf = $model;
1543  return 1;
1544  }
1545  else
1546  {
1547  dol_print_error($this->db);
1548  return -1;
1549  }
1550  }
1551 }
1552 
1553 
1554 
1560 {
1561  public $element='facturedetrec';
1562  public $table_element='facturedet_rec';
1563 
1571  function delete(User $user, $notrigger = false)
1572  {
1573  $error=0;
1574 
1575  $this->db->begin();
1576 
1577  if (! $error) {
1578  if (! $notrigger) {
1579  // Call triggers
1580  $result=$this->call_trigger('LINEBILLREC_DELETE', $user);
1581  if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
1582  // End call triggers
1583  }
1584  }
1585 
1586  if (! $error)
1587  {
1588  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
1589 
1590  $res = $this->db->query($sql);
1591  if($res===false) {
1592  $error++;
1593  $this->errors[] = $this->db->lasterror();
1594  }
1595  }
1596 
1597  // Commit or rollback
1598  if ($error) {
1599  $this->db->rollback();
1600  return -1;
1601  } else {
1602  $this->db->commit();
1603  return 1;
1604  }
1605  }
1606 
1607 
1614  function fetch($rowid)
1615  {
1616  $sql = 'SELECT l.rowid, l.fk_facture ,l.fk_product, l.product_type, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.vat_src_code, l.tva_tx,';
1617  $sql.= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
1618  $sql.= ' l.info_bits, l.total_ht, l.total_tva, l.total_ttc,';
1619  $sql.= ' l.rang, l.special_code,';
1620  $sql.= ' l.fk_unit, l.fk_contract_line,';
1621  $sql.= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
1622  $sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet_rec as l';
1623  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
1624  $sql.= ' WHERE l.rowid = '.$rowid;
1625  $sql.= ' ORDER BY l.rang';
1626 
1627  dol_syslog('FactureRec::fetch', LOG_DEBUG);
1628  $result = $this->db->query($sql);
1629  if ($result)
1630  {
1631 
1632  $objp = $this->db->fetch_object($result);
1633 
1634  $this->id = $objp->rowid;
1635  $this->label = $objp->custom_label; // Label line
1636  $this->desc = $objp->description; // Description line
1637  $this->description = $objp->description; // Description line
1638  $this->product_type = $objp->product_type; // Type of line
1639  $this->ref = $objp->product_ref; // Ref product
1640  $this->product_ref = $objp->product_ref; // Ref product
1641  $this->libelle = $objp->product_label; // deprecated
1642  $this->product_label = $objp->product_label; // Label product
1643  $this->product_desc = $objp->product_desc; // Description product
1644  $this->fk_product_type = $objp->fk_product_type; // Type of product
1645  $this->qty = $objp->qty;
1646  $this->price = $objp->price;
1647  $this->subprice = $objp->subprice;
1648  $this->fk_facture = $objp->fk_facture;
1649  $this->vat_src_code = $objp->vat_src_code;
1650  $this->tva_tx = $objp->tva_tx;
1651  $this->localtax1_tx = $objp->localtax1_tx;
1652  $this->localtax2_tx = $objp->localtax2_tx;
1653  $this->localtax1_type = $objp->localtax1_type;
1654  $this->localtax2_type = $objp->localtax2_type;
1655  $this->remise_percent = $objp->remise_percent;
1656  $this->fk_remise_except = $objp->fk_remise_except;
1657  $this->fk_product = $objp->fk_product;
1658  $this->info_bits = $objp->info_bits;
1659  $this->total_ht = $objp->total_ht;
1660  $this->total_tva = $objp->total_tva;
1661  $this->total_ttc = $objp->total_ttc;
1662  $this->code_ventilation = $objp->fk_code_ventilation;
1663  $this->rang = $objp->rang;
1664  $this->special_code = $objp->special_code;
1665  $this->fk_unit = $objp->fk_unit;
1666  $this->fk_contract_line = $objp->fk_contract_line;
1667 
1668 
1669  $this->db->free($result);
1670  return 1;
1671  }
1672  else
1673  {
1674  $this->error=$this->db->lasterror();
1675  return -3;
1676  }
1677  }
1678 
1679 
1685  function update()
1686  {
1687  global $user;
1688 
1689  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1690 
1691  if ($fk_product)
1692  {
1693  $product=new Product($this->db);
1694  $result=$product->fetch($fk_product);
1695  $product_type=$product->type;
1696  }
1697 
1698  $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET ";
1699  $sql.= " fk_facture = ".$this->fk_facture;
1700  $sql.= ", label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null");
1701  $sql.= ", description='".$this->db->escape($this->desc)."'";
1702  $sql.= ", price=".price2num($this->price);
1703  $sql.= ", qty=".price2num($this->qty);
1704  $sql.= ", tva_tx=".price2num($this->tva_tx);
1705  $sql.= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
1706  $sql.= ", localtax1_tx=".price2num($this->localtax1_tx);
1707  $sql.= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
1708  $sql.= ", localtax2_tx=".price2num($this->localtax2_tx);
1709  $sql.= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
1710  $sql.= ", fk_product=".($this->fk_product > 0 ? $this->fk_product :"null");
1711  $sql.= ", product_type=".$this->product_type;
1712  $sql.= ", remise_percent='".price2num($this->remise_percent)."'";
1713  $sql.= ", subprice='".price2num($this->subprice)."'";
1714  $sql.= ", total_ht='".price2num($this->total_ht)."'";
1715  $sql.= ", total_tva='".price2num($this->total_tva)."'";
1716  $sql.= ", total_localtax1='".price2num($this->total_localtax1)."'";
1717  $sql.= ", total_localtax2='".price2num($this->total_localtax2)."'";
1718  $sql.= ", total_ttc='".price2num($this->total_ttc)."'";
1719  $sql.= ", rang=".$this->rang;
1720  $sql.= ", special_code=".$this->special_code;
1721  $sql.= ", fk_unit=".($this->fk_unit ?"'".$this->db->escape($this->fk_unit )."'":"null");
1722  $sql.= ", fk_contract_line=".($this->fk_contract_line?$this->fk_contract_line:"null");
1723 
1724  $sql.= " WHERE rowid = ".$this->id;
1725 
1726  dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
1727  $resql=$this->db->query($sql);
1728  if ($resql)
1729  {
1730  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
1731  {
1732  $result=$this->insertExtraFields();
1733  if ($result < 0)
1734  {
1735  $error++;
1736  }
1737  }
1738 
1739  if (! $notrigger)
1740  {
1741  // Call trigger
1742  $result=$this->call_trigger('LINEBILL_REC_UPDATE',$user);
1743  if ($result < 0)
1744  {
1745  $this->db->rollback();
1746  return -2;
1747  }
1748  // End call triggers
1749  }
1750  $this->db->commit();
1751  return 1;
1752  }
1753  else
1754  {
1755  $this->error=$this->db->error();
1756  $this->db->rollback();
1757  return -2;
1758  }
1759 
1760  }
1761 
1762 }
setNextDate($date, $increment_nb_gen_done=0)
Update the next date of execution.
calculate_date_lim_reglement($cond_reglement=0)
Renvoi une date limite de reglement de facture en fonction des conditions de reglements de la facture...
Class to manage invoice lines of templates.
img_picto($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='')
Show picto whatever it's its name (generic function)
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
Delete all links between an object $this.
addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $info_bits=0, $fk_remise_except='', $pu_ttc=0, $type=0, $rang=-1, $special_code=0, $label='', $fk_unit=null, $pu_ht_devise=0)
Add a line to invoice.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm=false, $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
</td >< tdclass="liste_titre"align="right"></td ></tr >< trclass="liste_titre">< inputtype="checkbox"onClick="toggle(this)"/> Ref p ref Label p label Duration p duration warehouseinternal SELECT description FROM product_lang WHERE qty< br > qty qty qty StockTooLow img yes disabled img no img no< trclass="oddeven">< td >< inputtype="checkbox"class="check"name="'.$i.'"'.$disabled.'></td >< td >< inputtype="checkbox"class="check"name="choose'.$i.'"></td >< tdclass="nowrap"></td >< td >< inputtype="hidden"name="desc'.$i.'"value="'.dol_escape_htmltag($objp-> description
Only used if Module[ID]Desc translation string is not found.
Definition: replenish.php:554
Class to manage products or services.
Class to manage invoice templates.
Class to manage Dolibarr users.
Definition: user.class.php:39
Class to manage Dolibarr database access.
setAutoValidate($validate)
Update the auto validate invoice.
fetch($rowid, $ref='', $ref_ext='', $ref_int='')
Load object and lines.
setGeneratePdf($validate)
Update the auto generate documents.
getLinesArray()
Create an array of invoice lines.
getNextDate()
Return the next date of.
dol_print_error($db='', $error='', $errors=null)
Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remonte...
initAsSpecimen($option='')
Initialise an instance with random values.
Parent class of all other business classes for details of elements (invoices, contracts, proposals, orders, ...)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields...
Class to manage standard extra fields.
__construct($db)
Constructor.
createRecurringInvoices()
Create all recurrents invoices (for all entities if multicompany is used).
fetch_lines()
Recupere les lignes de factures predefinies dans this->lines.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='')
Write log message into outputs.
setMaxPeriod($nb)
Update the maximum period.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
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)...
static commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
getEntity($element, $shared=1, $forceentity=null)
Get list of entity id to use.
img_object($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
getNomUrl($withpicto=0, $option='', $max=0, $short=0, $moretitle='', $notooltip='', $save_lastsearch_value=-1)
Return clicable name (with picto eventually)
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...
Superclass for invoices classes.
strikeIfMaxNbGenReached($ret)
Format string to output with by striking the string if max number of generation was reached...
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller= '', $localtaxes_array='', $progress=100, $multicurrency_tx=1, $pu_devise=0)
Calculate totals (net, vat, ...) of a line.
Definition: price.lib.php:85
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages...
fetch($rowid)
Recupere les lignes de factures predefinies dans this->lines.
update()
Update a line to invoice_rec.
updateline($rowid, $desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $info_bits=0, $fk_remise_except='', $pu_ttc=0, $type=0, $rang=-1, $special_code=0, $label='', $fk_unit=null, $pu_ht_devise=0, $notrigger=0)
Update a line to invoice.
create($user, $facid)
Create a predefined invoice.
setFrequencyAndUnit($frequency, $unit)
Update frequency and unit.
static replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
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:1013
LibStatut($recur, $status, $mode=0, $alreadypaid=-1, $type=0)
Return label of a status.
setModelPdf($model)
Update the model for documents.
isMaxNbGenReached()
Return if maximum number of generation is reached.
Class to manage invoices.
dol_getdate($timestamp, $fast=false)
Return an array with locale date info.
call_trigger($trigger_name, $user)
Call trigger based on this instance.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
add_object_linked($origin=null, $origin_id=null)
Add objects linked in llx_element_element.
dol_time_plus_duree($time, $duration_value, $duration_unit)
Add a delay to a date.
Definition: date.lib.php:116
type
Definition: viewcat.php:283
price2num($amount, $rounding='', $alreadysqlnb=0)
Function that return a number with universal decimal format (decimal separator is '...
getLibStatut($mode=0, $alreadypaid=-1)
Return label of object status.
Class to manage invoice lines.