dolibarr  7.0.0-beta
fournisseur.facture.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-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2004 Christophe Combelles <ccomb@free.fr>
5  * Copyright (C) 2005 Marc Barilley <marc@ocebo.com>
6  * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com>
7  * Copyright (C) 2010-2017 Juanjo Menent <jmenent@2byte.es>
8  * Copyright (C) 2013 Philippe Grand <philippe.grand@atoo-net.com>
9  * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
10  * Copyright (C) 2014-2016 Marcos García <marcosgdf@gmail.com>
11  * Copyright (C) 2015 Bahfir Abbes <bafbes@gmail.com>
12  * Copyright (C) 2015 Ferran Marcet <fmarcet@2byte.es>
13  * Copyright (C) 2016 Alexandre Spangaro <aspangaro@zendsi.com>
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program. If not, see <http://www.gnu.org/licenses/>.
27  */
28 
35 include_once DOL_DOCUMENT_ROOT.'/core/class/commoninvoice.class.php';
36 require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
37 
42 {
43  public $element='invoice_supplier';
44  public $table_element='facture_fourn';
45  public $table_element_line='facture_fourn_det';
46  public $fk_element='fk_facture_fourn';
47  public $picto='bill';
52  public $ismultientitymanaged = 1;
57  public $restrictiononfksoc = 1;
58 
62  protected $table_ref_field = 'ref';
63 
64  public $rowid;
65  public $ref;
66  public $product_ref;
67  public $ref_supplier;
68  public $socid;
69  //Check constants for types
70  public $type = self::TYPE_STANDARD;
71 
77  public $statut;
78 
84  public $paye;
85 
86  public $author;
87  public $libelle;
88  public $datec; // Creation date
89  public $tms; // Last update date
90  public $date; // Invoice date
91  public $date_echeance; // Max payment date
92  public $amount;
93  public $remise;
94  public $tva;
95  public $localtax1;
96  public $localtax2;
97  public $total_ht;
98  public $total_tva;
99  public $total_localtax1;
100  public $total_localtax2;
101  public $total_ttc;
106  public $note;
107  public $note_private;
108  public $note_public;
109  public $propalid;
110  public $cond_reglement_id;
111  public $cond_reglement_code;
112  public $fk_account;
113  public $mode_reglement_id;
114  public $mode_reglement_code;
115 
120  public $lines = array();
124  public $fournisseur;
125 
126  //Incorterms
127  public $fk_incoterms;
128  public $location_incoterms;
129  public $libelle_incoterms; //Used into tooltip
130 
131  public $extraparams=array();
132 
133  // Multicurrency
134  public $fk_multicurrency;
135  public $multicurrency_code;
136  public $multicurrency_tx;
137  public $multicurrency_total_ht;
138  public $multicurrency_total_tva;
139  public $multicurrency_total_ttc;
142 
146  const TYPE_STANDARD = 0;
147 
151  const TYPE_REPLACEMENT = 1;
152 
156  const TYPE_CREDIT_NOTE = 2;
157 
161  const TYPE_DEPOSIT = 3;
162 
166  const STATUS_DRAFT = 0;
167 
171  const STATUS_VALIDATED = 1;
172 
180  const STATUS_CLOSED = 2;
181 
189  const STATUS_ABANDONED = 3;
190 
191  const CLOSECODE_DISCOUNTVAT = 'discount_vat';
192  const CLOSECODE_BADCREDIT = 'badsupplier';
193  const CLOSECODE_ABANDONED = 'abandon';
194  const CLOSECODE_REPLACED = 'replaced';
195 
201  public function __construct($db)
202  {
203  $this->db = $db;
204 
205  $this->amount = 0;
206  $this->remise = 0;
207  $this->tva = 0;
208  $this->total_localtax1 = 0;
209  $this->total_localtax2 = 0;
210  $this->total_ht = 0;
211  $this->total_tva = 0;
212  $this->total_ttc = 0;
213  $this->propalid = 0;
214 
215  $this->products = array();
216  }
217 
224  public function create($user)
225  {
226  global $langs,$conf,$hookmanager;
227 
228  $error=0;
229  $now=dol_now();
230 
231  // Clean parameters
232  if (isset($this->ref_supplier)) $this->ref_supplier=trim($this->ref_supplier);
233  if (empty($this->type)) $this->type = self::TYPE_STANDARD;
234  if (empty($this->date)) $this->date=$now;
235 
236  $socid = $this->socid;
237  $ref_supplier = $this->ref_supplier;
238  $amount = $this->amount;
239  $remise = $this->remise;
240 
241  // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
242  if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) list($this->fk_multicurrency,$this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
243  else $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
244  if (empty($this->fk_multicurrency))
245  {
246  $this->multicurrency_code = $conf->currency;
247  $this->fk_multicurrency = 0;
248  $this->multicurrency_tx = 1;
249  }
250 
251  $this->db->begin();
252 
253  if (! $remise) $remise = 0 ;
254  $totalht = ($amount - $remise);
255 
256  $sql = "INSERT INTO ".MAIN_DB_PREFIX."facture_fourn (";
257  $sql.= "ref";
258  $sql.= ", ref_supplier";
259  $sql.= ", entity";
260  $sql.= ", type";
261  $sql.= ", libelle";
262  $sql.= ", fk_soc";
263  $sql.= ", datec";
264  $sql.= ", datef";
265  $sql.= ", fk_projet";
266  $sql.= ", fk_cond_reglement";
267  $sql.= ", fk_mode_reglement";
268  $sql.= ", fk_account";
269  $sql.= ", note_private";
270  $sql.= ", note_public";
271  $sql.= ", fk_user_author";
272  $sql.= ", date_lim_reglement";
273  $sql.= ", fk_incoterms, location_incoterms";
274  $sql.= ", fk_multicurrency";
275  $sql.= ", multicurrency_code";
276  $sql.= ", multicurrency_tx";
277  $sql.= ", fk_facture_source";
278  $sql.= ")";
279  $sql.= " VALUES (";
280  $sql.= "'(PROV)'";
281  $sql.= ", '".$this->db->escape($this->ref_supplier)."'";
282  $sql.= ", ".$conf->entity;
283  $sql.= ", '".$this->db->escape($this->type)."'";
284  $sql.= ", '".$this->db->escape($this->libelle)."'";
285  $sql.= ", ".$this->socid;
286  $sql.= ", '".$this->db->idate($now)."'";
287  $sql.= ", '".$this->db->idate($this->date)."'";
288  $sql.= ", ".(isset($this->fk_project)?$this->fk_project:"null");
289  $sql.= ", ".(isset($this->cond_reglement_id)?$this->cond_reglement_id:"null");
290  $sql.= ", ".(isset($this->mode_reglement_id)?$this->mode_reglement_id:"null");
291  $sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL');
292  $sql.= ", '".$this->db->escape($this->note_private)."'";
293  $sql.= ", '".$this->db->escape($this->note_public)."'";
294  $sql.= ", ".$user->id.",";
295  $sql.= $this->date_echeance!=''?"'".$this->db->idate($this->date_echeance)."'":"null";
296  $sql.= ", ".(int) $this->fk_incoterms;
297  $sql.= ", '".$this->db->escape($this->location_incoterms)."'";
298  $sql.= ", ".(int) $this->fk_multicurrency;
299  $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
300  $sql.= ", ".(double) $this->multicurrency_tx;
301  $sql.= ", ".(isset($this->fk_facture_source)?$this->fk_facture_source:"NULL");
302  $sql.= ")";
303 
304  dol_syslog(get_class($this)."::create", LOG_DEBUG);
305  $resql=$this->db->query($sql);
306  if ($resql)
307  {
308  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn');
309 
310  // Update ref with new one
311  $this->ref='(PROV'.$this->id.')';
312  $sql = 'UPDATE '.MAIN_DB_PREFIX."facture_fourn SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".$this->id;
313 
314  dol_syslog(get_class($this)."::create", LOG_DEBUG);
315  $resql=$this->db->query($sql);
316  if (! $resql) $error++;
317 
318  if (! empty($this->linkedObjectsIds) && empty($this->linked_objects)) // To use new linkedObjectsIds instead of old linked_objects
319  {
320  $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
321  }
322 
323  // Add object linked
324  if (! $error && $this->id && is_array($this->linked_objects) && ! empty($this->linked_objects))
325  {
326  foreach($this->linked_objects as $origin => $tmp_origin_id)
327  {
328  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, ...))
329  {
330  foreach($tmp_origin_id as $origin_id)
331  {
332  $ret = $this->add_object_linked($origin, $origin_id);
333  if (! $ret)
334  {
335  dol_print_error($this->db);
336  $error++;
337  }
338  }
339  }
340  else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
341  {
342  $origin_id = $tmp_origin_id;
343  $ret = $this->add_object_linked($origin, $origin_id);
344  if (! $ret)
345  {
346  dol_print_error($this->db);
347  $error++;
348  }
349  }
350  }
351  }
352 
353  // Add linked object (deprecated, use ->linkedObjectsIds instead)
354  if (! $error && $this->id && ! empty($this->origin) && ! empty($this->origin_id))
355  {
356  $ret = $this->add_object_linked();
357  if (! $ret)
358  {
359  dol_print_error($this->db);
360  $error++;
361  }
362  }
363 
364  if (count($this->lines) && is_object($this->lines[0])) // If this->lines is array of InvoiceLines (preferred mode)
365  {
366  dol_syslog("There is ".count($this->lines)." lines that are invoice lines objects");
367  foreach ($this->lines as $i => $val)
368  {
369  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn)';
370  $sql .= ' VALUES ('.$this->id.')';
371 
372  $resql_insert=$this->db->query($sql);
373  if ($resql_insert)
374  {
375  $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det');
376 
377  $this->updateline(
378  $idligne,
379  $this->lines[$i]->description,
380  $this->lines[$i]->pu_ht,
381  $this->lines[$i]->tva_tx,
382  $this->lines[$i]->localtax1_tx,
383  $this->lines[$i]->localtax2_tx,
384  $this->lines[$i]->qty,
385  $this->lines[$i]->fk_product,
386  'HT',
387  (! empty($this->lines[$i]->info_bits)?$this->lines[$i]->info_bits:''),
388  $this->lines[$i]->product_type
389  );
390  }
391  else
392  {
393  $this->error=$this->db->lasterror();
394  $this->db->rollback();
395  return -5;
396  }
397  }
398  }
399  else // If this->lines is an array of invoice line arrays
400  {
401  dol_syslog("There is ".count($this->lines)." lines that are array lines");
402  foreach ($this->lines as $i => $val)
403  {
404  $line = $this->lines[$i];
405 
406  // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
407  //if (! is_object($line)) $line=json_decode(json_encode($line), FALSE); // convert recursively array into object.
408  if (! is_object($line)) $line = (object) $line;
409 
410  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn)';
411  $sql .= ' VALUES ('.$this->id.')';
412 
413  $resql_insert=$this->db->query($sql);
414  if ($resql_insert)
415  {
416  $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det');
417 
418  $this->updateline(
419  $idligne,
420  $line->description,
421  $line->pu_ht,
422  $line->tva_tx,
423  $line->localtax1_tx,
424  $line->localtax2_tx,
425  $line->qty,
426  $line->fk_product,
427  'HT',
428  (! empty($line->info_bits)?$line->info_bits:''),
429  $line->product_type
430  );
431  }
432  else
433  {
434  $this->error=$this->db->lasterror();
435  $this->db->rollback();
436  return -5;
437  }
438  }
439  }
440 
441  // Update total price
442  $result=$this->update_price();
443  if ($result > 0)
444  {
445  $action='create';
446 
447  // Actions on extra fields (by external module or standard code)
448  // TODO le hook fait double emploi avec le trigger !!
449  $hookmanager->initHooks(array('supplierinvoicedao'));
450  $parameters=array('socid'=>$this->id);
451  $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks
452  if (empty($reshook))
453  {
454  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
455  {
456  $result=$this->insertExtraFields(); // This also set $this->error or $this->errors if errors are found
457  if ($result < 0)
458  {
459  $error++;
460  }
461  }
462  }
463  else if ($reshook < 0) $error++;
464 
465  if (! $error)
466  {
467  // Call trigger
468  $result=$this->call_trigger('BILL_SUPPLIER_CREATE',$user);
469  if ($result < 0) $error++;
470  // End call triggers
471  }
472 
473  if (! $error)
474  {
475  $this->db->commit();
476  return $this->id;
477  }
478  else
479  {
480  $this->db->rollback();
481  return -4;
482  }
483  }
484  else
485  {
486  $this->error=$langs->trans('FailedToUpdatePrice');
487  $this->db->rollback();
488  return -3;
489  }
490  }
491  else
492  {
493  if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS')
494  {
495  $this->error=$langs->trans('ErrorRefAlreadyExists');
496  $this->db->rollback();
497  return -1;
498  }
499  else
500  {
501  $this->error=$this->db->lasterror();
502  $this->db->rollback();
503  return -2;
504  }
505  }
506  }
507 
515  public function fetch($id='',$ref='')
516  {
517  global $langs;
518 
519  $sql = "SELECT";
520  $sql.= " t.rowid,";
521  $sql.= " t.ref,";
522  $sql.= " t.ref_supplier,";
523  $sql.= " t.entity,";
524  $sql.= " t.type,";
525  $sql.= " t.fk_soc,";
526  $sql.= " t.datec,";
527  $sql.= " t.datef,";
528  $sql.= " t.tms,";
529  $sql.= " t.libelle,";
530  $sql.= " t.paye,";
531  $sql.= " t.amount,";
532  $sql.= " t.remise,";
533  $sql.= " t.close_code,";
534  $sql.= " t.close_note,";
535  $sql.= " t.tva,";
536  $sql.= " t.localtax1,";
537  $sql.= " t.localtax2,";
538  //$sql.= " t.total,";
539  $sql.= " t.total_ht,";
540  $sql.= " t.total_tva,";
541  $sql.= " t.total_ttc,";
542  $sql.= " t.fk_statut,";
543  $sql.= " t.fk_user_author,";
544  $sql.= " t.fk_user_valid,";
545  $sql.= " t.fk_facture_source,";
546  $sql.= " t.fk_projet,";
547  $sql.= " t.fk_cond_reglement,";
548  $sql.= " t.fk_account,";
549  $sql.= " t.fk_mode_reglement,";
550  $sql.= " t.date_lim_reglement,";
551  $sql.= " t.note_private,";
552  $sql.= " t.note_public,";
553  $sql.= " t.model_pdf,";
554  $sql.= " t.import_key,";
555  $sql.= " t.extraparams,";
556  $sql.= " cr.code as cond_reglement_code, cr.libelle as cond_reglement_libelle,";
557  $sql.= " p.code as mode_reglement_code, p.libelle as mode_reglement_libelle,";
558  $sql.= ' s.nom as socnom, s.rowid as socid,';
559  $sql.= ' t.fk_incoterms, t.location_incoterms,';
560  $sql.= " i.libelle as libelle_incoterms,";
561  $sql.= ' t.fk_multicurrency, t.multicurrency_code, t.multicurrency_tx, t.multicurrency_total_ht, t.multicurrency_total_tva, t.multicurrency_total_ttc';
562  $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as t';
563  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON (t.fk_soc = s.rowid)";
564  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_payment_term as cr ON t.fk_cond_reglement = cr.rowid AND cr.entity IN (".getEntity('c_payment_term').")";
565  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as p ON t.fk_mode_reglement = p.id AND p.entity IN (".getEntity('c_paiement').")";
566  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON t.fk_incoterms = i.rowid';
567  if ($id) $sql.= " WHERE t.rowid=".$id;
568  if ($ref) $sql.= " WHERE t.ref='".$this->db->escape($ref)."'";
569 
570  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
571  $resql=$this->db->query($sql);
572  if ($resql)
573  {
574  if ($this->db->num_rows($resql))
575  {
576  $obj = $this->db->fetch_object($resql);
577 
578  $this->id = $obj->rowid;
579  $this->ref = $obj->ref?$obj->ref:$obj->rowid; // We take rowid if ref is empty for backward compatibility
580 
581  $this->ref_supplier = $obj->ref_supplier;
582  $this->entity = $obj->entity;
583  $this->type = empty($obj->type)? self::TYPE_STANDARD:$obj->type;
584  $this->fk_soc = $obj->fk_soc;
585  $this->datec = $this->db->jdate($obj->datec);
586  $this->date = $this->db->jdate($obj->datef);
587  $this->datep = $this->db->jdate($obj->datef);
588  $this->tms = $this->db->jdate($obj->tms);
589  $this->libelle = $obj->libelle;
590  $this->label = $obj->libelle;
591  $this->paye = $obj->paye;
592  $this->amount = $obj->amount;
593  $this->remise = $obj->remise;
594  $this->close_code = $obj->close_code;
595  $this->close_note = $obj->close_note;
596  $this->tva = $obj->tva;
597  $this->total_localtax1 = $obj->localtax1;
598  $this->total_localtax2 = $obj->localtax2;
599  //$this->total = $obj->total;
600  $this->total_ht = $obj->total_ht;
601  $this->total_tva = $obj->total_tva;
602  $this->total_ttc = $obj->total_ttc;
603  $this->fk_statut = $obj->fk_statut;
604  $this->statut = $obj->fk_statut;
605  $this->fk_user_author = $obj->fk_user_author;
606  $this->author = $obj->fk_user_author;
607  $this->fk_user_valid = $obj->fk_user_valid;
608  $this->fk_facture_source = $obj->fk_facture_source;
609  $this->fk_project = $obj->fk_projet;
610  $this->cond_reglement_id = $obj->fk_cond_reglement;
611  $this->cond_reglement_code = $obj->cond_reglement_code;
612  $this->cond_reglement = $obj->cond_reglement_libelle;
613  $this->cond_reglement_doc = $obj->cond_reglement_libelle;
614  $this->fk_account = $obj->fk_account;
615  $this->mode_reglement_id = $obj->fk_mode_reglement;
616  $this->mode_reglement_code = $obj->mode_reglement_code;
617  $this->mode_reglement = $obj->mode_reglement_libelle;
618  $this->date_echeance = $this->db->jdate($obj->date_lim_reglement);
619  $this->note = $obj->note_private; // deprecated
620  $this->note_private = $obj->note_private;
621  $this->note_public = $obj->note_public;
622  $this->model_pdf = $obj->model_pdf;
623  $this->modelpdf = $obj->model_pdf;
624  $this->import_key = $obj->import_key;
625 
626  //Incoterms
627  $this->fk_incoterms = $obj->fk_incoterms;
628  $this->location_incoterms = $obj->location_incoterms;
629  $this->libelle_incoterms = $obj->libelle_incoterms;
630 
631  // Multicurrency
632  $this->fk_multicurrency = $obj->fk_multicurrency;
633  $this->multicurrency_code = $obj->multicurrency_code;
634  $this->multicurrency_tx = $obj->multicurrency_tx;
635  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
636  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
637  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
638 
639  $this->extraparams = (array) json_decode($obj->extraparams, true);
640 
641  $this->socid = $obj->socid;
642  $this->socnom = $obj->socnom;
643 
644  // Retreive all extrafield
645  // fetch optionals attributes and labels
646  require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php');
647  $extrafields=new ExtraFields($this->db);
648  $extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true);
649  $this->fetch_optionals($this->id,$extralabels);
650 
651  if ($this->statut == self::STATUS_DRAFT) $this->brouillon = 1;
652 
653  $result=$this->fetch_lines();
654  if ($result < 0)
655  {
656  $this->error=$this->db->lasterror();
657  return -3;
658  }
659 
660  }
661  else
662  {
663  $this->error='Bill with id '.$id.' not found';
664  dol_syslog(get_class($this).'::fetch '.$this->error);
665  return 0;
666  }
667 
668  $this->db->free($resql);
669  return 1;
670  }
671  else
672  {
673  $this->error="Error ".$this->db->lasterror();
674  return -1;
675  }
676  }
677 
678 
684  function fetch_lines()
685  {
686  $sql = 'SELECT f.rowid, f.ref as ref_supplier, f.description, f.pu_ht, f.pu_ttc, f.qty, f.remise_percent, f.vat_src_code, f.tva_tx';
687  $sql.= ', f.localtax1_tx, f.localtax2_tx, f.localtax1_type, f.localtax2_type, f.total_localtax1, f.total_localtax2, f.fk_facture_fourn ';
688  $sql.= ', f.total_ht, f.tva as total_tva, f.total_ttc, f.fk_product, f.product_type, f.info_bits, f.rang, f.special_code, f.fk_parent_line, f.fk_unit';
689  $sql.= ', p.rowid as product_id, p.ref as product_ref, p.label as label, p.description as product_desc';
690  $sql.= ', f.fk_multicurrency, f.multicurrency_code, f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc';
691  $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
692  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
693  $sql.= ' WHERE fk_facture_fourn='.$this->id;
694  $sql.= ' ORDER BY f.rang, f.rowid';
695 
696 
697  dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
698  $resql_rows = $this->db->query($sql);
699  if ($resql_rows)
700  {
701  $num_rows = $this->db->num_rows($resql_rows);
702  if ($num_rows)
703  {
704  $i = 0;
705  while ($i < $num_rows)
706  {
707  $obj = $this->db->fetch_object($resql_rows);
708 
709  $line = new SupplierInvoiceLine($this->db);
710 
711  $line->id = $obj->rowid;
712  $line->rowid = $obj->rowid;
713  $line->description = $obj->description;
714  $line->product_ref = $obj->product_ref;
715  $line->ref = $obj->product_ref;
716  $line->ref_supplier = $obj->ref_supplier;
717  $line->libelle = $obj->label;
718  $line->label = $obj->label;
719  $line->product_desc = $obj->product_desc;
720  $line->subprice = $obj->pu_ht;
721  $line->pu_ht = $obj->pu_ht;
722  $line->pu_ttc = $obj->pu_ttc;
723 
724  $line->vat_src_code = $obj->vat_src_code;
725  $line->tva_tx = $obj->tva_tx;
726  $line->localtax1_tx = $obj->localtax1_tx;
727  $line->localtax2_tx = $obj->localtax2_tx;
728  $line->localtax1_type = $obj->localtax1_type;
729  $line->localtax2_type = $obj->localtax2_type;
730  $line->qty = $obj->qty;
731  $line->remise_percent = $obj->remise_percent;
732  $line->tva = $obj->total_tva;
733  $line->total_ht = $obj->total_ht;
734  $line->total_tva = $obj->total_tva;
735  $line->total_localtax1 = $obj->total_localtax1;
736  $line->total_localtax2 = $obj->total_localtax2;
737  $line->fk_facture_fourn = $obj->fk_facture_fourn;
738  $line->total_ttc = $obj->total_ttc;
739  $line->fk_product = $obj->fk_product;
740  $line->product_type = $obj->product_type;
741  $line->product_label = $obj->label;
742  $line->info_bits = $obj->info_bits;
743  $line->fk_parent_line = $obj->fk_parent_line;
744  $line->special_code = $obj->special_code;
745  $line->rang = $obj->rang;
746  $line->fk_unit = $obj->fk_unit;
747 
748  // Multicurrency
749  $line->fk_multicurrency = $obj->fk_multicurrency;
750  $line->multicurrency_code = $obj->multicurrency_code;
751  $line->multicurrency_subprice = $obj->multicurrency_subprice;
752  $line->multicurrency_total_ht = $obj->multicurrency_total_ht;
753  $line->multicurrency_total_tva = $obj->multicurrency_total_tva;
754  $line->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
755 
756  $this->lines[$i] = $line;
757 
758  $i++;
759  }
760  }
761  $this->db->free($resql_rows);
762  return 1;
763  }
764  else
765  {
766  $this->error=$this->db->error();
767  return -3;
768  }
769  }
770 
771 
779  public function update($user=null, $notrigger=0)
780  {
781  global $conf, $langs;
782  $error=0;
783 
784  // Clean parameters
785  if (empty($this->type)) $this->type= self::TYPE_STANDARD;
786  if (isset($this->ref)) $this->ref=trim($this->ref);
787  if (isset($this->ref_supplier)) $this->ref_supplier=trim($this->ref_supplier);
788  if (isset($this->entity)) $this->entity=trim($this->entity);
789  if (isset($this->type)) $this->type=trim($this->type);
790  if (isset($this->fk_soc)) $this->fk_soc=trim($this->fk_soc);
791  if (isset($this->libelle)) $this->libelle=trim($this->libelle);
792  if (isset($this->paye)) $this->paye=trim($this->paye);
793  if (isset($this->amount)) $this->amount=trim($this->amount);
794  if (isset($this->remise)) $this->remise=trim($this->remise);
795  if (isset($this->close_code)) $this->close_code=trim($this->close_code);
796  if (isset($this->close_note)) $this->close_note=trim($this->close_note);
797  if (isset($this->tva)) $this->tva=trim($this->tva);
798  if (isset($this->localtax1)) $this->localtax1=trim($this->localtax1);
799  if (isset($this->localtax2)) $this->localtax2=trim($this->localtax2);
800  if (empty($this->total_ht)) $this->total_ht=0;
801  if (empty($this->total_tva)) $this->total_tva=0;
802  // if (isset($this->total_localtax1)) $this->total_localtax1=trim($this->total_localtax1);
803  // if (isset($this->total_localtax2)) $this->total_localtax2=trim($this->total_localtax2);
804  if (isset($this->total_ttc)) $this->total_ttc=trim($this->total_ttc);
805  if (isset($this->statut)) $this->statut=(int) $this->statut;
806  if (isset($this->author)) $this->author=trim($this->author);
807  if (isset($this->fk_user_valid)) $this->fk_user_valid=trim($this->fk_user_valid);
808  if (isset($this->fk_facture_source)) $this->fk_facture_source=trim($this->fk_facture_source);
809  if (isset($this->fk_project)) $this->fk_project=trim($this->fk_project);
810  if (isset($this->cond_reglement_id)) $this->cond_reglement_id=trim($this->cond_reglement_id);
811  if (isset($this->note_private)) $this->note=trim($this->note_private);
812  if (isset($this->note_public)) $this->note_public=trim($this->note_public);
813  if (isset($this->model_pdf)) $this->model_pdf=trim($this->model_pdf);
814  if (isset($this->import_key)) $this->import_key=trim($this->import_key);
815 
816 
817  // Check parameters
818  // Put here code to add control on parameters values
819 
820  // Update request
821  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn SET";
822  $sql.= " ref=".(isset($this->ref)?"'".$this->db->escape($this->ref)."'":"null").",";
823  $sql.= " ref_supplier=".(isset($this->ref_supplier)?"'".$this->db->escape($this->ref_supplier)."'":"null").",";
824  $sql.= " entity=".(isset($this->entity)?$this->entity:"null").",";
825  $sql.= " type=".(isset($this->type)?$this->type:"null").",";
826  $sql.= " fk_soc=".(isset($this->fk_soc)?$this->fk_soc:"null").",";
827  $sql.= " datec=".(dol_strlen($this->datec)!=0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
828  $sql.= " datef=".(dol_strlen($this->date)!=0 ? "'".$this->db->idate($this->date)."'" : 'null').",";
829  if (dol_strlen($this->tms) != 0) $sql.= " tms=".(dol_strlen($this->tms)!=0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
830  $sql.= " libelle=".(isset($this->label)?"'".$this->db->escape($this->label)."'":"null").",";
831  $sql.= " paye=".(isset($this->paye)?$this->paye:"null").",";
832  $sql.= " amount=".(isset($this->amount)?$this->amount:"null").",";
833  $sql.= " remise=".(isset($this->remise)?$this->remise:"null").",";
834  $sql.= " close_code=".(isset($this->close_code)?"'".$this->db->escape($this->close_code)."'":"null").",";
835  $sql.= " close_note=".(isset($this->close_note)?"'".$this->db->escape($this->close_note)."'":"null").",";
836  $sql.= " tva=".(isset($this->tva)?$this->tva:"null").",";
837  $sql.= " localtax1=".(isset($this->localtax1)?$this->localtax1:"null").",";
838  $sql.= " localtax2=".(isset($this->localtax2)?$this->localtax2:"null").",";
839  //$sql.= " total=".(isset($this->total)?$this->total:"null").",";
840  $sql.= " total_ht=".(isset($this->total_ht)?$this->total_ht:"null").",";
841  $sql.= " total_tva=".(isset($this->total_tva)?$this->total_tva:"null").",";
842  $sql.= " total_ttc=".(isset($this->total_ttc)?$this->total_ttc:"null").",";
843  $sql.= " fk_statut=".(isset($this->statut)?$this->statut:"null").",";
844  $sql.= " fk_user_author=".(isset($this->author)?$this->author:"null").",";
845  $sql.= " fk_user_valid=".(isset($this->fk_user_valid)?$this->fk_user_valid:"null").",";
846  $sql.= " fk_facture_source=".(isset($this->fk_facture_source)?$this->fk_facture_source:"null").",";
847  $sql.= " fk_projet=".(isset($this->fk_project)?$this->fk_project:"null").",";
848  $sql.= " fk_cond_reglement=".(isset($this->cond_reglement_id)?$this->cond_reglement_id:"null").",";
849  $sql.= " date_lim_reglement=".(dol_strlen($this->date_echeance)!=0 ? "'".$this->db->idate($this->date_echeance)."'" : 'null').",";
850  $sql.= " note_private=".(isset($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null").",";
851  $sql.= " note_public=".(isset($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null").",";
852  $sql.= " model_pdf=".(isset($this->model_pdf)?"'".$this->db->escape($this->model_pdf)."'":"null").",";
853  $sql.= " import_key=".(isset($this->import_key)?"'".$this->db->escape($this->import_key)."'":"null")."";
854  $sql.= " WHERE rowid=".$this->id;
855 
856  $this->db->begin();
857 
858  dol_syslog(get_class($this)."::update", LOG_DEBUG);
859  $resql = $this->db->query($sql);
860 
861  if (!$resql) {
862  $error++;
863 
864  if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
865  $this->errors[] = $langs->trans('ErrorRefAlreadyExists');
866  } else {
867  $this->errors[] = "Error ".$this->db->lasterror();
868  }
869  }
870 
871  if (! $error)
872  {
873  if (! $notrigger)
874  {
875  // Call trigger
876  $result=$this->call_trigger('BILL_SUPPLIER_UPDATE',$user);
877  if ($result < 0) $error++;
878  // End call triggers
879  }
880  }
881 
882  // Commit or rollback
883  if ($error)
884  {
885  foreach($this->errors as $errmsg)
886  {
887  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
888  $this->error.=($this->error?', '.$errmsg:$errmsg);
889  }
890  $this->db->rollback();
891  return -1*$error;
892  }
893  else
894  {
895  $this->db->commit();
896  return 1;
897  }
898  }
899 
900 
908  public function delete(User $user, $notrigger=0)
909  {
910  global $langs,$conf;
911 
912  $rowid=$this->id;
913 
914  dol_syslog("FactureFournisseur::delete rowid=".$rowid, LOG_DEBUG);
915 
916  // TODO Test if there is at least on payment. If yes, refuse to delete.
917 
918  $error=0;
919  $this->db->begin();
920 
921  if (! $error && ! $notrigger)
922  {
923  // Call trigger
924  $result=$this->call_trigger('BILL_SUPPLIER_DELETE',$user);
925  if ($result < 0)
926  {
927  $this->db->rollback();
928  return -1;
929  }
930  // Fin appel triggers
931  }
932 
933  if (! $error)
934  {
935  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det WHERE fk_facture_fourn = '.$rowid.';';
936  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
937  $resql = $this->db->query($sql);
938  if ($resql)
939  {
940  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn WHERE rowid = '.$rowid;
941  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
942  $resql2 = $this->db->query($sql);
943  if (! $resql2) {
944  $error++;
945  }
946  }
947  else {
948  $error++;
949  }
950  }
951 
952  if (! $error)
953  {
954  // Delete linked object
955  $res = $this->deleteObjectLinked();
956  if ($res < 0) $error++;
957  }
958 
959  if (! $error)
960  {
961  // Delete linked object
962  $res = $this->deleteObjectLinked();
963  if ($res < 0) $error++;
964  }
965 
966  if (! $error)
967  {
968  // We remove directory
969  if ($conf->fournisseur->facture->dir_output)
970  {
971  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
972 
973  $ref = dol_sanitizeFileName($this->ref);
974  $dir = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoive_supplier').$ref;
975  $file = $dir . "/" . $ref . ".pdf";
976  if (file_exists($file))
977  {
978  if (! dol_delete_file($file,0,0,0,$this)) // For triggers
979  {
980  $this->error='ErrorFailToDeleteFile';
981  $error++;
982  }
983  }
984  if (file_exists($dir))
985  {
986  $res=@dol_delete_dir_recursive($dir);
987 
988  if (! $res)
989  {
990  $this->error='ErrorFailToDeleteDir';
991  $error++;
992  }
993  }
994  }
995  }
996 
997  // Remove extrafields
998  if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used
999  {
1000  $result=$this->deleteExtraFields();
1001  if ($result < 0)
1002  {
1003  $error++;
1004  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1005  }
1006  }
1007 
1008  if (! $error)
1009  {
1010  dol_syslog(get_class($this)."::delete $this->id by $user->id", LOG_DEBUG);
1011  $this->db->commit();
1012  return 1;
1013  }
1014  else
1015  {
1016  $this->error=$this->db->lasterror();
1017  $this->db->rollback();
1018  return -$error;
1019  }
1020  }
1021 
1022 
1031  function set_paid($user, $close_code='', $close_note='')
1032  {
1033  global $conf,$langs;
1034  $error=0;
1035 
1036  $this->db->begin();
1037 
1038  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn';
1039  $sql.= ' SET paye = 1, fk_statut=2';
1040  $sql.= ' WHERE rowid = '.$this->id;
1041 
1042  dol_syslog("FactureFournisseur::set_paid", LOG_DEBUG);
1043  $resql = $this->db->query($sql);
1044  if ($resql)
1045  {
1046  // Call trigger
1047  $result=$this->call_trigger('BILL_SUPPLIER_PAYED',$user);
1048  if ($result < 0) $error++;
1049  // End call triggers
1050  }
1051  else
1052  {
1053  $error++;
1054  $this->error=$this->db->error();
1055  dol_print_error($this->db);
1056  }
1057 
1058  if (! $error)
1059  {
1060  $this->db->commit();
1061  return 1;
1062  }
1063  else
1064  {
1065  $this->db->rollback();
1066  return -1;
1067  }
1068  }
1069 
1070 
1079  function set_unpaid($user)
1080  {
1081  global $conf,$langs;
1082  $error=0;
1083 
1084  $this->db->begin();
1085 
1086  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn';
1087  $sql.= ' SET paye=0, fk_statut=1, close_code=null, close_note=null';
1088  $sql.= ' WHERE rowid = '.$this->id;
1089 
1090  dol_syslog("FactureFournisseur::set_unpaid", LOG_DEBUG);
1091  $resql = $this->db->query($sql);
1092  if ($resql)
1093  {
1094  // Call trigger
1095  $result=$this->call_trigger('BILL_SUPPLIER_UNPAYED',$user);
1096  if ($result < 0) $error++;
1097  // End call triggers
1098  }
1099  else
1100  {
1101  $error++;
1102  $this->error=$this->db->lasterror();
1103  dol_syslog("FactureFournisseur::set_unpaid ".$this->error);
1104  }
1105 
1106  if (! $error)
1107  {
1108  $this->db->commit();
1109  return 1;
1110  }
1111  else
1112  {
1113  $this->db->rollback();
1114  return -1;
1115  }
1116  }
1117 
1127  public function validate($user, $force_number='', $idwarehouse=0, $notrigger=0)
1128  {
1129  global $conf,$langs;
1130  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1131 
1132  $now=dol_now();
1133 
1134  $error=0;
1135  dol_syslog(get_class($this).'::validate user='.$user->id.', force_number='.$force_number.', idwarehouse='.$idwarehouse);
1136 
1137  // Force to have object complete for checks
1138  $this->fetch_thirdparty();
1139  $this->fetch_lines();
1140 
1141  // Check parameters
1142  if ($this->statut > self::STATUS_DRAFT) // This is to avoid to validate twice (avoid errors on logs and stock management)
1143  {
1144  dol_syslog(get_class($this)."::validate no draft status", LOG_WARNING);
1145  return 0;
1146  }
1147  if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ').'/', $this->ref_supplier))
1148  {
1149  $langs->load("errors");
1150  $this->error=$langs->trans("ErrorFieldFormat",$langs->transnoentities("RefSupplier")).'. '.$langs->trans('RemoveString',$langs->transnoentitiesnoconv("CopyOf"));
1151  return -1;
1152  }
1153  if (count($this->lines) <= 0)
1154  {
1155  $langs->load("errors");
1156  $this->error=$langs->trans("ErrorObjectMustHaveLinesToBeValidated", $this->ref);
1157  return -1;
1158  }
1159 
1160  $this->db->begin();
1161 
1162  // Define new ref
1163  if ($force_number)
1164  {
1165  $num = $force_number;
1166  }
1167  else if (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) // empty should not happened, but when it occurs, the test save life
1168  {
1169  $num = $this->getNextNumRef($this->thirdparty);
1170  }
1171  else
1172  {
1173  $num = $this->ref;
1174  }
1175  $this->newref = $num;
1176 
1177  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1178  $sql.= " SET ref='".$num."', fk_statut = 1, fk_user_valid = ".$user->id.", date_valid = '".$this->db->idate($now)."'";
1179  $sql.= " WHERE rowid = ".$this->id;
1180 
1181  dol_syslog(get_class($this)."::validate", LOG_DEBUG);
1182  $resql = $this->db->query($sql);
1183  if ($resql)
1184  {
1185  // Si on incrémente le produit principal et ses composants à la validation de facture fournisseur
1186  if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL))
1187  {
1188  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1189  $langs->load("agenda");
1190 
1191  $cpt=count($this->lines);
1192  for ($i = 0; $i < $cpt; $i++)
1193  {
1194  if ($this->lines[$i]->fk_product > 0)
1195  {
1196  $this->line = $this->lines[$i];
1197  $mouvP = new MouvementStock($this->db);
1198  $mouvP->origin = &$this;
1199  // We increase stock for product
1200  $up_ht_disc=$this->lines[$i]->pu_ht;
1201  if (! empty($this->lines[$i]->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) $up_ht_disc=price2num($up_ht_disc * (100 - $this->lines[$i]->remise_percent) / 100, 'MU');
1202  $result=$mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr",$num));
1203  if ($result < 0) { $error++; }
1204  unset($this->line);
1205  }
1206  }
1207  }
1208 
1209  // Triggers call
1210  if (! $error && empty($notrigger))
1211  {
1212  // Call trigger
1213  $result=$this->call_trigger('BILL_SUPPLIER_VALIDATE',$user);
1214  if ($result < 0) $error++;
1215  // End call triggers
1216  }
1217 
1218  if (! $error)
1219  {
1220  $this->oldref = $this->ref;
1221 
1222  // Rename directory if dir was a temporary ref
1223  if (preg_match('/^[\(]?PROV/i', $this->ref))
1224  {
1225  // On renomme repertoire facture ($this->ref = ancienne ref, $num = nouvelle ref)
1226  // in order not to lose the attached files
1227  $oldref = dol_sanitizeFileName($this->ref);
1228  $newref = dol_sanitizeFileName($num);
1229 
1230  $dirsource = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id,2,0,0, $this, 'invoice_supplier').$oldref;
1231  $dirdest = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id,2,0,0, $this, 'invoice_supplier').$newref;
1232  if (file_exists($dirsource))
1233  {
1234  dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest);
1235 
1236  if (@rename($dirsource, $dirdest))
1237  {
1238  dol_syslog("Rename ok");
1239  // Rename docs starting with $oldref with $newref
1240  $listoffiles=dol_dir_list($conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id,2,0,0, $this, 'invoice_supplier').$newref, 'files', 1, '^'.preg_quote($oldref,'/'));
1241  foreach($listoffiles as $fileentry)
1242  {
1243  $dirsource=$fileentry['name'];
1244  $dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource);
1245  $dirsource=$fileentry['path'].'/'.$dirsource;
1246  $dirdest=$fileentry['path'].'/'.$dirdest;
1247  @rename($dirsource, $dirdest);
1248  }
1249  }
1250  }
1251  }
1252  }
1253 
1254  // Set new ref and define current statut
1255  if (! $error)
1256  {
1257  $this->ref = $num;
1258  $this->statut=self::STATUS_VALIDATED;
1259  //$this->date_validation=$now; this is stored into log table
1260  }
1261 
1262  if (! $error)
1263  {
1264  $this->db->commit();
1265  return 1;
1266  }
1267  else
1268  {
1269  $this->db->rollback();
1270  return -1;
1271  }
1272  }
1273  else
1274  {
1275  $this->error=$this->db->error();
1276  $this->db->rollback();
1277  return -1;
1278  }
1279  }
1280 
1281 
1289  function set_draft($user, $idwarehouse=-1)
1290  {
1291  global $conf,$langs;
1292 
1293  $error=0;
1294 
1295  if ($this->statut == self::STATUS_DRAFT)
1296  {
1297  dol_syslog(get_class($this)."::set_draft already draft status", LOG_WARNING);
1298  return 0;
1299  }
1300 
1301  $this->db->begin();
1302 
1303  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1304  $sql.= " SET fk_statut = 0";
1305  $sql.= " WHERE rowid = ".$this->id;
1306 
1307  dol_syslog(get_class($this)."::set_draft", LOG_DEBUG);
1308  $result=$this->db->query($sql);
1309  if ($result)
1310  {
1311  // Si on incremente le produit principal et ses composants a la validation de facture fournisseur, on decremente
1312  if ($result >= 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL))
1313  {
1314  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1315  $langs->load("agenda");
1316 
1317  $cpt=count($this->lines);
1318  for ($i = 0; $i < $cpt; $i++)
1319  {
1320  if ($this->lines[$i]->fk_product > 0)
1321  {
1322  $mouvP = new MouvementStock($this->db);
1323  $mouvP->origin = &$this;
1324  // We increase stock for product
1325  $result=$mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
1326  }
1327  }
1328  }
1329  // Triggers call
1330  if (! $error && empty($notrigger))
1331  {
1332  // Call trigger
1333  $result=$this->call_trigger('BILL_SUPPLIER_UNVALIDATE',$user);
1334  if ($result < 0) $error++;
1335  // End call triggers
1336  }
1337  if ($error == 0)
1338  {
1339  $this->db->commit();
1340  return 1;
1341  }
1342  else
1343  {
1344  $this->db->rollback();
1345  return -1;
1346  }
1347  }
1348  else
1349  {
1350  $this->error=$this->db->error();
1351  $this->db->rollback();
1352  return -1;
1353  }
1354  }
1355 
1356 
1389  public function addline($desc, $pu, $txtva, $txlocaltax1, $txlocaltax2, $qty, $fk_product=0, $remise_percent=0, $date_start='', $date_end='', $ventil=0, $info_bits='', $price_base_type='HT', $type=0, $rang=-1, $notrigger=false, $array_options=0, $fk_unit=null, $origin_id=0, $pu_ht_devise=0, $ref_supplier='')
1390  {
1391  dol_syslog(get_class($this)."::addline $desc,$pu,$qty,$txtva,$fk_product,$remise_percent,$date_start,$date_end,$ventil,$info_bits,$price_base_type,$type,$fk_unit", LOG_DEBUG);
1392  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1393  global $mysoc;
1394 
1395  // Clean parameters
1396  if (empty($remise_percent)) $remise_percent=0;
1397  if (empty($qty)) $qty=0;
1398  if (empty($info_bits)) $info_bits=0;
1399  if (empty($rang)) $rang=0;
1400  if (empty($ventil)) $ventil=0;
1401  if (empty($txtva)) $txtva=0;
1402  if (empty($txlocaltax1)) $txlocaltax1=0;
1403  if (empty($txlocaltax2)) $txlocaltax2=0;
1404 
1405  $localtaxes_type=getLocalTaxesFromRate($txtva, 0, $mysoc, $this->thirdparty);
1406 
1407  // Clean vat code
1408  $vat_src_code='';
1409  if (preg_match('/\((.*)\)/', $txtva, $reg))
1410  {
1411  $vat_src_code = $reg[1];
1412  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
1413  }
1414 
1415  $remise_percent=price2num($remise_percent);
1416  $qty=price2num($qty);
1417  $pu=price2num($pu);
1418  $txtva=price2num($txtva);
1419  $txlocaltax1=price2num($txlocaltax1);
1420  $txlocaltax2=price2num($txlocaltax2);
1421 
1422  $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $this->thirdparty, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
1423  $total_ht = $tabprice[0];
1424  $total_tva = $tabprice[1];
1425  $total_ttc = $tabprice[2];
1426  $total_localtax1 = $tabprice[9];
1427  $total_localtax2 = $tabprice[10];
1428  $pu_ht = $tabprice[3];
1429 
1430  // MultiCurrency
1431  $multicurrency_total_ht = $tabprice[16];
1432  $multicurrency_total_tva = $tabprice[17];
1433  $multicurrency_total_ttc = $tabprice[18];
1434  $pu_ht_devise = $tabprice[19];
1435 
1436  // Check parameters
1437  if ($type < 0) return -1;
1438 
1439  // Insert line
1440  $this->line=new SupplierInvoiceLine($this->db);
1441 
1442  $this->line->context = $this->context;
1443 
1444  $this->line->fk_facture_fourn=$this->id;
1445  //$this->line->label=$label; // deprecated
1446  $this->line->desc=$desc;
1447  $this->line->qty= ($this->type==self::TYPE_CREDIT_NOTE?abs($qty):$qty); // For credit note, quantity is always positive and unit price negative
1448  $this->line->ref_supplier=$ref_supplier;
1449 
1450  $this->line->vat_src_code=$vat_src_code;
1451  $this->line->tva_tx=$txtva;
1452  $this->line->localtax1_tx=($total_localtax1?$localtaxes_type[1]:0);
1453  $this->line->localtax2_tx=($total_localtax2?$localtaxes_type[3]:0);
1454  $this->line->localtax1_type = $localtaxes_type[0];
1455  $this->line->localtax2_type = $localtaxes_type[2];
1456  $this->line->fk_product=$fk_product;
1457  $this->line->product_type=$type;
1458  $this->line->remise_percent=$remise_percent;
1459  $this->line->subprice= ($this->type==self::TYPE_CREDIT_NOTE?-abs($pu_ht):$pu_ht); // For credit note, unit price always negative, always positive otherwise
1460  $this->line->date_start=$date_start;
1461  $this->line->date_end=$date_end;
1462  $this->line->ventil=$ventil;
1463  $this->line->rang=$rang;
1464  $this->line->info_bits=$info_bits;
1465  $this->line->total_ht= (($this->type==self::TYPE_CREDIT_NOTE||$qty<0)?-abs($total_ht):$total_ht); // For credit note and if qty is negative, total is negative
1466  $this->line->total_tva= $total_tva;
1467  $this->line->total_localtax1=$total_localtax1;
1468  $this->line->total_localtax2=$total_localtax2;
1469  $this->line->total_ttc= (($this->type==self::TYPE_CREDIT_NOTE||$qty<0)?-abs($total_ttc):$total_ttc);
1470  $this->line->special_code=$this->special_code;
1471  $this->line->fk_parent_line=$this->fk_parent_line;
1472  $this->line->origin=$this->origin;
1473  $this->line->origin_id=$origin_id;
1474  $this->line->fk_unit=$fk_unit;
1475 
1476  // Multicurrency
1477  $this->line->fk_multicurrency = $this->fk_multicurrency;
1478  $this->line->multicurrency_code = $this->multicurrency_code;
1479  $this->line->multicurrency_subprice = $pu_ht_devise;
1480  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
1481  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
1482  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
1483 
1484  if (is_array($array_options) && count($array_options)>0) {
1485  $this->line->array_options=$array_options;
1486  }
1487 
1488  $result=$this->line->insert($notrigger);
1489  if ($result > 0)
1490  {
1491  // Reorder if child line
1492  if (! empty($fk_parent_line)) $this->line_order(true,'DESC');
1493 
1494  // Mise a jour informations denormalisees au niveau de la facture meme
1495  $result=$this->update_price(1,'auto',0,$this->thirdparty); // The addline method is designed to add line from user input so total calculation with update_price must be done using 'auto' mode.
1496  if ($result > 0)
1497  {
1498  $this->db->commit();
1499  return $this->line->id;
1500  }
1501  else
1502  {
1503  $this->error=$this->db->error();
1504  $this->db->rollback();
1505  return -1;
1506  }
1507  }
1508  else
1509  {
1510  $this->error=$this->line->error;
1511  $this->errors=$this->line->errors;
1512  $this->db->rollback();
1513  return -2;
1514  }
1515  }
1516 
1540  public function updateline($id, $desc, $pu, $vatrate, $txlocaltax1=0, $txlocaltax2=0, $qty=1, $idproduct=0, $price_base_type='HT', $info_bits=0, $type=0, $remise_percent=0, $notrigger=false, $date_start='', $date_end='', $array_options=0, $fk_unit = null, $pu_ht_devise=0)
1541  {
1542  global $mysoc;
1543  dol_syslog(get_class($this)."::updateline $id,$desc,$pu,$vatrate,$qty,$idproduct,$price_base_type,$info_bits,$type,$remise_percent,$fk_unit", LOG_DEBUG);
1544  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1545 
1546  $pu = price2num($pu);
1547  $qty = price2num($qty);
1548  $remise_percent=price2num($remise_percent);
1549  $pu_ht_devise = price2num($pu_ht_devise);
1550 
1551  // Check parameters
1552  //if (! is_numeric($pu) || ! is_numeric($qty)) return -1;
1553  if ($type < 0) return -1;
1554 
1555  // Clean parameters
1556  if (empty($vatrate)) $vatrate=0;
1557  if (empty($txlocaltax1)) $txlocaltax1=0;
1558  if (empty($txlocaltax2)) $txlocaltax2=0;
1559 
1560  $txlocaltax1=price2num($txlocaltax1);
1561  $txlocaltax2=price2num($txlocaltax2);
1562 
1563  $localtaxes_type = array($txlocaltax1,$txlocaltax2);
1564 
1565  // Calcul du total TTC et de la TVA pour la ligne a partir de
1566  // qty, pu, remise_percent et txtva
1567  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1568  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1569 
1570  $localtaxes_type=getLocalTaxesFromRate($vatrate,0,$mysoc, $this->thirdparty);
1571 
1572  // Clean vat code
1573  $vat_src_code='';
1574  if (preg_match('/\((.*)\)/', $vatrate, $reg))
1575  {
1576  $vat_src_code = $reg[1];
1577  $vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate.
1578  }
1579 
1580  $tabprice = calcul_price_total($qty, $pu, $remise_percent, $vatrate, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $this->thirdparty, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
1581  $total_ht = $tabprice[0];
1582  $total_tva = $tabprice[1];
1583  $total_ttc = $tabprice[2];
1584  $pu_ht = $tabprice[3];
1585  $pu_tva = $tabprice[4];
1586  $pu_ttc = $tabprice[5];
1587  $total_localtax1 = $tabprice[9];
1588  $total_localtax2 = $tabprice[10];
1589 
1590  // MultiCurrency
1591  $multicurrency_total_ht = $tabprice[16];
1592  $multicurrency_total_tva = $tabprice[17];
1593  $multicurrency_total_ttc = $tabprice[18];
1594  $pu_ht_devise = $tabprice[19];
1595 
1596  if (empty($info_bits)) $info_bits=0;
1597 
1598  if ($idproduct)
1599  {
1600  $product=new Product($this->db);
1601  $result=$product->fetch($idproduct);
1602  $product_type = $product->type;
1603  }
1604  else
1605  {
1606  $product_type = $type;
1607  }
1608 
1609  $line = new SupplierInvoiceLine($this->db);
1610 
1611  if ($line->fetch($id) < 1) {
1612  return -1;
1613  }
1614 
1615  $line->description = $desc;
1616  $line->subprice = $pu_ht;
1617  $line->pu_ht = $pu_ht;
1618  $line->pu_ttc = $pu_ttc;
1619  $line->qty = $qty;
1620  $line->remise_percent = $remise_percent;
1621 
1622  $line->vat_src_code=$vat_src_code;
1623  $line->tva_tx = $vatrate;
1624  $line->localtax1_tx = $txlocaltax1;
1625  $line->localtax2_tx = $txlocaltax2;
1626  $line->localtax1_type = $localtaxes_type[0];
1627  $line->localtax2_type = $localtaxes_type[2];
1628  $line->total_ht = $total_ht;
1629  $line->total_tva = $total_tva;
1630  $line->total_localtax1 = $total_localtax1;
1631  $line->total_localtax2 = $total_localtax2;
1632  $line->total_ttc = $total_ttc;
1633  $line->fk_product = $idproduct;
1634  $line->product_type = $product_type;
1635  $line->info_bits = $info_bits;
1636  $line->fk_unit = $fk_unit;
1637  $line->array_options = $array_options;
1638 
1639  // Multicurrency
1640  $line->multicurrency_subprice = $pu_ht_devise;
1641  $line->multicurrency_total_ht = $multicurrency_total_ht;
1642  $line->multicurrency_total_tva = $multicurrency_total_tva;
1643  $line->multicurrency_total_ttc = $multicurrency_total_ttc;
1644 
1645  $res = $line->update($notrigger);
1646 
1647  if ($res < 1) {
1648  $this->errors[] = $line->error;
1649  } else {
1650  // Update total price into invoice record
1651  $res = $this->update_price('','auto');
1652  }
1653 
1654  return $res;
1655  }
1656 
1664  public function deleteline($rowid, $notrigger=0)
1665  {
1666  if (!$rowid) {
1667  $rowid = $this->id;
1668  }
1669 
1670  $line = new SupplierInvoiceLine($this->db);
1671 
1672  if ($line->fetch($rowid) < 1) {
1673  return -1;
1674  }
1675 
1676  $res = $line->delete($notrigger);
1677 
1678  if ($res < 1) {
1679  $this->errors[] = $line->error;
1680  } else {
1681  $res = $this->update_price();
1682  }
1683 
1684  return $res;
1685  }
1686 
1687 
1694  public function info($id)
1695  {
1696  $sql = 'SELECT c.rowid, datec, tms as datem, ';
1697  $sql.= ' fk_user_author, fk_user_modif, fk_user_valid';
1698  $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as c';
1699  $sql.= ' WHERE c.rowid = '.$id;
1700 
1701  $result=$this->db->query($sql);
1702  if ($result)
1703  {
1704  if ($this->db->num_rows($result))
1705  {
1706  $obj = $this->db->fetch_object($result);
1707  $this->id = $obj->rowid;
1708  if ($obj->fk_user_author)
1709  {
1710  $cuser = new User($this->db);
1711  $cuser->fetch($obj->fk_user_author);
1712  $this->user_creation = $cuser;
1713  }
1714  if ($obj->fk_user_valid)
1715  {
1716  $vuser = new User($this->db);
1717  $vuser->fetch($obj->fk_user_valid);
1718  $this->user_validation = $vuser;
1719  }
1720  if ($obj->fk_user_modif)
1721  {
1722  $muser = new User($this->db);
1723  $muser->fetch($obj->fk_user_modif);
1724  $this->user_modification = $muser;
1725  }
1726  $this->date_creation = $this->db->idate($obj->datec);
1727  $this->date_modification = $this->db->idate($obj->datem);
1728  //$this->date_validation = $obj->datev; // This field is not available. Should be store into log table and using this function should be replaced with showing content of log (like for supplier orders)
1729  }
1730  $this->db->free($result);
1731  }
1732  else
1733  {
1734  dol_print_error($this->db);
1735  }
1736  }
1737 
1746  {
1747  global $conf;
1748 
1749  $return = array();
1750 
1751  $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut,";
1752  $sql.= " ff.rowid as rowidnext";
1753  $sql.= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
1754  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
1755  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."facture_fourn as ff ON f.rowid = ff.fk_facture_source";
1756  $sql.= " WHERE (f.fk_statut = ".self::STATUS_VALIDATED." OR (f.fk_statut = ".self::STATUS_ABANDONED." AND f.close_code = '".self::CLOSECODE_ABANDONED."'))";
1757  $sql.= " AND f.entity = ".$conf->entity;
1758  $sql.= " AND f.paye = 0"; // Pas classee payee completement
1759  $sql.= " AND pf.fk_paiementfourn IS NULL"; // Aucun paiement deja fait
1760  $sql.= " AND ff.fk_statut IS NULL"; // Renvoi vrai si pas facture de remplacement
1761  if ($socid > 0) $sql.=" AND f.fk_soc = ".$socid;
1762  $sql.= " ORDER BY f.ref";
1763 
1764  dol_syslog(get_class($this)."::list_replacable_supplier_invoices", LOG_DEBUG);
1765  $resql=$this->db->query($sql);
1766  if ($resql)
1767  {
1768  while ($obj=$this->db->fetch_object($resql))
1769  {
1770  $return[$obj->rowid]=array( 'id' => $obj->rowid,
1771  'ref' => $obj->ref,
1772  'status' => $obj->fk_statut);
1773  }
1774  //print_r($return);
1775  return $return;
1776  }
1777  else
1778  {
1779  $this->error=$this->db->error();
1780  return -1;
1781  }
1782  }
1783 
1793  {
1794  global $conf;
1795 
1796  $return = array();
1797 
1798  $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.paye, pf.fk_paiementfourn";
1799  $sql.= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
1800  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
1801  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."facture_fourn as ff ON (f.rowid = ff.fk_facture_source AND ff.type=".self::TYPE_REPLACEMENT.")";
1802  $sql.= " WHERE f.entity = ".$conf->entity;
1803  $sql.= " AND f.fk_statut in (".self::STATUS_VALIDATED.",".self::STATUS_CLOSED.")";
1804  $sql.= " AND ff.type IS NULL"; // Renvoi vrai si pas facture de remplacement
1805  $sql.= " AND f.type != ".self::TYPE_CREDIT_NOTE; // Type non 2 si facture non avoir
1806  if ($socid > 0) $sql.=" AND f.fk_soc = ".$socid;
1807  $sql.= " ORDER BY f.ref";
1808 
1809  dol_syslog(get_class($this)."::list_qualified_avoir_supplier_invoices", LOG_DEBUG);
1810  $resql=$this->db->query($sql);
1811  if ($resql)
1812  {
1813  while ($obj=$this->db->fetch_object($resql))
1814  {
1815  $qualified=0;
1816  if ($obj->fk_statut == self::STATUS_VALIDATED) $qualified=1;
1817  if ($obj->fk_statut == self::STATUS_CLOSED) $qualified=1;
1818  if ($qualified)
1819  {
1820  $paymentornot=($obj->fk_paiementfourn?1:0);
1821  $return[$obj->rowid]=array('ref'=>$obj->ref,'status'=>$obj->fk_statut,'type'=>$obj->type,'paye'=>$obj->paye,'paymentornot'=>$paymentornot);
1822  }
1823  }
1824 
1825  return $return;
1826  }
1827  else
1828  {
1829  $this->error=$this->db->error();
1830  return -1;
1831  }
1832  }
1833 
1840  function load_board($user)
1841  {
1842  global $conf, $langs;
1843 
1844  $sql = 'SELECT ff.rowid, ff.date_lim_reglement as datefin, ff.fk_statut';
1845  $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as ff';
1846  if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
1847  $sql.= ' WHERE ff.paye=0';
1848  $sql.= ' AND ff.fk_statut > 0';
1849  $sql.= " AND ff.entity = ".$conf->entity;
1850  if ($user->societe_id) $sql.=' AND ff.fk_soc = '.$user->societe_id;
1851  if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= " AND ff.fk_soc = sc.fk_soc AND sc.fk_user = ".$user->id;
1852 
1853  $resql=$this->db->query($sql);
1854  if ($resql)
1855  {
1856  $langs->load("bills");
1857  $now=dol_now();
1858 
1859  $response = new WorkboardResponse();
1860  $response->warning_delay=$conf->facture->fournisseur->warning_delay/60/60/24;
1861  $response->label=$langs->trans("SupplierBillsToPay");
1862 
1863  $response->url=DOL_URL_ROOT.'/fourn/facture/list.php?search_status=1&mainmenu=accountancy&leftmenu=suppliers_bills';
1864  $response->img=img_object($langs->trans("Bills"),"bill");
1865 
1866  $facturestatic = new FactureFournisseur($this->db);
1867 
1868  while ($obj=$this->db->fetch_object($resql))
1869  {
1870  $response->nbtodo++;
1871 
1872  $facturestatic->date_echeance = $this->db->jdate($obj->datefin);
1873  $facturestatic->statut = $obj->fk_statut;
1874 
1875  if ($facturestatic->hasDelay()) {
1876  $response->nbtodolate++;
1877  }
1878  }
1879  $this->db->free($resql);
1880  return $response;
1881  }
1882  else
1883  {
1884  dol_print_error($this->db);
1885  $this->error=$this->db->error();
1886  return -1;
1887  }
1888  }
1889 
1890 
1903  public function getNomUrl($withpicto=0, $option='',$max=0, $short=0, $moretitle='', $notooltip=0, $save_lastsearch_value=-1)
1904  {
1905  global $langs, $conf;
1906 
1907  $result='';
1908 
1909  if ($option == 'document') $url = DOL_URL_ROOT.'/fourn/facture/document.php?facid='.$this->id;
1910  else $url = DOL_URL_ROOT.'/fourn/facture/card.php?facid='.$this->id;
1911 
1912  if ($short) return $url;
1913 
1914  if ($option !== 'nolink')
1915  {
1916  // Add param to save lastsearch_values or not
1917  $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
1918  if ($save_lastsearch_value == -1 && preg_match('/list\.php/',$_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
1919  if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
1920  }
1921 
1922  $picto='bill';
1923  if ($this->type == self::TYPE_REPLACEMENT) $picto.='r'; // Replacement invoice
1924  if ($this->type == self::TYPE_CREDIT_NOTE) $picto.='a'; // Credit note
1925  if ($this->type == self::TYPE_DEPOSIT) $picto.='d'; // Deposit invoice
1926 
1927  $label = '<u>' . $langs->trans("ShowSupplierInvoice") . '</u>';
1928  if (! empty($this->ref))
1929  $label .= '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
1930  if (! empty($this->ref_supplier))
1931  $label.= '<br><b>' . $langs->trans('RefSupplier') . ':</b> ' . $this->ref_supplier;
1932  if (! empty($this->total_ht))
1933  $label.= '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
1934  if (! empty($this->total_tva))
1935  $label.= '<br><b>' . $langs->trans('VAT') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
1936  if (! empty($this->total_ttc))
1937  $label.= '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
1938  if ($this->type == self::TYPE_REPLACEMENT) $label=$langs->transnoentitiesnoconv("ShowInvoiceReplace").': '.$this->ref;
1939  if ($this->type == self::TYPE_CREDIT_NOTE) $label=$langs->transnoentitiesnoconv("ShowInvoiceAvoir").': '.$this->ref;
1940  if ($this->type == self::TYPE_DEPOSIT) $label=$langs->transnoentitiesnoconv("ShowInvoiceDeposit").': '.$this->ref;
1941  if ($moretitle) $label.=' - '.$moretitle;
1942 
1943  $ref=$this->ref;
1944  if (empty($ref)) $ref=$this->id;
1945 
1946  $linkclose='';
1947  if (empty($notooltip))
1948  {
1949  if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
1950  {
1951  $label=$langs->trans("ShowSupplierInvoice");
1952  $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
1953  }
1954  $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
1955  $linkclose.=' class="classfortooltip"';
1956  }
1957 
1958  $linkstart = '<a href="'.$url.'"';
1959  $linkstart.=$linkclose.'>';
1960  $linkend='</a>';
1961 
1962  $result .= $linkstart;
1963  if ($withpicto) $result.=img_object(($notooltip?'':$label), $this->picto, ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
1964  if ($withpicto != 2) $result.= ($max?dol_trunc($ref,$max):$ref);
1965  $result .= $linkend;
1966 
1967  return $result;
1968  }
1969 
1978  public function getNextNumRef($soc,$mode='next')
1979  {
1980  global $db, $langs, $conf;
1981  $langs->load("orders");
1982 
1983  // Clean parameters (if not defined or using deprecated value)
1984  if (empty($conf->global->INVOICE_SUPPLIER_ADDON_NUMBER)) $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER='mod_facture_fournisseur_cactus';
1985 
1986  $mybool=false;
1987 
1988  $file = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER.".php";
1989  $classname = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER;
1990 
1991  // Include file with class
1992  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1993 
1994  foreach ($dirmodels as $reldir) {
1995 
1996  $dir = dol_buildpath($reldir."core/modules/supplier_invoice/");
1997 
1998  // Load file with numbering class (if found)
1999  $mybool|=@include_once $dir.$file;
2000  }
2001 
2002  if (! $mybool)
2003  {
2004  dol_print_error('',"Failed to include file ".$file);
2005  return '';
2006  }
2007 
2008  $obj = new $classname();
2009  $numref = "";
2010  $numref = $obj->getNumRef($soc,$this,$mode);
2011 
2012  if ($numref != "")
2013  {
2014  return $numref;
2015  }
2016  else
2017  {
2018  $this->error=$obj->error;
2019  //dol_print_error($db,get_class($this)."::getNextNumRef ".$obj->error);
2020  return false;
2021  }
2022  }
2023 
2024 
2033  public function initAsSpecimen($option='')
2034  {
2035  global $langs,$conf;
2036  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
2037 
2038  $now = dol_now();
2039 
2040  // Load array of products prodids
2041  $num_prods = 0;
2042  $prodids = array();
2043 
2044  $sql = "SELECT rowid";
2045  $sql.= " FROM ".MAIN_DB_PREFIX."product";
2046  $sql.= " WHERE entity IN (".getEntity('product').")";
2047 
2048  $resql = $this->db->query($sql);
2049  if ($resql)
2050  {
2051  $num_prods = $this->db->num_rows($resql);
2052  $i = 0;
2053  while ($i < $num_prods)
2054  {
2055  $i++;
2056  $row = $this->db->fetch_row($resql);
2057  $prodids[$i] = $row[0];
2058  }
2059  }
2060 
2061  // Initialise parametres
2062  $this->id=0;
2063  $this->ref = 'SPECIMEN';
2064  $this->ref_supplier = 'SUPPLIER_REF_SPECIMEN';
2065  $this->specimen=1;
2066  $this->socid = 1;
2067  $this->date = $now;
2068  $this->date_lim_reglement=$this->date+3600*24*30;
2069  $this->cond_reglement_code = 'RECEP';
2070  $this->mode_reglement_code = 'CHQ';
2071  $this->note_public='This is a comment (public)';
2072  $this->note_private='This is a comment (private)';
2073 
2074  if (empty($option) || $option != 'nolines')
2075  {
2076  // Lines
2077  $nbp = 5;
2078  $xnbp = 0;
2079  while ($xnbp < $nbp)
2080  {
2081  $line=new FactureLigne($this->db);
2082  $line->desc=$langs->trans("Description")." ".$xnbp;
2083  $line->qty=1;
2084  $line->subprice=100;
2085  $line->pu_ht=100; // the canelle template use pu_ht and not subprice
2086  $line->price=100;
2087  $line->tva_tx=19.6;
2088  $line->localtax1_tx=0;
2089  $line->localtax2_tx=0;
2090  if ($xnbp == 2)
2091  {
2092  $line->total_ht=50;
2093  $line->total_ttc=59.8;
2094  $line->total_tva=9.8;
2095  $line->remise_percent=50;
2096  }
2097  else
2098  {
2099  $line->total_ht=100;
2100  $line->total_ttc=119.6;
2101  $line->total_tva=19.6;
2102  $line->remise_percent=0;
2103  }
2104 
2105  if ($num_prods > 0)
2106  {
2107  $prodid = mt_rand(1, $num_prods);
2108  $line->fk_product=$prodids[$prodid];
2109  }
2110  $line->product_type=0;
2111 
2112  $this->lines[$xnbp]=$line;
2113 
2114  $this->total_ht += $line->total_ht;
2115  $this->total_tva += $line->total_tva;
2116  $this->total_ttc += $line->total_ttc;
2117 
2118  $xnbp++;
2119  }
2120  }
2121 
2122  $this->amount_ht = $xnbp*100;
2123  $this->total_ht = $xnbp*100;
2124  $this->total_tva = $xnbp*19.6;
2125  $this->total_ttc = $xnbp*119.6;
2126  }
2127 
2133  function load_state_board()
2134  {
2135  global $conf, $user;
2136 
2137  $this->nb=array();
2138 
2139  $clause = "WHERE";
2140 
2141  $sql = "SELECT count(f.rowid) as nb";
2142  $sql.= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2143  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
2144  if (!$user->rights->societe->client->voir && !$user->societe_id)
2145  {
2146  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
2147  $sql.= " WHERE sc.fk_user = " .$user->id;
2148  $clause = "AND";
2149  }
2150  $sql.= " ".$clause." f.entity = ".$conf->entity;
2151 
2152  $resql=$this->db->query($sql);
2153  if ($resql)
2154  {
2155  while ($obj=$this->db->fetch_object($resql))
2156  {
2157  $this->nb["supplier_invoices"]=$obj->nb;
2158  }
2159  $this->db->free($resql);
2160  return 1;
2161  }
2162  else
2163  {
2164  dol_print_error($this->db);
2165  $this->error=$this->db->error();
2166  return -1;
2167  }
2168  }
2169 
2177  public function createFromClone($fromid,$invertdetail=0)
2178  {
2179  global $user,$langs;
2180 
2181  $error=0;
2182 
2183  $object=new FactureFournisseur($this->db);
2184 
2185  $object->context['createfromclone'] = 'createfromclone';
2186 
2187  $this->db->begin();
2188 
2189  // Load source object
2190  $object->fetch($fromid);
2191  $object->id=0;
2192  $object->statut=self::STATUS_DRAFT;
2193 
2194  // Clear fields
2195  $object->ref_supplier=$langs->trans("CopyOf").' '.$object->ref_supplier;
2196  $object->author = $user->id;
2197  $object->user_valid = '';
2198  $object->fk_facture_source = 0;
2199  $object->date_creation = '';
2200  $object->date_validation = '';
2201  $object->date = '';
2202  $object->date_echeance = '';
2203  $object->ref_client = '';
2204  $object->close_code = '';
2205  $object->close_note = '';
2206 
2207  // Loop on each line of new invoice
2208  foreach($object->lines as $i => $line)
2209  {
2210  if (isset($object->lines[$i]->info_bits) && ($object->lines[$i]->info_bits & 0x02) == 0x02) // We do not clone line of discounts
2211  {
2212  unset($object->lines[$i]);
2213  }
2214  }
2215 
2216  // Create clone
2217  $result=$object->create($user);
2218 
2219  // Other options
2220  if ($result < 0)
2221  {
2222  $this->error=$object->error;
2223  $error++;
2224  }
2225 
2226  if (! $error)
2227  {
2228 
2229 
2230 
2231  }
2232 
2233  unset($object->context['createfromclone']);
2234 
2235  // End
2236  if (! $error)
2237  {
2238  $this->db->commit();
2239  return $object->id;
2240  }
2241  else
2242  {
2243  $this->db->rollback();
2244  return -1;
2245  }
2246  }
2247 
2258  public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
2259  {
2260  global $conf, $user, $langs;
2261 
2262  $langs->load("suppliers");
2263 
2264  // Set the model on the model name to use
2265  if (empty($modele))
2266  {
2267  if (! empty($conf->global->INVOICE_SUPPLIER_ADDON_PDF))
2268  {
2269  $modele = $conf->global->INVOICE_SUPPLIER_ADDON_PDF;
2270  }
2271  else
2272  {
2273  $modele = ''; // No default value. For supplier invoice, we allow to disable all PDF generation
2274  }
2275  }
2276 
2277  if (empty($modele))
2278  {
2279  return 0;
2280  }
2281  else
2282  {
2283  $modelpath = "core/modules/supplier_invoice/pdf/";
2284 
2285  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
2286  }
2287  }
2288 
2293  public function getRights()
2294  {
2295  global $user;
2296 
2297  return $user->rights->fournisseur->facture;
2298  }
2299 
2308  public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
2309  {
2310  $tables = array(
2311  'facture_fourn'
2312  );
2313 
2314  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
2315  }
2316 
2322  public function hasDelay()
2323  {
2324  global $conf;
2325 
2326  $now = dol_now();
2327 
2328  if (!$this->date_echeance) {
2329  return false;
2330  }
2331 
2332  return ($this->statut == self::STATUS_VALIDATED) && ($this->date_echeance < ($now - $conf->facture->fournisseur->warning_delay));
2333  }
2334 }
2335 
2336 
2337 
2342 {
2343  public $element='facture_fourn_det';
2344  public $table_element='facture_fourn_det';
2345 
2346  public $oldline;
2347 
2352  public $ref;
2357  public $product_ref;
2358 
2364  public $ref_supplier;
2365 
2370  public $libelle;
2375  public $product_desc;
2376 
2383  public $pu_ht;
2384  public $subprice;
2385 
2390  public $pu_ttc;
2391 
2398  public $tva;
2399  public $total_tva;
2400 
2405  public $fk_facture_fourn;
2406 
2412  public $label;
2413 
2418  public $description;
2419 
2420  public $skip_update_total; // Skip update price total for special lines
2421 
2425  public $situation_percent;
2426 
2430  public $fk_prev_id;
2431 
2432  public $tva_tx;
2433  public $localtax1_tx;
2434  public $localtax2_tx;
2435  public $qty;
2436  public $remise_percent;
2437  public $total_ht;
2438  public $total_ttc;
2439  public $total_localtax1;
2440  public $total_localtax2;
2441  public $fk_product;
2442  public $product_type;
2443  public $product_label;
2444  public $info_bits;
2445  public $fk_parent_line;
2446  public $special_code;
2447  public $rang;
2448  public $localtax1_type;
2449  public $localtax2_type;
2450 
2451  // Multicurrency
2452  public $fk_multicurrency;
2453  public $multicurrency_code;
2454  public $multicurrency_subprice;
2455  public $multicurrency_total_ht;
2456  public $multicurrency_total_tva;
2457  public $multicurrency_total_ttc;
2458 
2464  public function __construct($db)
2465  {
2466  $this->db= $db;
2467  }
2468 
2475  public function fetch($rowid)
2476  {
2477  $sql = 'SELECT f.rowid, f.ref as ref_supplier, f.description, f.pu_ht, f.pu_ttc, f.qty, f.remise_percent, f.tva_tx';
2478  $sql.= ', f.localtax1_type, f.localtax2_type, f.localtax1_tx, f.localtax2_tx, f.total_localtax1, f.total_localtax2 ';
2479  $sql.= ', f.total_ht, f.tva as total_tva, f.total_ttc, f.fk_facture_fourn, f.fk_product, f.product_type, f.info_bits, f.rang, f.special_code, f.fk_parent_line, f.fk_unit';
2480  $sql.= ', p.rowid as product_id, p.ref as product_ref, p.label as label, p.description as product_desc';
2481  $sql.= ', f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, multicurrency_total_ttc';
2482  $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
2483  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
2484  $sql.= ' WHERE f.rowid = '.$rowid;
2485  $sql.= ' ORDER BY f.rang, f.rowid';
2486 
2487  $query = $this->db->query($sql);
2488 
2489  if (!$query) {
2490  $this->errors[] = $this->db->error();
2491  return -1;
2492  }
2493 
2494  if (!$this->db->num_rows($query)) {
2495  return 0;
2496  }
2497 
2498  $obj = $this->db->fetch_object($query);
2499 
2500  $this->id = $obj->rowid;
2501  $this->rowid = $obj->rowid;
2502  $this->fk_facture_fourn = $obj->fk_facture_fourn;
2503  $this->description = $obj->description;
2504  $this->product_ref = $obj->product_ref;
2505  $this->ref = $obj->product_ref;
2506  $this->ref_supplier = $obj->ref_supplier;
2507  $this->libelle = $obj->label;
2508  $this->label = $obj->label;
2509  $this->product_desc = $obj->product_desc;
2510  $this->subprice = $obj->pu_ht;
2511  $this->pu_ht = $obj->pu_ht;
2512  $this->pu_ttc = $obj->pu_ttc;
2513  $this->tva_tx = $obj->tva_tx;
2514  $this->localtax1_tx = $obj->localtax1_tx;
2515  $this->localtax2_tx = $obj->localtax2_tx;
2516  $this->localtax1_type = $obj->localtax1_type;
2517  $this->localtax2_type = $obj->localtax2_type;
2518  $this->qty = $obj->qty;
2519  $this->remise_percent = $obj->remise_percent;
2520  $this->tva = $obj->total_tva;
2521  $this->total_ht = $obj->total_ht;
2522  $this->total_tva = $obj->total_tva;
2523  $this->total_localtax1 = $obj->total_localtax1;
2524  $this->total_localtax2 = $obj->total_localtax2;
2525  $this->total_ttc = $obj->total_ttc;
2526  $this->fk_product = $obj->fk_product;
2527  $this->product_type = $obj->product_type;
2528  $this->product_label = $obj->label;
2529  $this->info_bits = $obj->info_bits;
2530  $this->tva_npr = ($obj->info_bits & 1 == 1) ? 1 : 0;
2531  $this->fk_parent_line = $obj->fk_parent_line;
2532  $this->special_code = $obj->special_code;
2533  $this->rang = $obj->rang;
2534  $this->fk_unit = $obj->fk_unit;
2535 
2536  $this->multicurrency_subprice = $obj->multicurrency_subprice;
2537  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
2538  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
2539  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
2540 
2541  return 1;
2542  }
2543 
2550  public function delete($notrigger = 0)
2551  {
2552  dol_syslog(get_class($this)."::deleteline rowid=".$this->id, LOG_DEBUG);
2553 
2554  $error = 0;
2555 
2556  $this->db->begin();
2557 
2558  if (!$notrigger) {
2559  if ($this->call_trigger('LINEBILL_SUPPLIER_DELETE',$user) < 0) {
2560  $error++;
2561  }
2562  }
2563 
2564  if (!$error) {
2565  // Supprime ligne
2566  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det ';
2567  $sql .= ' WHERE rowid = '.$this->id;
2568  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
2569  $resql = $this->db->query($sql);
2570  if (!$resql) {
2571  $error++;
2572  $this->error = $this->db->lasterror();
2573  }
2574  }
2575 
2576  if (! $error)
2577  {
2578  $this->db->commit();
2579  return 1;
2580  }
2581  else
2582  {
2583  $this->db->rollback();
2584  return -1;
2585  }
2586  }
2587 
2594  public function update($notrigger = 0)
2595  {
2596  global $conf;
2597 
2598  $pu = price2num($this->pu_ht);
2599  $qty = price2num($this->qty);
2600 
2601  // Check parameters
2602  if (empty($this->qty)) $this->qty=0;
2603 
2604  if ($this->product_type < 0) {
2605  return -1;
2606  }
2607 
2608  // Clean parameters
2609  if (empty($this->remise_percent)) $this->remise_percent = 0;
2610  if (empty($this->tva_tx)) $this->tva_tx = 0;
2611  if (empty($this->localtax1_tx)) $this->localtax1_tx = 0;
2612  if (empty($this->localtax2_tx)) $this->localtax2_tx = 0;
2613 
2614  $this->db->begin();
2615 
2616  if (empty($this->fk_product))
2617  {
2618  $fk_product = "null";
2619  } else {
2620  $fk_product = $this->fk_product;
2621  }
2622 
2623  if (empty($this->fk_unit)) {
2624  $fk_unit = "null";
2625  } else {
2626  $fk_unit = "'".$this->db->escape($this->fk_unit)."'";
2627  }
2628 
2629  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
2630  $sql.= " description ='".$this->db->escape($this->description)."'";
2631  $sql.= ", ref ='".$this->db->escape($this->ref)."'";
2632  $sql.= ", pu_ht = ".price2num($this->pu_ht);
2633  $sql.= ", pu_ttc = ".price2num($this->pu_ttc);
2634  $sql.= ", qty = ".price2num($this->qty);
2635  $sql.= ", remise_percent = ".price2num($this->remise_percent);
2636  $sql.= ", vat_src_code = '".(empty($this->vat_src_code)?'':$this->vat_src_code)."'";
2637  $sql.= ", tva_tx = ".price2num($this->tva_tx);
2638  $sql.= ", localtax1_tx = ".price2num($this->localtax1_tx);
2639  $sql.= ", localtax2_tx = ".price2num($this->localtax2_tx);
2640  $sql.= ", localtax1_type = '".$this->db->escape($this->localtax1_type)."'";
2641  $sql.= ", localtax2_type = '".$this->db->escape($this->localtax2_type)."'";
2642  $sql.= ", total_ht = ".price2num($this->total_ht);
2643  $sql.= ", tva= ".price2num($this->total_tva);
2644  $sql.= ", total_localtax1= ".price2num($this->total_localtax1);
2645  $sql.= ", total_localtax2= ".price2num($this->total_localtax2);
2646  $sql.= ", total_ttc = ".price2num($this->total_ttc);
2647  $sql.= ", fk_product = ".$fk_product;
2648  $sql.= ", product_type = ".$this->product_type;
2649  $sql.= ", info_bits = ".$this->info_bits;
2650  $sql.= ", fk_unit = ".$fk_unit;
2651 
2652  // Multicurrency
2653  $sql.= " , multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
2654  $sql.= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
2655  $sql.= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
2656  $sql.= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
2657 
2658  $sql.= " WHERE rowid = ".$this->id;
2659 
2660  dol_syslog(get_class($this)."::update", LOG_DEBUG);
2661  $resql = $this->db->query($sql);
2662 
2663  if (!$resql) {
2664  $this->db->rollback();
2665  $this->error = $this->db->lasterror();
2666  return -1;
2667  }
2668 
2669  $this->rowid = $this->id;
2670  $error = 0;
2671 
2672  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
2673  {
2674  if ($this->insertExtraFields() < 0) {
2675  $error++;
2676  }
2677  }
2678 
2679  if (! $error && ! $notrigger)
2680  {
2681  global $langs, $user;
2682 
2683  // Call trigger
2684  if ($this->call_trigger('LINEBILL_SUPPLIER_UPDATE',$user) < 0) {
2685  $this->db->rollback();
2686  return -1;
2687  }
2688  // End call triggers
2689  }
2690 
2691  if ($error) {
2692  $this->db->rollback();
2693  return -1;
2694  }
2695 
2696  $this->db->commit();
2697  return 1;
2698  }
2699 
2706  public function insert($notrigger=0)
2707  {
2708  global $user,$conf;
2709 
2710  $error=0;
2711 
2712  dol_syslog(get_class($this)."::insert rang=".$this->rang, LOG_DEBUG);
2713 
2714  // Clean parameters
2715  $this->desc=trim($this->desc);
2716  if (empty($this->tva_tx)) $this->tva_tx=0;
2717  if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
2718  if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
2719  if (empty($this->localtax1_type)) $this->localtax1_type='0';
2720  if (empty($this->localtax2_type)) $this->localtax2_type='0';
2721  if (empty($this->total_localtax1)) $this->total_localtax1=0;
2722  if (empty($this->total_localtax2)) $this->total_localtax2=0;
2723  if (empty($this->rang)) $this->rang=0;
2724  if (empty($this->remise_percent)) $this->remise_percent=0;
2725  if (empty($this->info_bits)) $this->info_bits=0;
2726  if (empty($this->subprice)) $this->subprice=0;
2727  if (empty($this->special_code)) $this->special_code=0;
2728  if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
2729  if (! isset($this->situation_percent) || $this->situation_percent > 100 || (string) $this->situation_percent == '') $this->situation_percent = 100;
2730 
2731  if (empty($this->pa_ht)) $this->pa_ht=0;
2732  if (empty($this->multicurrency_subprice)) $this->multicurrency_subprice=0;
2733  if (empty($this->multicurrency_total_ht)) $this->multicurrency_total_ht=0;
2734  if (empty($this->multicurrency_total_tva)) $this->multicurrency_total_tva=0;
2735  if (empty($this->multicurrency_total_ttc)) $this->multicurrency_total_ttc=0;
2736 
2737 
2738  // Check parameters
2739  if ($this->product_type < 0)
2740  {
2741  $this->error='ErrorProductTypeMustBe0orMore';
2742  return -1;
2743  }
2744  if (! empty($this->fk_product))
2745  {
2746  // Check product exists
2747  $result=Product::isExistingObject('product', $this->fk_product);
2748  if ($result <= 0)
2749  {
2750  $this->error='ErrorProductIdDoesNotExists';
2751  return -1;
2752  }
2753  }
2754 
2755  $this->db->begin();
2756 
2757  // Insertion dans base de la ligne
2758  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
2759  $sql.= ' (fk_facture_fourn, fk_parent_line, label, description, ref, qty,';
2760  $sql.= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
2761  $sql.= ' fk_product, product_type, remise_percent, pu_ht, pu_ttc,';
2762  $sql.= ' date_start, date_end, fk_code_ventilation, rang, special_code,';
2763  $sql.= ' info_bits, total_ht, tva, total_ttc, total_localtax1, total_localtax2, fk_unit';
2764  $sql.= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
2765  $sql.= ')';
2766  $sql.= " VALUES (".$this->fk_facture_fourn.",";
2767  $sql.= " ".($this->fk_parent_line>0?"'".$this->db->escape($this->fk_parent_line)."'":"null").",";
2768  $sql.= " ".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null").",";
2769  $sql.= " '".$this->db->escape($this->desc ? $this->desc : $this->description)."',";
2770  $sql.= " '".$this->db->escape($this->ref_supplier)."',";
2771  $sql.= " ".price2num($this->qty).",";
2772 
2773  $sql.= " ".(empty($this->vat_src_code)?"''":"'".$this->db->escape($this->vat_src_code)."'").",";
2774  $sql.= " ".price2num($this->tva_tx).",";
2775  $sql.= " ".price2num($this->localtax1_tx).",";
2776  $sql.= " ".price2num($this->localtax2_tx).",";
2777  $sql.= " '".$this->db->escape($this->localtax1_type)."',";
2778  $sql.= " '".$this->db->escape($this->localtax2_type)."',";
2779  $sql.= ' '.(! empty($this->fk_product)?$this->fk_product:"null").',';
2780  $sql.= " ".$this->product_type.",";
2781  $sql.= " ".price2num($this->remise_percent).",";
2782  $sql.= " ".price2num($this->subprice).",";
2783  $sql.= " ".price2num($this->total_ttc/$this->qty).",";
2784  $sql.= " ".(! empty($this->date_start)?"'".$this->db->idate($this->date_start)."'":"null").",";
2785  $sql.= " ".(! empty($this->date_end)?"'".$this->db->idate($this->date_end)."'":"null").",";
2786  $sql.= ' '.(!empty($this->fk_code_ventilation)?$this->fk_code_ventilation:0).',';
2787  $sql.= ' '.$this->rang.',';
2788  $sql.= ' '.$this->special_code.',';
2789  $sql.= " '".$this->db->escape($this->info_bits)."',";
2790  $sql.= " ".price2num($this->total_ht).",";
2791  $sql.= " ".price2num($this->total_tva).",";
2792  $sql.= " ".price2num($this->total_ttc).",";
2793  $sql.= " ".price2num($this->total_localtax1).",";
2794  $sql.= " ".price2num($this->total_localtax2);
2795  $sql .= ", ".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
2796  $sql.= ", ".(int) $this->fk_multicurrency;
2797  $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
2798  $sql.= ", ".price2num($this->multicurrency_subprice);
2799  $sql.= ", ".price2num($this->multicurrency_total_ht);
2800  $sql.= ", ".price2num($this->multicurrency_total_tva);
2801  $sql.= ", ".price2num($this->multicurrency_total_ttc);
2802  $sql.= ')';
2803 
2804  dol_syslog(get_class($this)."::insert", LOG_DEBUG);
2805  $resql=$this->db->query($sql);
2806  if ($resql)
2807  {
2808  $this->id=$this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
2809  $this->rowid=$this->id;
2810 
2811  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
2812  {
2813  $result=$this->insertExtraFields();
2814  if ($result < 0)
2815  {
2816  $error++;
2817  }
2818  }
2819 
2820  if (! $notrigger)
2821  {
2822  // Call trigger
2823  $result=$this->call_trigger('LINEBILL_SUPPLIER_CREATE',$user);
2824  if ($result < 0)
2825  {
2826  $this->db->rollback();
2827  return -2;
2828  }
2829  // End call triggers
2830  }
2831 
2832  $this->db->commit();
2833  return $this->id;
2834 
2835  }
2836  else
2837  {
2838  $this->error=$this->db->error();
2839  $this->db->rollback();
2840  return -2;
2841  }
2842  }
2848  function update_total()
2849  {
2850  $this->db->begin();
2851 
2852  // Mise a jour ligne en base
2853  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
2854  $sql.= " total_ht='".price2num($this->total_ht)."'";
2855  $sql.= ", tva='".price2num($this->total_tva)."'";
2856  $sql.= ", total_localtax1='".price2num($this->total_localtax1)."'";
2857  $sql.= ", total_localtax2='".price2num($this->total_localtax2)."'";
2858  $sql.= ", total_ttc='".price2num($this->total_ttc)."'";
2859  $sql.= " WHERE rowid = ".$this->rowid;
2860 
2861  dol_syslog("FactureFournisseurLigne.class.php::update_total", LOG_DEBUG);
2862 
2863  $resql=$this->db->query($sql);
2864  if ($resql)
2865  {
2866  $this->db->commit();
2867  return 1;
2868  }
2869  else
2870  {
2871  $this->error=$this->db->error();
2872  $this->db->rollback();
2873  return -2;
2874  }
2875  }
2876  }
static replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
const TYPE_STANDARD
Standard invoice.
Class to manage stock movements.
update($user=null, $notrigger=0)
Update database.
insert($notrigger=0)
Insert line into database.
info($id)
Charge les informations d'ordre info dans l'objet facture.
initAsSpecimen($option='')
Initialise an instance with random values.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '...' if string larger than length.
static getIdFromCode(&$db, $code)
Get id of currency from code.
const TYPE_DEPOSIT
Deposit invoice.
$fk_facture_source
id of source invoice if replacement invoice or credit note
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
Delete all links between an object $this.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create a document onto disk according to template model.
list_replacable_supplier_invoices($socid=0)
Renvoi liste des factures remplacables Statut validee ou abandonnee pour raison autre + non payee + a...
</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
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Class to manage line invoices.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart)
Return a path to have a the directory according to object where files are stored. ...
updateline($id, $desc, $pu, $vatrate, $txlocaltax1=0, $txlocaltax2=0, $qty=1, $idproduct=0, $price_base_type='HT', $info_bits=0, $type=0, $remise_percent=0, $notrigger=false, $date_start='', $date_end='', $array_options=0, $fk_unit=null, $pu_ht_devise=0)
Update a line detail into database.
Class to manage products or services.
Class to manage Dolibarr users.
Definition: user.class.php:39
Class to manage Dolibarr database access.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
const TYPE_REPLACEMENT
Replacement invoice.
load_board($user)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
getNextNumRef($soc, $mode='next')
Return next reference of supplier invoice not already used (or last reference) according to numbering...
dol_print_error($db='', $error='', $errors=null)
Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remonte...
const STATUS_VALIDATED
Validated (need to be paid)
Class to manage suppliers invoices.
load_state_board()
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
fetch_thirdparty($force_thirdparty_id=0)
Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
update_total()
Mise a jour de l'objet ligne de commande en base.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="")
Scan a directory and return a list of files/directories.
Definition: files.lib.php:58
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Class to manage standard extra fields.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='')
Write log message into outputs.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
set_unpaid($user)
Tag la facture comme non payee completement + appel trigger BILL_UNPAYED Fonction utilisee quand un p...
getNomUrl($withpicto=0, $option='', $max=0, $short=0, $moretitle='', $notooltip=0, $save_lastsearch_value=-1)
Return clicable name (with picto eventually)
set_draft($user, $idwarehouse=-1)
Set draft status.
static isExistingObject($element, $id, $ref='', $ref_ext='')
Check an object id/ref exists If you don't need/want to instantiate object and just need to know if o...
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.
list_qualified_avoir_supplier_invoices($socid=0)
Renvoi liste des factures qualifiables pour correction par avoir Les factures qui respectent les regl...
getRights()
Returns the rights used for this class.
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:1234
getEntity($element, $shared=1, $forceentity=null)
Get list of entity id to use.
fetch($rowid)
Retrieves a supplier invoice line.
img_object($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
deleteExtraFields()
Delete all extra fields values for the current object.
dol_now($mode='gmt')
Return date for now.
update($notrigger=0)
Update a supplier invoice line.
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...
set_paid($user, $close_code='', $close_note='')
Tag invoice as a payed invoice.
deleteline($rowid, $notrigger=0)
Delete a detail line from database.
Superclass for invoices classes.
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_CLOSED
Classified paid.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages...
const TYPE_CREDIT_NOTE
Credit note invoice.
validate($user, $force_number='', $idwarehouse=0, $notrigger=0)
Tag invoice as validated + call trigger BILL_VALIDATE.
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
line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
Save a new position (field rang) for details lines.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null)
Remove a file or several files with a mask.
Definition: files.lib.php:1103
hasDelay()
Is the payment of the supplier invoice having a delay?
const STATUS_ABANDONED
Classified abandoned and no payment done.
fetch($id='', $ref='')
Load object in memory from database.
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.
createFromClone($fromid, $invertdetail=0)
Load an object from its id and create a new one in database.
add_object_linked($origin=null, $origin_id=null)
Add objects linked in llx_element_element.
addline($desc, $pu, $txtva, $txlocaltax1, $txlocaltax2, $qty, $fk_product=0, $remise_percent=0, $date_start='', $date_end='', $ventil=0, $info_bits='', $price_base_type='HT', $type=0, $rang=-1, $notrigger=false, $array_options=0, $fk_unit=null, $origin_id=0, $pu_ht_devise=0, $ref_supplier='')
Ajoute une ligne de facture (associe a aucun produit/service predefini) Les parametres sont deja cens...
create($user)
Create supplier invoice into database.
type
Definition: viewcat.php:283
price2num($amount, $rounding='', $alreadysqlnb=0)
Function that return a number with universal decimal format (decimal separator is '...
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
fetch_lines()
Load this->lines.
Class to manage invoice lines.
static getIdAndTxFromCode(&$db, $code, $date_document='')
Get id and rate of currency from code.