dolibarr  13.0.2
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@inodbox.com>
7  * Copyright (C) 2010-2020 Juanjo Menent <jmenent@2byte.es>
8  * Copyright (C) 2013-2019 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-2019 Ferran Marcet <fmarcet@2byte.es>
13  * Copyright (C) 2016 Alexandre Spangaro <aspangaro@open-dsi.fr>
14  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
15  * Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program. If not, see <https://www.gnu.org/licenses/>.
29  */
30 
37 require_once DOL_DOCUMENT_ROOT.'/core/class/commoninvoice.class.php';
38 require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
39 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
40 
41 if (!empty($conf->accounting->enabled)) require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
42 if (!empty($conf->accounting->enabled)) require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
43 
48 {
52  public $element = 'invoice_supplier';
53 
57  public $table_element = 'facture_fourn';
58 
62  public $table_element_line = 'facture_fourn_det';
63 
67  public $fk_element = 'fk_facture_fourn';
68 
72  public $picto = 'supplier_invoice';
73 
78  public $ismultientitymanaged = 1;
79 
84  public $restrictiononfksoc = 1;
85 
89  protected $table_ref_field = 'ref';
90 
94  public $rowid;
95 
99  public $ref;
100 
104  public $ref_supplier;
105 
109  public $label;
110 
111  public $socid;
112 
113  //Check constants for types
114  public $type = self::TYPE_STANDARD;
115 
121  public $statut;
122 
127  public $paye;
128 
129  public $author;
130 
136  public $datec;
137 
143  public $tms;
144 
150  public $date;
151 
157  public $date_echeance;
158 
159  public $amount = 0;
160  public $remise = 0;
161  public $tva = 0;
162  public $localtax1;
163  public $localtax2;
164  public $total_ht = 0;
165  public $total_tva = 0;
166  public $total_localtax1 = 0;
167  public $total_localtax2 = 0;
168  public $total_ttc = 0;
169 
174  public $note;
175 
176  public $note_private;
177  public $note_public;
178  public $propalid;
179 
180  public $cond_reglement_id;
181  public $cond_reglement_code;
182  public $cond_reglement_label;
183  public $cond_reglement_doc;
184 
188  public $fk_account;
189 
190  public $mode_reglement_id;
191  public $mode_reglement_code;
192 
193  public $extraparams = array();
194 
199  public $lines = array();
200 
204  public $fournisseur;
205 
206  // Multicurrency
210  public $fk_multicurrency;
211 
212  public $multicurrency_code;
213  public $multicurrency_tx;
214  public $multicurrency_total_ht;
215  public $multicurrency_total_tva;
216  public $multicurrency_total_ttc;
218 
221  public $fk_facture_source;
222 
223 
224  public $fields = array(
225  'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
226  'ref' =>array('type'=>'varchar(255)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>15),
227  'ref_supplier' =>array('type'=>'varchar(255)', 'label'=>'RefSupplier', 'enabled'=>1, 'visible'=>-1, 'position'=>20),
228  'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>25, 'index'=>1),
229  'ref_ext' =>array('type'=>'varchar(255)', 'label'=>'RefExt', 'enabled'=>1, 'visible'=>0, 'position'=>30),
230  'type' =>array('type'=>'smallint(6)', 'label'=>'Type', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35),
231  'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>40),
232  'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
233  'datef' =>array('type'=>'date', 'label'=>'Date', 'enabled'=>1, 'visible'=>-1, 'position'=>50),
234  'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>55),
235  'libelle' =>array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>1, 'visible'=>-1, 'position'=>60),
236  'paye' =>array('type'=>'smallint(6)', 'label'=>'Paye', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>65),
237  'amount' =>array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>70),
238  'remise' =>array('type'=>'double(24,8)', 'label'=>'Discount', 'enabled'=>1, 'visible'=>-1, 'position'=>75),
239  'close_code' =>array('type'=>'varchar(16)', 'label'=>'CloseCode', 'enabled'=>1, 'visible'=>-1, 'position'=>80),
240  'close_note' =>array('type'=>'varchar(128)', 'label'=>'CloseNote', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
241  'tva' =>array('type'=>'double(24,8)', 'label'=>'Tva', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
242  'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>-1, 'position'=>95),
243  'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>-1, 'position'=>100),
244  'total_ht' =>array('type'=>'double(24,8)', 'label'=>'TotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
245  'total_tva' =>array('type'=>'double(24,8)', 'label'=>'TotalVAT', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
246  'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'TotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
247  'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-1, 'position'=>125),
248  'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>130),
249  'fk_user_valid' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>135),
250  'fk_facture_source' =>array('type'=>'integer', 'label'=>'Fk facture source', 'enabled'=>1, 'visible'=>-1, 'position'=>140),
251  'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label'=>'Project', 'enabled'=>1, 'visible'=>-1, 'position'=>145),
252  'fk_account' =>array('type'=>'integer', 'label'=>'Account', 'enabled'=>1, 'visible'=>-1, 'position'=>150),
253  'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'PaymentTerm', 'enabled'=>1, 'visible'=>-1, 'position'=>155),
254  'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'PaymentMode', 'enabled'=>1, 'visible'=>-1, 'position'=>160),
255  'date_lim_reglement' =>array('type'=>'date', 'label'=>'DateLimReglement', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
256  'note_private' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>170),
257  'note_public' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>175),
258  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'ModelPdf', 'enabled'=>1, 'visible'=>0, 'position'=>180),
259  'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>190),
260  'fk_incoterms' =>array('type'=>'integer', 'label'=>'IncotermCode', 'enabled'=>1, 'visible'=>-1, 'position'=>195),
261  'location_incoterms' =>array('type'=>'varchar(255)', 'label'=>'IncotermLocation', 'enabled'=>1, 'visible'=>-1, 'position'=>200),
262  'fk_multicurrency' =>array('type'=>'integer', 'label'=>'MulticurrencyId', 'enabled'=>1, 'visible'=>-1, 'position'=>205),
263  'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'MulticurrencyCode', 'enabled'=>1, 'visible'=>-1, 'position'=>210),
264  'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyRate', 'enabled'=>1, 'visible'=>-1, 'position'=>215),
265  'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyTotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>220),
266  'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyTotalVAT', 'enabled'=>1, 'visible'=>-1, 'position'=>225),
267  'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyTotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>230),
268  'date_pointoftax' =>array('type'=>'date', 'label'=>'Date pointoftax', 'enabled'=>1, 'visible'=>-1, 'position'=>235),
269  'date_valid' =>array('type'=>'date', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>240),
270  'last_main_doc' =>array('type'=>'varchar(255)', 'label'=>'Last main doc', 'enabled'=>1, 'visible'=>-1, 'position'=>245),
271  'fk_statut' =>array('type'=>'smallint(6)', 'label'=>'Status', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>500),
272  'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>900),
273  );
274 
275 
279  const TYPE_STANDARD = 0;
280 
284  const TYPE_REPLACEMENT = 1;
285 
289  const TYPE_CREDIT_NOTE = 2;
290 
294  const TYPE_DEPOSIT = 3;
295 
299  const STATUS_DRAFT = 0;
300 
304  const STATUS_VALIDATED = 1;
305 
313  const STATUS_CLOSED = 2;
314 
322  const STATUS_ABANDONED = 3;
323 
324  const CLOSECODE_DISCOUNTVAT = 'discount_vat';
325  const CLOSECODE_BADCREDIT = 'badsupplier';
326  const CLOSECODE_ABANDONED = 'abandon';
327  const CLOSECODE_REPLACED = 'replaced';
328 
334  public function __construct($db)
335  {
336  $this->db = $db;
337  }
338 
345  public function create($user)
346  {
347  global $langs, $conf, $hookmanager;
348 
349  $error = 0;
350  $now = dol_now();
351 
352  // Clean parameters
353  if (isset($this->ref_supplier)) $this->ref_supplier = trim($this->ref_supplier);
354  if (empty($this->type)) $this->type = self::TYPE_STANDARD;
355  if (empty($this->date)) $this->date = $now;
356 
357  $socid = $this->socid;
358  $ref_supplier = $this->ref_supplier;
359  $amount = $this->amount;
360  $remise = $this->remise;
361 
362  // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
363  if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $this->date);
364  else $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
365  if (empty($this->fk_multicurrency))
366  {
367  $this->multicurrency_code = $conf->currency;
368  $this->fk_multicurrency = 0;
369  $this->multicurrency_tx = 1;
370  }
371 
372  $this->db->begin();
373 
374  if (!$remise) $remise = 0;
375 
376  $sql = "INSERT INTO ".MAIN_DB_PREFIX."facture_fourn (";
377  $sql .= "ref";
378  $sql .= ", ref_supplier";
379  $sql .= ", entity";
380  $sql .= ", type";
381  $sql .= ", libelle";
382  $sql .= ", fk_soc";
383  $sql .= ", datec";
384  $sql .= ", datef";
385  $sql .= ", fk_projet";
386  $sql .= ", fk_cond_reglement";
387  $sql .= ", fk_mode_reglement";
388  $sql .= ", fk_account";
389  $sql .= ", note_private";
390  $sql .= ", note_public";
391  $sql .= ", fk_user_author";
392  $sql .= ", date_lim_reglement";
393  $sql .= ", fk_incoterms, location_incoterms";
394  $sql .= ", fk_multicurrency";
395  $sql .= ", multicurrency_code";
396  $sql .= ", multicurrency_tx";
397  $sql .= ", fk_facture_source";
398  $sql .= ")";
399  $sql .= " VALUES (";
400  $sql .= "'(PROV)'";
401  $sql .= ", '".$this->db->escape($this->ref_supplier)."'";
402  $sql .= ", ".$conf->entity;
403  $sql .= ", '".$this->db->escape($this->type)."'";
404  $sql .= ", '".$this->db->escape(isset($this->label) ? $this->label : (isset($this->libelle) ? $this->libelle : ''))."'";
405  $sql .= ", ".$this->socid;
406  $sql .= ", '".$this->db->idate($now)."'";
407  $sql .= ", '".$this->db->idate($this->date)."'";
408  $sql .= ", ".($this->fk_project > 0 ? $this->fk_project : "null");
409  $sql .= ", ".($this->cond_reglement_id > 0 ? $this->cond_reglement_id : "null");
410  $sql .= ", ".($this->mode_reglement_id > 0 ? $this->mode_reglement_id : "null");
411  $sql .= ", ".($this->fk_account > 0 ? $this->fk_account : 'NULL');
412  $sql .= ", '".$this->db->escape($this->note_private)."'";
413  $sql .= ", '".$this->db->escape($this->note_public)."'";
414  $sql .= ", ".$user->id.",";
415  $sql .= $this->date_echeance != '' ? "'".$this->db->idate($this->date_echeance)."'" : "null";
416  $sql .= ", ".(int) $this->fk_incoterms;
417  $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
418  $sql .= ", ".(int) $this->fk_multicurrency;
419  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
420  $sql .= ", ".(double) $this->multicurrency_tx;
421  $sql .= ", ".(isset($this->fk_facture_source) ? $this->fk_facture_source : "NULL");
422  $sql .= ")";
423 
424  dol_syslog(get_class($this)."::create", LOG_DEBUG);
425  $resql = $this->db->query($sql);
426  if ($resql)
427  {
428  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn');
429 
430  // Update ref with new one
431  $this->ref = '(PROV'.$this->id.')';
432  $sql = 'UPDATE '.MAIN_DB_PREFIX."facture_fourn SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".$this->id;
433 
434  dol_syslog(get_class($this)."::create", LOG_DEBUG);
435  $resql = $this->db->query($sql);
436  if (!$resql) $error++;
437 
438  if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) // To use new linkedObjectsIds instead of old linked_objects
439  {
440  $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
441  }
442 
443  // Add object linked
444  if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects))
445  {
446  foreach ($this->linked_objects as $origin => $tmp_origin_id)
447  {
448  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, ...))
449  {
450  foreach ($tmp_origin_id as $origin_id)
451  {
452  $ret = $this->add_object_linked($origin, $origin_id);
453  if (!$ret)
454  {
455  dol_print_error($this->db);
456  $error++;
457  }
458  }
459  } else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
460  {
461  $origin_id = $tmp_origin_id;
462  $ret = $this->add_object_linked($origin, $origin_id);
463  if (!$ret)
464  {
465  dol_print_error($this->db);
466  $error++;
467  }
468  }
469  }
470  }
471 
472  if (count($this->lines) && is_object($this->lines[0])) // If this->lines is array of InvoiceLines (preferred mode)
473  {
474  dol_syslog("There is ".count($this->lines)." lines that are invoice lines objects");
475  foreach ($this->lines as $i => $val)
476  {
477  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn, special_code)';
478  $sql .= ' VALUES ('.$this->id.','.intval($this->lines[$i]->special_code).')';
479 
480  $resql_insert = $this->db->query($sql);
481  if ($resql_insert)
482  {
483  $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det');
484 
485  $this->updateline(
486  $idligne,
487  $this->lines[$i]->description,
488  $this->lines[$i]->pu_ht,
489  $this->lines[$i]->tva_tx.($this->lines[$i]->vat_src_code ? ' ('.$this->lines[$i]->vat_src_code.')' : ''),
490  $this->lines[$i]->localtax1_tx,
491  $this->lines[$i]->localtax2_tx,
492  $this->lines[$i]->qty,
493  $this->lines[$i]->fk_product,
494  'HT',
495  (!empty($this->lines[$i]->info_bits) ? $this->lines[$i]->info_bits : ''),
496  $this->lines[$i]->product_type,
497  $this->lines[$i]->remise_percent,
498  false,
499  $this->lines[$i]->date_start,
500  $this->lines[$i]->date_end,
501  $this->lines[$i]->array_options,
502  $this->lines[$i]->fk_unit,
503  $this->lines[$i]->multicurrency_subprice
504  );
505  } else {
506  $this->error = $this->db->lasterror();
507  $this->db->rollback();
508  return -5;
509  }
510  }
511  } else // If this->lines is an array of invoice line arrays
512  {
513  dol_syslog("There is ".count($this->lines)." lines that are array lines");
514  foreach ($this->lines as $i => $val)
515  {
516  $line = $this->lines[$i];
517 
518  // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
519  //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
520  if (!is_object($line)) $line = (object) $line;
521 
522  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn, special_code)';
523  $sql .= ' VALUES ('.$this->id.','.intval($this->lines[$i]->special_code).')';
524 
525  $resql_insert = $this->db->query($sql);
526  if ($resql_insert)
527  {
528  $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det');
529 
530  $this->updateline(
531  $idligne,
532  $line->description,
533  $line->pu_ht,
534  $line->tva_tx,
535  $line->localtax1_tx,
536  $line->localtax2_tx,
537  $line->qty,
538  $line->fk_product,
539  'HT',
540  (!empty($line->info_bits) ? $line->info_bits : ''),
541  $line->product_type
542  );
543  } else {
544  $this->error = $this->db->lasterror();
545  $this->db->rollback();
546  return -5;
547  }
548  }
549  }
550 
551  // Update total price
552  $result = $this->update_price();
553  if ($result > 0)
554  {
555  // Actions on extra fields
556  if (!$error)
557  {
558  $result = $this->insertExtraFields(); // This also set $this->error or $this->errors if errors are found
559  if ($result < 0)
560  {
561  $error++;
562  }
563  }
564 
565  if (!$error)
566  {
567  // Call trigger
568  $result = $this->call_trigger('BILL_SUPPLIER_CREATE', $user);
569  if ($result < 0) $error++;
570  // End call triggers
571  }
572 
573  if (!$error)
574  {
575  $this->db->commit();
576  return $this->id;
577  } else {
578  $this->db->rollback();
579  return -4;
580  }
581  } else {
582  $this->error = $langs->trans('FailedToUpdatePrice');
583  $this->db->rollback();
584  return -3;
585  }
586  } else {
587  if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS')
588  {
589  $this->error = $langs->trans('ErrorRefAlreadyExists');
590  $this->db->rollback();
591  return -1;
592  } else {
593  $this->error = $this->db->lasterror();
594  $this->db->rollback();
595  return -2;
596  }
597  }
598  }
599 
607  public function fetch($id = '', $ref = '')
608  {
609  global $langs;
610 
611  $sql = "SELECT";
612  $sql .= " t.rowid,";
613  $sql .= " t.ref,";
614  $sql .= " t.ref_supplier,";
615  $sql .= " t.entity,";
616  $sql .= " t.type,";
617  $sql .= " t.fk_soc,";
618  $sql .= " t.datec,";
619  $sql .= " t.datef,";
620  $sql .= " t.tms,";
621  $sql .= " t.libelle as label,";
622  $sql .= " t.paye,";
623  $sql .= " t.amount,";
624  $sql .= " t.remise,";
625  $sql .= " t.close_code,";
626  $sql .= " t.close_note,";
627  $sql .= " t.tva,";
628  $sql .= " t.localtax1,";
629  $sql .= " t.localtax2,";
630  $sql .= " t.total_ht,";
631  $sql .= " t.total_tva,";
632  $sql .= " t.total_ttc,";
633  $sql .= " t.fk_statut,";
634  $sql .= " t.fk_user_author,";
635  $sql .= " t.fk_user_valid,";
636  $sql .= " t.fk_facture_source,";
637  $sql .= " t.fk_projet as fk_project,";
638  $sql .= " t.fk_cond_reglement,";
639  $sql .= " t.fk_account,";
640  $sql .= " t.fk_mode_reglement,";
641  $sql .= " t.date_lim_reglement,";
642  $sql .= " t.note_private,";
643  $sql .= " t.note_public,";
644  $sql .= " t.model_pdf,";
645  $sql .= " t.import_key,";
646  $sql .= " t.extraparams,";
647  $sql .= " cr.code as cond_reglement_code, cr.libelle as cond_reglement_label, cr.libelle_facture as cond_reglement_doc,";
648  $sql .= " p.code as mode_reglement_code, p.libelle as mode_reglement_label,";
649  $sql .= ' s.nom as socnom, s.rowid as socid,';
650  $sql .= ' t.fk_incoterms, t.location_incoterms,';
651  $sql .= " i.libelle as label_incoterms,";
652  $sql .= ' t.fk_multicurrency, t.multicurrency_code, t.multicurrency_tx, t.multicurrency_total_ht, t.multicurrency_total_tva, t.multicurrency_total_ttc';
653  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as t';
654  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON (t.fk_soc = s.rowid)";
655  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_payment_term as cr ON t.fk_cond_reglement = cr.rowid";
656  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as p ON t.fk_mode_reglement = p.id";
657  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON t.fk_incoterms = i.rowid';
658  if ($id) $sql .= " WHERE t.rowid=".$id;
659  if ($ref) $sql .= " WHERE t.ref='".$this->db->escape($ref)."' AND t.entity IN (".getEntity('supplier_invoice').")";
660 
661  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
662  $resql = $this->db->query($sql);
663  if ($resql)
664  {
665  if ($this->db->num_rows($resql))
666  {
667  $obj = $this->db->fetch_object($resql);
668 
669  $this->id = $obj->rowid;
670  $this->ref = $obj->ref ? $obj->ref : $obj->rowid; // We take rowid if ref is empty for backward compatibility
671 
672  $this->ref_supplier = $obj->ref_supplier;
673  $this->entity = $obj->entity;
674  $this->type = empty($obj->type) ? self::TYPE_STANDARD : $obj->type;
675  $this->fk_soc = $obj->fk_soc;
676  $this->datec = $this->db->jdate($obj->datec);
677  $this->date = $this->db->jdate($obj->datef);
678  $this->datep = $this->db->jdate($obj->datef);
679  $this->tms = $this->db->jdate($obj->tms);
680  $this->libelle = $obj->label; // deprecated
681  $this->label = $obj->label;
682  $this->paye = $obj->paye;
683  $this->paid = $obj->paye;
684  $this->amount = $obj->amount;
685  $this->remise = $obj->remise;
686  $this->close_code = $obj->close_code;
687  $this->close_note = $obj->close_note;
688  $this->tva = $obj->tva;
689  $this->total_localtax1 = $obj->localtax1;
690  $this->total_localtax2 = $obj->localtax2;
691  $this->total_ht = $obj->total_ht;
692  $this->total_tva = $obj->total_tva;
693  $this->total_ttc = $obj->total_ttc;
694  $this->fk_statut = $obj->fk_statut;
695  $this->statut = $obj->fk_statut;
696  $this->fk_user_author = $obj->fk_user_author;
697  $this->author = $obj->fk_user_author;
698  $this->fk_user_valid = $obj->fk_user_valid;
699  $this->fk_facture_source = $obj->fk_facture_source;
700  $this->fk_project = $obj->fk_project;
701  $this->cond_reglement_id = $obj->fk_cond_reglement;
702  $this->cond_reglement_code = $obj->cond_reglement_code;
703  $this->cond_reglement = $obj->cond_reglement_label; // deprecated
704  $this->cond_reglement_label = $obj->cond_reglement_label;
705  $this->cond_reglement_doc = $obj->cond_reglement_doc;
706  $this->fk_account = $obj->fk_account;
707  $this->mode_reglement_id = $obj->fk_mode_reglement;
708  $this->mode_reglement_code = $obj->mode_reglement_code;
709  $this->mode_reglement = $obj->mode_reglement_label;
710  $this->date_echeance = $this->db->jdate($obj->date_lim_reglement);
711  $this->note = $obj->note_private; // deprecated
712  $this->note_private = $obj->note_private;
713  $this->note_public = $obj->note_public;
714  $this->model_pdf = $obj->model_pdf;
715  $this->modelpdf = $obj->model_pdf; // deprecated
716  $this->import_key = $obj->import_key;
717 
718  //Incoterms
719  $this->fk_incoterms = $obj->fk_incoterms;
720  $this->location_incoterms = $obj->location_incoterms;
721  $this->label_incoterms = $obj->label_incoterms;
722 
723  // Multicurrency
724  $this->fk_multicurrency = $obj->fk_multicurrency;
725  $this->multicurrency_code = $obj->multicurrency_code;
726  $this->multicurrency_tx = $obj->multicurrency_tx;
727  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
728  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
729  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
730 
731  $this->extraparams = (array) json_decode($obj->extraparams, true);
732 
733  $this->socid = $obj->socid;
734  $this->socnom = $obj->socnom;
735 
736  // Retrieve all extrafield
737  // fetch optionals attributes and labels
738  $this->fetch_optionals();
739 
740  if ($this->statut == self::STATUS_DRAFT) $this->brouillon = 1;
741 
742  $result = $this->fetch_lines();
743  if ($result < 0)
744  {
745  $this->error = $this->db->lasterror();
746  return -3;
747  }
748  } else {
749  $this->error = 'Bill with id '.$id.' not found';
750  dol_syslog(get_class($this).'::fetch '.$this->error);
751  return 0;
752  }
753 
754  $this->db->free($resql);
755  return 1;
756  } else {
757  $this->error = "Error ".$this->db->lasterror();
758  return -1;
759  }
760  }
761 
762 
763  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
769  public function fetch_lines()
770  {
771  // phpcs:enable
772  $this->lines = array();
773 
774  $sql = 'SELECT f.rowid, f.ref as ref_supplier, f.description, f.date_start, f.date_end, f.pu_ht, f.pu_ttc, f.qty, f.remise_percent, f.vat_src_code, f.tva_tx';
775  $sql .= ', f.localtax1_tx, f.localtax2_tx, f.localtax1_type, f.localtax2_type, f.total_localtax1, f.total_localtax2, f.fk_facture_fourn ';
776  $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';
777  $sql .= ', p.rowid as product_id, p.ref as product_ref, p.label as label, p.description as product_desc';
778  $sql .= ', f.fk_code_ventilation, f.fk_multicurrency, f.multicurrency_code, f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc';
779  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
780  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
781  $sql .= ' WHERE fk_facture_fourn='.$this->id;
782  $sql .= ' ORDER BY f.rang, f.rowid';
783 
784  dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
785  $resql_rows = $this->db->query($sql);
786  if ($resql_rows)
787  {
788  $num_rows = $this->db->num_rows($resql_rows);
789  if ($num_rows)
790  {
791  $i = 0;
792  while ($i < $num_rows)
793  {
794  $obj = $this->db->fetch_object($resql_rows);
795 
796  $line = new SupplierInvoiceLine($this->db);
797 
798  $line->id = $obj->rowid;
799  $line->rowid = $obj->rowid;
800  $line->description = $obj->description;
801  $line->date_start = $obj->date_start;
802  $line->date_end = $obj->date_end;
803 
804  $line->product_ref = $obj->product_ref;
805  $line->ref = $obj->product_ref;
806  $line->ref_supplier = $obj->ref_supplier;
807  $line->libelle = $obj->label;
808  $line->label = $obj->label;
809  $line->product_desc = $obj->product_desc;
810  $line->subprice = $obj->pu_ht;
811  $line->pu_ht = $obj->pu_ht;
812  $line->pu_ttc = $obj->pu_ttc;
813 
814  $line->vat_src_code = $obj->vat_src_code;
815  $line->tva_tx = $obj->tva_tx;
816  $line->localtax1_tx = $obj->localtax1_tx;
817  $line->localtax2_tx = $obj->localtax2_tx;
818  $line->localtax1_type = $obj->localtax1_type;
819  $line->localtax2_type = $obj->localtax2_type;
820  $line->qty = $obj->qty;
821  $line->remise_percent = $obj->remise_percent;
822  $line->tva = $obj->total_tva; // deprecated
823  $line->total_ht = $obj->total_ht;
824  $line->total_ttc = $obj->total_ttc;
825  $line->total_tva = $obj->total_tva;
826  $line->total_localtax1 = $obj->total_localtax1;
827  $line->total_localtax2 = $obj->total_localtax2;
828  $line->fk_facture_fourn = $obj->fk_facture_fourn;
829  $line->fk_product = $obj->fk_product;
830  $line->product_type = $obj->product_type;
831  $line->product_label = $obj->label;
832  $line->info_bits = $obj->info_bits;
833  $line->fk_parent_line = $obj->fk_parent_line;
834  $line->special_code = $obj->special_code;
835  $line->rang = $obj->rang;
836  $line->fk_unit = $obj->fk_unit;
837 
838  // Accountancy
839  $line->code_ventilation = $obj->fk_code_ventilation;
840  $line->fk_accounting_account = $obj->fk_code_ventilation;
841 
842  // Multicurrency
843  $line->fk_multicurrency = $obj->fk_multicurrency;
844  $line->multicurrency_code = $obj->multicurrency_code;
845  $line->multicurrency_subprice = $obj->multicurrency_subprice;
846  $line->multicurrency_total_ht = $obj->multicurrency_total_ht;
847  $line->multicurrency_total_tva = $obj->multicurrency_total_tva;
848  $line->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
849 
850  // Extra fields
851  $line->fetch_optionals();
852 
853  $this->lines[$i] = $line;
854 
855  $i++;
856  }
857  }
858  $this->db->free($resql_rows);
859  return 1;
860  } else {
861  $this->error = $this->db->error();
862  return -3;
863  }
864  }
865 
866 
874  public function update($user = null, $notrigger = 0)
875  {
876  global $conf, $langs;
877  $error = 0;
878 
879  // Clean parameters
880  if (empty($this->type)) $this->type = self::TYPE_STANDARD;
881  if (isset($this->ref)) $this->ref = trim($this->ref);
882  if (isset($this->ref_supplier)) $this->ref_supplier = trim($this->ref_supplier);
883  if (isset($this->entity)) $this->entity = trim($this->entity);
884  if (isset($this->type)) $this->type = trim($this->type);
885  if (isset($this->fk_soc)) $this->fk_soc = trim($this->fk_soc);
886  if (isset($this->label)) $this->label = trim($this->label);
887  if (isset($this->libelle)) $this->libelle = trim($this->libelle); // deprecated
888  if (isset($this->paye)) $this->paye = trim($this->paye);
889  if (isset($this->amount)) $this->amount = trim($this->amount);
890  if (isset($this->remise)) $this->remise = trim($this->remise);
891  if (isset($this->close_code)) $this->close_code = trim($this->close_code);
892  if (isset($this->close_note)) $this->close_note = trim($this->close_note);
893  if (isset($this->tva)) $this->tva = trim($this->tva);
894  if (isset($this->localtax1)) $this->localtax1 = trim($this->localtax1);
895  if (isset($this->localtax2)) $this->localtax2 = trim($this->localtax2);
896  if (empty($this->total_ht)) $this->total_ht = 0;
897  if (empty($this->total_tva)) $this->total_tva = 0;
898  // if (isset($this->total_localtax1)) $this->total_localtax1=trim($this->total_localtax1);
899  // if (isset($this->total_localtax2)) $this->total_localtax2=trim($this->total_localtax2);
900  if (isset($this->total_ttc)) $this->total_ttc = trim($this->total_ttc);
901  if (isset($this->statut)) $this->statut = (int) $this->statut;
902  if (isset($this->author)) $this->author = trim($this->author);
903  if (isset($this->fk_user_valid)) $this->fk_user_valid = trim($this->fk_user_valid);
904  if (isset($this->fk_facture_source)) $this->fk_facture_source = trim($this->fk_facture_source);
905  if (isset($this->fk_project)) $this->fk_project = trim($this->fk_project);
906  if (isset($this->cond_reglement_id)) $this->cond_reglement_id = trim($this->cond_reglement_id);
907  if (isset($this->note_private)) $this->note = trim($this->note_private);
908  if (isset($this->note_public)) $this->note_public = trim($this->note_public);
909  if (isset($this->model_pdf)) $this->model_pdf = trim($this->model_pdf);
910  if (isset($this->import_key)) $this->import_key = trim($this->import_key);
911 
912 
913  // Check parameters
914  // Put here code to add control on parameters values
915 
916  // Update request
917  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn SET";
918  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
919  $sql .= " ref_supplier=".(isset($this->ref_supplier) ? "'".$this->db->escape($this->ref_supplier)."'" : "null").",";
920  $sql .= " entity=".(isset($this->entity) ? $this->entity : "null").",";
921  $sql .= " type=".(isset($this->type) ? $this->type : "null").",";
922  $sql .= " fk_soc=".(isset($this->fk_soc) ? $this->fk_soc : "null").",";
923  $sql .= " datec=".(dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
924  $sql .= " datef=".(dol_strlen($this->date) != 0 ? "'".$this->db->idate($this->date)."'" : 'null').",";
925  if (dol_strlen($this->tms) != 0) $sql .= " tms=".(dol_strlen($this->tms) != 0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
926  $sql .= " libelle=".(isset($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
927  $sql .= " paye=".(isset($this->paye) ? $this->paye : "null").",";
928  $sql .= " amount=".(isset($this->amount) ? $this->amount : "null").",";
929  $sql .= " remise=".(isset($this->remise) ? $this->remise : "null").",";
930  $sql .= " close_code=".(isset($this->close_code) ? "'".$this->db->escape($this->close_code)."'" : "null").",";
931  $sql .= " close_note=".(isset($this->close_note) ? "'".$this->db->escape($this->close_note)."'" : "null").",";
932  $sql .= " tva=".(isset($this->tva) ? $this->tva : "null").",";
933  $sql .= " localtax1=".(isset($this->localtax1) ? $this->localtax1 : "null").",";
934  $sql .= " localtax2=".(isset($this->localtax2) ? $this->localtax2 : "null").",";
935  $sql .= " total_ht=".(isset($this->total_ht) ? $this->total_ht : "null").",";
936  $sql .= " total_tva=".(isset($this->total_tva) ? $this->total_tva : "null").",";
937  $sql .= " total_ttc=".(isset($this->total_ttc) ? $this->total_ttc : "null").",";
938  $sql .= " fk_statut=".(isset($this->statut) ? $this->statut : "null").",";
939  $sql .= " fk_user_author=".(isset($this->author) ? $this->author : "null").",";
940  $sql .= " fk_user_valid=".(isset($this->fk_user_valid) ? $this->fk_user_valid : "null").",";
941  $sql .= " fk_facture_source=".(isset($this->fk_facture_source) ? $this->fk_facture_source : "null").",";
942  $sql .= " fk_projet=".(isset($this->fk_project) ? $this->fk_project : "null").",";
943  $sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? $this->cond_reglement_id : "null").",";
944  $sql .= " date_lim_reglement=".(dol_strlen($this->date_echeance) != 0 ? "'".$this->db->idate($this->date_echeance)."'" : 'null').",";
945  $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
946  $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
947  $sql .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
948  $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null")."";
949  $sql .= " WHERE rowid=".$this->id;
950 
951  $this->db->begin();
952 
953  dol_syslog(get_class($this)."::update", LOG_DEBUG);
954  $resql = $this->db->query($sql);
955 
956  if (!$resql) {
957  $error++;
958 
959  if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
960  $this->errors[] = $langs->trans('ErrorRefAlreadyExists');
961  } else {
962  $this->errors[] = "Error ".$this->db->lasterror();
963  }
964  }
965 
966  if (!$error)
967  {
968  $result = $this->insertExtraFields();
969  if ($result < 0)
970  {
971  $error++;
972  }
973  }
974 
975  if (!$error)
976  {
977  if (!$notrigger)
978  {
979  // Call trigger
980  $result = $this->call_trigger('BILL_SUPPLIER_UPDATE', $user);
981  if ($result < 0) $error++;
982  // End call triggers
983  }
984  }
985 
986  // Commit or rollback
987  if ($error)
988  {
989  foreach ($this->errors as $errmsg)
990  {
991  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
992  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
993  }
994  $this->db->rollback();
995  return -1 * $error;
996  } else {
997  $this->db->commit();
998  return 1;
999  }
1000  }
1001 
1002  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1009  public function insert_discount($idremise)
1010  {
1011  // phpcs:enable
1012  global $langs;
1013 
1014  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1015  include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
1016 
1017  $this->db->begin();
1018 
1019  $remise = new DiscountAbsolute($this->db);
1020  $result = $remise->fetch($idremise);
1021 
1022  if ($result > 0)
1023  {
1024  if ($remise->fk_invoice_supplier) // Protection against multiple submission
1025  {
1026  $this->error = $langs->trans("ErrorDiscountAlreadyUsed");
1027  $this->db->rollback();
1028  return -5;
1029  }
1030 
1031  $facligne = new SupplierInvoiceLine($this->db);
1032  $facligne->fk_facture_fourn = $this->id;
1033  $facligne->fk_remise_except = $remise->id;
1034  $facligne->desc = $remise->description; // Description ligne
1035  $facligne->vat_src_code = $remise->vat_src_code;
1036  $facligne->tva_tx = $remise->tva_tx;
1037  $facligne->subprice = -$remise->amount_ht;
1038  $facligne->fk_product = 0; // Id produit predefini
1039  $facligne->product_type = 0;
1040  $facligne->qty = 1;
1041  $facligne->remise_percent = 0;
1042  $facligne->rang = -1;
1043  $facligne->info_bits = 2;
1044 
1045  // Get buy/cost price of invoice that is source of discount
1046  if ($remise->fk_invoice_supplier_source > 0)
1047  {
1048  $srcinvoice = new FactureFournisseur($this->db);
1049  $srcinvoice->fetch($remise->fk_invoice_supplier_source);
1050  $totalcostpriceofinvoice = 0;
1051  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php'; // TODO Move this into commonobject
1052  $formmargin = new FormMargin($this->db);
1053  $arraytmp = $formmargin->getMarginInfosArray($srcinvoice, false);
1054  $facligne->pa_ht = $arraytmp['pa_total'];
1055  }
1056 
1057  $facligne->total_ht = -$remise->amount_ht;
1058  $facligne->total_tva = -$remise->amount_tva;
1059  $facligne->total_ttc = -$remise->amount_ttc;
1060 
1061  $facligne->multicurrency_subprice = -$remise->multicurrency_subprice;
1062  $facligne->multicurrency_total_ht = -$remise->multicurrency_total_ht;
1063  $facligne->multicurrency_total_tva = -$remise->multicurrency_total_tva;
1064  $facligne->multicurrency_total_ttc = -$remise->multicurrency_total_ttc;
1065 
1066  $lineid = $facligne->insert();
1067  if ($lineid > 0)
1068  {
1069  $result = $this->update_price(1);
1070  if ($result > 0)
1071  {
1072  // Create link between discount and invoice line
1073  $result = $remise->link_to_invoice($lineid, 0, 'supplier');
1074  if ($result < 0)
1075  {
1076  $this->error = $remise->error;
1077  $this->db->rollback();
1078  return -4;
1079  }
1080 
1081  $this->db->commit();
1082  return 1;
1083  } else {
1084  $this->error = $facligne->error;
1085  $this->db->rollback();
1086  return -1;
1087  }
1088  } else {
1089  $this->error = $facligne->error;
1090  $this->db->rollback();
1091  return -2;
1092  }
1093  } else {
1094  $this->db->rollback();
1095  return -3;
1096  }
1097  }
1098 
1099 
1107  public function delete(User $user, $notrigger = 0)
1108  {
1109  global $langs, $conf;
1110 
1111  $rowid = $this->id;
1112 
1113  dol_syslog("FactureFournisseur::delete rowid=".$rowid, LOG_DEBUG);
1114 
1115  // TODO Test if there is at least on payment. If yes, refuse to delete.
1116 
1117  $error = 0;
1118  $this->db->begin();
1119 
1120  if (!$error && !$notrigger)
1121  {
1122  // Call trigger
1123  $result = $this->call_trigger('BILL_SUPPLIER_DELETE', $user);
1124  if ($result < 0)
1125  {
1126  $this->db->rollback();
1127  return -1;
1128  }
1129  // Fin appel triggers
1130  }
1131 
1132  if (!$error) {
1133  // If invoice was converted into a discount not yet consumed, we remove discount
1134  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'societe_remise_except';
1135  $sql .= ' WHERE fk_invoice_supplier_source = '.$rowid;
1136  $sql .= ' AND fk_invoice_supplier_line IS NULL';
1137  $resql = $this->db->query($sql);
1138 
1139  // If invoice has consumned discounts
1140  $this->fetch_lines();
1141  $list_rowid_det = array();
1142  foreach ($this->lines as $key => $invoiceline) {
1143  $list_rowid_det[] = $invoiceline->rowid;
1144  }
1145 
1146  // Consumned discounts are freed
1147  if (count($list_rowid_det)) {
1148  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
1149  $sql .= ' SET fk_invoice_supplier = NULL, fk_invoice_supplier_line = NULL';
1150  $sql .= ' WHERE fk_invoice_supplier_line IN ('.join(',', $list_rowid_det).')';
1151 
1152  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1153  if (!$this->db->query($sql)) {
1154  $error++;
1155  }
1156  }
1157  }
1158 
1159  if (!$error)
1160  {
1161  $main = MAIN_DB_PREFIX.'facture_fourn_det';
1162  $ef = $main."_extrafields";
1163  $sqlef = "DELETE FROM $ef WHERE fk_object IN (SELECT rowid FROM $main WHERE fk_facture_fourn = $rowid)";
1164  $resqlef = $this->db->query($sqlef);
1165  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det WHERE fk_facture_fourn = '.$rowid.';';
1166  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1167  $resql = $this->db->query($sql);
1168  if ($resqlef && $resql)
1169  {
1170  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn WHERE rowid = '.$rowid;
1171  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1172  $resql2 = $this->db->query($sql);
1173  if (!$resql2) {
1174  $error++;
1175  }
1176  } else {
1177  $error++;
1178  }
1179  }
1180 
1181  if (!$error)
1182  {
1183  // Delete linked object
1184  $res = $this->deleteObjectLinked();
1185  if ($res < 0) $error++;
1186  }
1187 
1188  if (!$error)
1189  {
1190  // Delete linked object
1191  $res = $this->deleteObjectLinked();
1192  if ($res < 0) $error++;
1193  }
1194 
1195  if (!$error)
1196  {
1197  // Delete record into ECM index (Note that delete is also done when deleting files with the dol_delete_dir_recursive
1198  $this->deleteEcmFiles();
1199 
1200  // We remove directory
1201  if ($conf->fournisseur->facture->dir_output)
1202  {
1203  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1204 
1205  $ref = dol_sanitizeFileName($this->ref);
1206  $dir = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$ref;
1207  $file = $dir."/".$ref.".pdf";
1208  if (file_exists($file))
1209  {
1210  if (!dol_delete_file($file, 0, 0, 0, $this)) // For triggers
1211  {
1212  $this->error = 'ErrorFailToDeleteFile';
1213  $error++;
1214  }
1215  }
1216  if (file_exists($dir))
1217  {
1218  $res = @dol_delete_dir_recursive($dir);
1219 
1220  if (!$res)
1221  {
1222  $this->error = 'ErrorFailToDeleteDir';
1223  $error++;
1224  }
1225  }
1226  }
1227  }
1228 
1229  // Remove extrafields
1230  if (!$error)
1231  {
1232  $result = $this->deleteExtraFields();
1233  if ($result < 0)
1234  {
1235  $error++;
1236  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1237  }
1238  }
1239 
1240  if (!$error)
1241  {
1242  dol_syslog(get_class($this)."::delete $this->id by $user->id", LOG_DEBUG);
1243  $this->db->commit();
1244  return 1;
1245  } else {
1246  $this->error = $this->db->lasterror();
1247  $this->db->rollback();
1248  return -$error;
1249  }
1250  }
1251 
1252 
1253  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1262  public function set_paid($user, $close_code = '', $close_note = '')
1263  {
1264  // phpcs:enable
1265  global $conf, $langs;
1266  $error = 0;
1267 
1268  $this->db->begin();
1269 
1270  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn';
1271  $sql .= ' SET paye = 1, fk_statut = '.self::STATUS_CLOSED;
1272  $sql .= ' WHERE rowid = '.$this->id;
1273 
1274  dol_syslog("FactureFournisseur::set_paid", LOG_DEBUG);
1275  $resql = $this->db->query($sql);
1276  if ($resql)
1277  {
1278  // Call trigger
1279  $result = $this->call_trigger('BILL_SUPPLIER_PAYED', $user);
1280  if ($result < 0) $error++;
1281  // End call triggers
1282  } else {
1283  $error++;
1284  $this->error = $this->db->error();
1285  dol_print_error($this->db);
1286  }
1287 
1288  if (!$error)
1289  {
1290  $this->db->commit();
1291  return 1;
1292  } else {
1293  $this->db->rollback();
1294  return -1;
1295  }
1296  }
1297 
1298 
1299  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1308  public function set_unpaid($user)
1309  {
1310  // phpcs:enable
1311  global $conf, $langs;
1312  $error = 0;
1313 
1314  $this->db->begin();
1315 
1316  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn';
1317  $sql .= ' SET paye=0, fk_statut=1, close_code=null, close_note=null';
1318  $sql .= ' WHERE rowid = '.$this->id;
1319 
1320  dol_syslog("FactureFournisseur::set_unpaid", LOG_DEBUG);
1321  $resql = $this->db->query($sql);
1322  if ($resql)
1323  {
1324  // Call trigger
1325  $result = $this->call_trigger('BILL_SUPPLIER_UNPAYED', $user);
1326  if ($result < 0) $error++;
1327  // End call triggers
1328  } else {
1329  $error++;
1330  $this->error = $this->db->lasterror();
1331  dol_syslog("FactureFournisseur::set_unpaid ".$this->error);
1332  }
1333 
1334  if (!$error)
1335  {
1336  $this->db->commit();
1337  return 1;
1338  } else {
1339  $this->db->rollback();
1340  return -1;
1341  }
1342  }
1343 
1353  public function validate($user, $force_number = '', $idwarehouse = 0, $notrigger = 0)
1354  {
1355  global $conf, $langs;
1356 
1357  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1358 
1359  $now = dol_now();
1360 
1361  $error = 0;
1362  dol_syslog(get_class($this).'::validate user='.$user->id.', force_number='.$force_number.', idwarehouse='.$idwarehouse);
1363 
1364  // Force to have object complete for checks
1365  $this->fetch_thirdparty();
1366  $this->fetch_lines();
1367 
1368  // Check parameters
1369  if ($this->statut > self::STATUS_DRAFT) // This is to avoid to validate twice (avoid errors on logs and stock management)
1370  {
1371  dol_syslog(get_class($this)."::validate no draft status", LOG_WARNING);
1372  return 0;
1373  }
1374  if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ').'/', $this->ref_supplier))
1375  {
1376  $langs->load("errors");
1377  $this->error = $langs->trans("ErrorFieldFormat", $langs->transnoentities("RefSupplier")).'. '.$langs->trans('RemoveString', $langs->transnoentitiesnoconv("CopyOf"));
1378  return -1;
1379  }
1380  if (count($this->lines) <= 0)
1381  {
1382  $langs->load("errors");
1383  $this->error = $langs->trans("ErrorObjectMustHaveLinesToBeValidated", $this->ref);
1384  return -1;
1385  }
1386 
1387  $this->db->begin();
1388 
1389  // Define new ref
1390  if ($force_number)
1391  {
1392  $num = $force_number;
1393  } elseif (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) // empty should not happened, but when it occurs, the test save life
1394  {
1395  $num = $this->getNextNumRef($this->thirdparty);
1396  } else {
1397  $num = $this->ref;
1398  }
1399  $this->newref = dol_sanitizeFileName($num);
1400 
1401  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1402  $sql .= " SET ref='".$num."', fk_statut = 1, fk_user_valid = ".$user->id.", date_valid = '".$this->db->idate($now)."'";
1403  $sql .= " WHERE rowid = ".$this->id;
1404 
1405  dol_syslog(get_class($this)."::validate", LOG_DEBUG);
1406  $resql = $this->db->query($sql);
1407  if ($resql)
1408  {
1409  // Si on incrémente le produit principal et ses composants à la validation de facture fournisseur
1410  if (!$error && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL))
1411  {
1412  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1413  $langs->load("agenda");
1414 
1415  $cpt = count($this->lines);
1416  for ($i = 0; $i < $cpt; $i++)
1417  {
1418  if ($this->lines[$i]->fk_product > 0)
1419  {
1420  $this->line = $this->lines[$i];
1421  $mouvP = new MouvementStock($this->db);
1422  $mouvP->origin = &$this;
1423  // We increase stock for product
1424  $up_ht_disc = $this->lines[$i]->pu_ht;
1425  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');
1426  if ($this->type == FactureFournisseur::TYPE_CREDIT_NOTE) $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1427  else $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1428  if ($result < 0) { $error++; }
1429  unset($this->line);
1430  }
1431  }
1432  }
1433 
1434  // Triggers call
1435  if (!$error && empty($notrigger))
1436  {
1437  // Call trigger
1438  $result = $this->call_trigger('BILL_SUPPLIER_VALIDATE', $user);
1439  if ($result < 0) $error++;
1440  // End call triggers
1441  }
1442 
1443  if (!$error)
1444  {
1445  $this->oldref = $this->ref;
1446 
1447  // Rename directory if dir was a temporary ref
1448  if (preg_match('/^[\(]?PROV/i', $this->ref))
1449  {
1450  // Now we rename also files into index
1451  $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'fournisseur/facture/".get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$this->db->escape($this->newref)."'";
1452  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'fournisseur/facture/".get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1453  $resql = $this->db->query($sql);
1454  if (!$resql) { $error++; $this->error = $this->db->lasterror(); }
1455 
1456  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1457  $oldref = dol_sanitizeFileName($this->ref);
1458  $newref = dol_sanitizeFileName($num);
1459  $dirsource = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$oldref;
1460  $dirdest = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$newref;
1461  if (!$error && file_exists($dirsource))
1462  {
1463  dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest);
1464 
1465  if (@rename($dirsource, $dirdest))
1466  {
1467  dol_syslog("Rename ok");
1468  // Rename docs starting with $oldref with $newref
1469  $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, '/'));
1470  foreach ($listoffiles as $fileentry)
1471  {
1472  $dirsource = $fileentry['name'];
1473  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1474  $dirsource = $fileentry['path'].'/'.$dirsource;
1475  $dirdest = $fileentry['path'].'/'.$dirdest;
1476  @rename($dirsource, $dirdest);
1477  }
1478  }
1479  }
1480  }
1481  }
1482 
1483  // Set new ref and define current statut
1484  if (!$error)
1485  {
1486  $this->ref = $num;
1487  $this->statut = self::STATUS_VALIDATED;
1488  //$this->date_validation=$now; this is stored into log table
1489  }
1490 
1491  if (!$error)
1492  {
1493  $this->db->commit();
1494  return 1;
1495  } else {
1496  $this->db->rollback();
1497  return -1;
1498  }
1499  } else {
1500  $this->error = $this->db->error();
1501  $this->db->rollback();
1502  return -1;
1503  }
1504  }
1505 
1513  public function setDraft($user, $idwarehouse = -1)
1514  {
1515  // phpcs:enable
1516  global $conf, $langs;
1517 
1518  $error = 0;
1519 
1520  if ($this->statut == self::STATUS_DRAFT)
1521  {
1522  dol_syslog(__METHOD__." already draft status", LOG_WARNING);
1523  return 0;
1524  }
1525 
1526  dol_syslog(__METHOD__, LOG_DEBUG);
1527 
1528  $this->db->begin();
1529 
1530  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1531  $sql .= " SET fk_statut = ".self::STATUS_DRAFT;
1532  $sql .= " WHERE rowid = ".$this->id;
1533 
1534  $result = $this->db->query($sql);
1535  if ($result)
1536  {
1537  if (!$error)
1538  {
1539  $this->oldcopy = clone $this;
1540  }
1541 
1542  // Si on incremente le produit principal et ses composants a la validation de facture fournisseur, on decremente
1543  if ($result >= 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL))
1544  {
1545  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1546  $langs->load("agenda");
1547 
1548  $cpt = count($this->lines);
1549  for ($i = 0; $i < $cpt; $i++)
1550  {
1551  if ($this->lines[$i]->fk_product > 0)
1552  {
1553  $mouvP = new MouvementStock($this->db);
1554  $mouvP->origin = &$this;
1555  // We increase stock for product
1556  if ($this->type == FactureFournisseur::TYPE_CREDIT_NOTE) $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
1557  else $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
1558  }
1559  }
1560  }
1561  // Triggers call
1562  if (!$error && empty($notrigger))
1563  {
1564  // Call trigger
1565  $result = $this->call_trigger('BILL_SUPPLIER_UNVALIDATE', $user);
1566  if ($result < 0) $error++;
1567  // End call triggers
1568  }
1569  if ($error == 0)
1570  {
1571  $this->db->commit();
1572  return 1;
1573  } else {
1574  $this->db->rollback();
1575  return -1;
1576  }
1577  } else {
1578  $this->error = $this->db->error();
1579  $this->db->rollback();
1580  return -1;
1581  }
1582  }
1583 
1584 
1617  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 = '', $special_code = '', $fk_parent_line = 0)
1618  {
1619  global $langs, $mysoc, $conf;
1620 
1621  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);
1622  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1623 
1624  if ($this->statut == self::STATUS_DRAFT)
1625  {
1626  // Clean parameters
1627  if (empty($remise_percent)) $remise_percent = 0;
1628  if (empty($qty)) $qty = 0;
1629  if (empty($info_bits)) $info_bits = 0;
1630  if (empty($rang)) $rang = 0;
1631  if (empty($ventil)) $ventil = 0;
1632  if (empty($txtva)) $txtva = 0;
1633  if (empty($txlocaltax1)) $txlocaltax1 = 0;
1634  if (empty($txlocaltax2)) $txlocaltax2 = 0;
1635 
1636  $remise_percent = price2num($remise_percent);
1637  $qty = price2num($qty);
1638  $pu = price2num($pu);
1639  if (!preg_match('/\((.*)\)/', $txtva)) {
1640  $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
1641  }
1642  $txlocaltax1 = price2num($txlocaltax1);
1643  $txlocaltax2 = price2num($txlocaltax2);
1644 
1645  if ($date_start && $date_end && $date_start > $date_end) {
1646  $langs->load("errors");
1647  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
1648  return -1;
1649  }
1650 
1651  $this->db->begin();
1652 
1653  if ($fk_product > 0)
1654  {
1655  if (!empty($conf->global->SUPPLIER_INVOICE_WITH_PREDEFINED_PRICES_ONLY))
1656  {
1657  // Check quantity is enough
1658  dol_syslog(get_class($this)."::addline we check supplier prices fk_product=".$fk_product." qty=".$qty." ref_supplier=".$ref_supplier);
1659  $prod = new Product($this->db, $fk_product);
1660  if ($prod->fetch($fk_product) > 0)
1661  {
1662  $product_type = $prod->type;
1663  $label = $prod->label;
1664  $fk_prod_fourn_price = 0;
1665 
1666  // We use 'none' instead of $ref_supplier, because $ref_supplier may not exists anymore. So we will take the first supplier price ok.
1667  // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
1668  $result = $prod->get_buyprice($fk_prod_fourn_price, $qty, $fk_product, 'none', ($this->fk_soc ? $this->fk_soc : $this->socid)); // Search on couple $fk_prod_fourn_price/$qty first, then on triplet $qty/$fk_product/$ref_supplier/$this->fk_soc
1669  if ($result > 0)
1670  {
1671  if (empty($pu)) $pu = $prod->fourn_pu; // Unit price supplier price set by get_buyprice
1672  $ref_supplier = $prod->ref_supplier; // Ref supplier price set by get_buyprice
1673  // is remise percent not keyed but present for the product we add it
1674  if ($remise_percent == 0 && $prod->remise_percent != 0)
1675  $remise_percent = $prod->remise_percent;
1676  }
1677  if ($result == 0) // If result == 0, we failed to found the supplier reference price
1678  {
1679  $langs->load("errors");
1680  $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
1681  $this->db->rollback();
1682  dol_syslog(get_class($this)."::addline we did not found supplier price, so we can't guess unit price");
1683  //$pu = $prod->fourn_pu; // We do not overwrite unit price
1684  //$ref = $prod->ref_fourn; // We do not overwrite ref supplier price
1685  return -1;
1686  }
1687  if ($result == -1)
1688  {
1689  $langs->load("errors");
1690  $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
1691  $this->db->rollback();
1692  dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_DEBUG);
1693  return -1;
1694  }
1695  if ($result < -1)
1696  {
1697  $this->error = $prod->error;
1698  $this->db->rollback();
1699  dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_ERR);
1700  return -1;
1701  }
1702  } else {
1703  $this->error = $prod->error;
1704  $this->db->rollback();
1705  return -1;
1706  }
1707  }
1708  } else {
1709  $product_type = $type;
1710  }
1711 
1712  if (!empty($conf->multicurrency->enabled) && $pu_ht_devise > 0) {
1713  $pu = 0;
1714  }
1715 
1716  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $mysoc, $this->thirdparty);
1717 
1718  // Clean vat code
1719  $reg = array();
1720  $vat_src_code = '';
1721  if (preg_match('/\((.*)\)/', $txtva, $reg))
1722  {
1723  $vat_src_code = $reg[1];
1724  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
1725  }
1726 
1727  // Calcul du total TTC et de la TVA pour la ligne a partir de
1728  // qty, pu, remise_percent et txtva
1729  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1730  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1731 
1732  $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);
1733  $total_ht = $tabprice[0];
1734  $total_tva = $tabprice[1];
1735  $total_ttc = $tabprice[2];
1736  $total_localtax1 = $tabprice[9];
1737  $total_localtax2 = $tabprice[10];
1738  $pu_ht = $tabprice[3];
1739 
1740  // MultiCurrency
1741  $multicurrency_total_ht = $tabprice[16];
1742  $multicurrency_total_tva = $tabprice[17];
1743  $multicurrency_total_ttc = $tabprice[18];
1744  $pu_ht_devise = $tabprice[19];
1745 
1746  // Check parameters
1747  if ($type < 0) return -1;
1748 
1749  if ($rang < 0)
1750  {
1751  $rangmax = $this->line_max();
1752  $rang = $rangmax + 1;
1753  }
1754 
1755  // Insert line
1756  $this->line = new SupplierInvoiceLine($this->db);
1757 
1758  $this->line->context = $this->context;
1759 
1760  $this->line->fk_facture_fourn = $this->id;
1761  //$this->line->label=$label; // deprecated
1762  $this->line->desc = $desc;
1763  $this->line->ref_supplier = $ref_supplier;
1764 
1765  $this->line->qty = ($this->type == self::TYPE_CREDIT_NOTE ?abs($qty) : $qty); // For credit note, quantity is always positive and unit price negative
1766  $this->line->subprice = ($this->type == self::TYPE_CREDIT_NOTE ?-abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
1767 
1768  $this->line->vat_src_code = $vat_src_code;
1769  $this->line->tva_tx = $txtva;
1770  $this->line->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
1771  $this->line->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
1772  $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
1773  $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
1774 
1775  $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
1776  $this->line->total_tva = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_tva) : $total_tva);
1777  $this->line->total_localtax1 = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_localtax1) : $total_localtax1);
1778  $this->line->total_localtax2 = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_localtax2) : $total_localtax2);
1779  $this->line->total_ttc = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_ttc) : $total_ttc);
1780 
1781  $this->line->fk_product = $fk_product;
1782  $this->line->product_type = $type;
1783  $this->line->remise_percent = $remise_percent;
1784  $this->line->date_start = $date_start;
1785  $this->line->date_end = $date_end;
1786  $this->line->ventil = $ventil;
1787  $this->line->rang = $rang;
1788  $this->line->info_bits = $info_bits;
1789 
1790  $this->line->special_code = ((string) $special_code != '' ? $special_code : $this->special_code);
1791  $this->line->fk_parent_line = $fk_parent_line;
1792  $this->line->origin = $this->origin;
1793  $this->line->origin_id = $origin_id;
1794  $this->line->fk_unit = $fk_unit;
1795 
1796  // Multicurrency
1797  $this->line->fk_multicurrency = $this->fk_multicurrency;
1798  $this->line->multicurrency_code = $this->multicurrency_code;
1799  $this->line->multicurrency_subprice = $pu_ht_devise;
1800  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
1801  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
1802  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
1803 
1804  if (is_array($array_options) && count($array_options) > 0) {
1805  $this->line->array_options = $array_options;
1806  }
1807 
1808  $result = $this->line->insert($notrigger);
1809  if ($result > 0)
1810  {
1811  // Reorder if child line
1812  if (!empty($fk_parent_line)) $this->line_order(true, 'DESC');
1813 
1814  // Mise a jour informations denormalisees au niveau de la facture meme
1815  $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.
1816  if ($result > 0)
1817  {
1818  $this->db->commit();
1819  return $this->line->id;
1820  } else {
1821  $this->error = $this->db->error();
1822  $this->db->rollback();
1823  return -1;
1824  }
1825  } else {
1826  $this->error = $this->line->error;
1827  $this->errors = $this->line->errors;
1828  $this->db->rollback();
1829  return -2;
1830  }
1831  } else {
1832  return 0;
1833  }
1834  }
1835 
1860  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, $ref_supplier = '')
1861  {
1862  global $mysoc, $langs;
1863 
1864  dol_syslog(get_class($this)."::updateline $id,$desc,$pu,$vatrate,$qty,$idproduct,$price_base_type,$info_bits,$type,$remise_percent,$notrigger,$date_start,$date_end,$fk_unit,$pu_ht_devise,$ref_supplier", LOG_DEBUG);
1865  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1866 
1867  $pu = price2num($pu);
1868  $qty = price2num($qty);
1869  $remise_percent = price2num($remise_percent);
1870  $pu_ht_devise = price2num($pu_ht_devise);
1871 
1872  // Check parameters
1873  //if (! is_numeric($pu) || ! is_numeric($qty)) return -1;
1874  if ($type < 0) return -1;
1875 
1876  if ($date_start && $date_end && $date_start > $date_end) {
1877  $langs->load("errors");
1878  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
1879  return -1;
1880  }
1881 
1882  // Clean parameters
1883  if (empty($vatrate)) $vatrate = 0;
1884  if (empty($txlocaltax1)) $txlocaltax1 = 0;
1885  if (empty($txlocaltax2)) $txlocaltax2 = 0;
1886 
1887  $txlocaltax1 = price2num($txlocaltax1);
1888  $txlocaltax2 = price2num($txlocaltax2);
1889 
1890  // Calcul du total TTC et de la TVA pour la ligne a partir de
1891  // qty, pu, remise_percent et txtva
1892  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1893  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1894 
1895  $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $mysoc, $this->thirdparty);
1896 
1897  $reg = array();
1898 
1899  // Clean vat code
1900  $vat_src_code = '';
1901  if (preg_match('/\((.*)\)/', $vatrate, $reg))
1902  {
1903  $vat_src_code = $reg[1];
1904  $vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate.
1905  }
1906 
1907  $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);
1908  $total_ht = $tabprice[0];
1909  $total_tva = $tabprice[1];
1910  $total_ttc = $tabprice[2];
1911  $pu_ht = $tabprice[3];
1912  $pu_tva = $tabprice[4];
1913  $pu_ttc = $tabprice[5];
1914  $total_localtax1 = $tabprice[9];
1915  $total_localtax2 = $tabprice[10];
1916 
1917  // MultiCurrency
1918  $multicurrency_total_ht = $tabprice[16];
1919  $multicurrency_total_tva = $tabprice[17];
1920  $multicurrency_total_ttc = $tabprice[18];
1921  $pu_ht_devise = $tabprice[19];
1922 
1923  if (empty($info_bits)) $info_bits = 0;
1924 
1925  if ($idproduct)
1926  {
1927  $product = new Product($this->db);
1928  $result = $product->fetch($idproduct);
1929  $product_type = $product->type;
1930  } else {
1931  $product_type = $type;
1932  }
1933 
1934  //Fetch current line from the database and then clone the object and set it in $oldline property
1935  $line = new SupplierInvoiceLine($this->db);
1936  $line->fetch($id);
1937  $line->fetch_optionals();
1938 
1939  $staticline = clone $line;
1940 
1941  $line->oldline = $staticline;
1942  $line->context = $this->context;
1943 
1944  $line->description = $desc;
1945  $line->subprice = $pu_ht;
1946  $line->pu_ht = $pu_ht;
1947  $line->pu_ttc = $pu_ttc;
1948  $line->qty = $qty;
1949  $line->remise_percent = $remise_percent;
1950  $line->ref_supplier = $ref_supplier;
1951 
1952  $line->date_start = $date_start;
1953  $line->date_end = $date_end;
1954 
1955  $line->vat_src_code = $vat_src_code;
1956  $line->tva_tx = $vatrate;
1957  $line->localtax1_tx = $txlocaltax1;
1958  $line->localtax2_tx = $txlocaltax2;
1959  $line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
1960  $line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
1961  $line->total_ht = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_ht) : $total_ht);
1962  $line->total_tva = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_tva) : $total_tva);
1963  $line->total_localtax1 = $total_localtax1;
1964  $line->total_localtax2 = $total_localtax2;
1965  $line->total_ttc = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_ttc) : $total_ttc);
1966  $line->fk_product = $idproduct;
1967  $line->product_type = $product_type;
1968  $line->info_bits = $info_bits;
1969  $line->fk_unit = $fk_unit;
1970 
1971  if (is_array($array_options) && count($array_options) > 0) {
1972  // We replace values in this->line->array_options only for entries defined into $array_options
1973  foreach ($array_options as $key => $value) {
1974  $line->array_options[$key] = $array_options[$key];
1975  }
1976  }
1977 
1978  // Multicurrency
1979  $line->multicurrency_subprice = $pu_ht_devise;
1980  $line->multicurrency_total_ht = $multicurrency_total_ht;
1981  $line->multicurrency_total_tva = $multicurrency_total_tva;
1982  $line->multicurrency_total_ttc = $multicurrency_total_ttc;
1983 
1984  $res = $line->update($notrigger);
1985 
1986  if ($res < 1) {
1987  $this->errors[] = $line->error;
1988  } else {
1989  // Update total price into invoice record
1990  $res = $this->update_price('', 'auto', 0, $this->thirdparty);
1991  }
1992 
1993  return $res;
1994  }
1995 
2003  public function deleteline($rowid, $notrigger = 0)
2004  {
2005  if (!$rowid) {
2006  $rowid = $this->id;
2007  }
2008 
2009  $this->db->begin();
2010 
2011  // Libere remise liee a ligne de facture
2012  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
2013  $sql .= ' SET fk_invoice_supplier_line = NULL';
2014  $sql .= ' WHERE fk_invoice_supplier_line = '.$rowid;
2015 
2016  dol_syslog(get_class($this)."::deleteline", LOG_DEBUG);
2017  $result = $this->db->query($sql);
2018  if (!$result)
2019  {
2020  $this->error = $this->db->error();
2021  $this->db->rollback();
2022  return -2;
2023  }
2024 
2025  $line = new SupplierInvoiceLine($this->db);
2026 
2027  if ($line->fetch($rowid) < 1) {
2028  return -1;
2029  }
2030 
2031  $res = $line->delete($notrigger);
2032 
2033  if ($res < 1) {
2034  $this->errors[] = $line->error;
2035  $this->db->rollback();
2036  return -3;
2037  } else {
2038  $res = $this->update_price();
2039 
2040  if ($res > 0)
2041  {
2042  $this->db->commit();
2043  return 1;
2044  } else {
2045  $this->db->rollback();
2046  $this->error = $this->db->lasterror();
2047  return -4;
2048  }
2049  }
2050  }
2051 
2052 
2059  public function info($id)
2060  {
2061  $sql = 'SELECT c.rowid, datec, tms as datem, ';
2062  $sql .= ' fk_user_author, fk_user_modif, fk_user_valid';
2063  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as c';
2064  $sql .= ' WHERE c.rowid = '.$id;
2065 
2066  $result = $this->db->query($sql);
2067  if ($result)
2068  {
2069  if ($this->db->num_rows($result))
2070  {
2071  $obj = $this->db->fetch_object($result);
2072  $this->id = $obj->rowid;
2073  if ($obj->fk_user_author)
2074  {
2075  $cuser = new User($this->db);
2076  $cuser->fetch($obj->fk_user_author);
2077  $this->user_creation = $cuser;
2078  }
2079  if ($obj->fk_user_valid)
2080  {
2081  $vuser = new User($this->db);
2082  $vuser->fetch($obj->fk_user_valid);
2083  $this->user_validation = $vuser;
2084  }
2085  if ($obj->fk_user_modif)
2086  {
2087  $muser = new User($this->db);
2088  $muser->fetch($obj->fk_user_modif);
2089  $this->user_modification = $muser;
2090  }
2091  $this->date_creation = $this->db->idate($obj->datec);
2092  $this->date_modification = $this->db->idate($obj->datem);
2093  //$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)
2094  }
2095  $this->db->free($result);
2096  } else {
2097  dol_print_error($this->db);
2098  }
2099  }
2100 
2101  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2110  public function list_replacable_supplier_invoices($socid = 0)
2111  {
2112  // phpcs:enable
2113  global $conf;
2114 
2115  $return = array();
2116 
2117  $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut,";
2118  $sql .= " ff.rowid as rowidnext";
2119  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2120  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2121  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture_fourn as ff ON f.rowid = ff.fk_facture_source";
2122  $sql .= " WHERE (f.fk_statut = ".self::STATUS_VALIDATED." OR (f.fk_statut = ".self::STATUS_ABANDONED." AND f.close_code = '".self::CLOSECODE_ABANDONED."'))";
2123  $sql .= " AND f.entity = ".$conf->entity;
2124  $sql .= " AND f.paye = 0"; // Pas classee payee completement
2125  $sql .= " AND pf.fk_paiementfourn IS NULL"; // Aucun paiement deja fait
2126  $sql .= " AND ff.fk_statut IS NULL"; // Renvoi vrai si pas facture de remplacement
2127  if ($socid > 0) $sql .= " AND f.fk_soc = ".$socid;
2128  $sql .= " ORDER BY f.ref";
2129 
2130  dol_syslog(get_class($this)."::list_replacable_supplier_invoices", LOG_DEBUG);
2131  $resql = $this->db->query($sql);
2132  if ($resql)
2133  {
2134  while ($obj = $this->db->fetch_object($resql))
2135  {
2136  $return[$obj->rowid] = array(
2137  'id' => $obj->rowid,
2138  'ref' => $obj->ref,
2139  'status' => $obj->fk_statut
2140  );
2141  }
2142  //print_r($return);
2143  return $return;
2144  } else {
2145  $this->error = $this->db->error();
2146  return -1;
2147  }
2148  }
2149 
2150  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2160  public function list_qualified_avoir_supplier_invoices($socid = 0)
2161  {
2162  // phpcs:enable
2163  global $conf;
2164 
2165  $return = array();
2166 
2167  $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.paye, pf.fk_paiementfourn";
2168  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2169  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2170  $sql .= " WHERE f.entity = ".$conf->entity;
2171  $sql .= " AND f.fk_statut in (".self::STATUS_VALIDATED.",".self::STATUS_CLOSED.")";
2172  $sql .= " AND NOT EXISTS (SELECT rowid from ".MAIN_DB_PREFIX."facture_fourn as ff WHERE f.rowid = ff.fk_facture_source";
2173  $sql .= " AND ff.type=".self::TYPE_REPLACEMENT.")";
2174  $sql .= " AND f.type != ".self::TYPE_CREDIT_NOTE; // Type non 2 si facture non avoir
2175  if ($socid > 0) $sql .= " AND f.fk_soc = ".$socid;
2176  $sql .= " ORDER BY f.ref";
2177 
2178  dol_syslog(get_class($this)."::list_qualified_avoir_supplier_invoices", LOG_DEBUG);
2179  $resql = $this->db->query($sql);
2180  if ($resql)
2181  {
2182  while ($obj = $this->db->fetch_object($resql))
2183  {
2184  $qualified = 0;
2185  if ($obj->fk_statut == self::STATUS_VALIDATED) $qualified = 1;
2186  if ($obj->fk_statut == self::STATUS_CLOSED) $qualified = 1;
2187  if ($qualified)
2188  {
2189  $paymentornot = ($obj->fk_paiementfourn ? 1 : 0);
2190  $return[$obj->rowid] = array('ref'=>$obj->ref, 'status'=>$obj->fk_statut, 'type'=>$obj->type, 'paye'=>$obj->paye, 'paymentornot'=>$paymentornot);
2191  }
2192  }
2193 
2194  return $return;
2195  } else {
2196  $this->error = $this->db->error();
2197  return -1;
2198  }
2199  }
2200 
2201  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2208  public function load_board($user)
2209  {
2210  // phpcs:enable
2211  global $conf, $langs;
2212 
2213  $sql = 'SELECT ff.rowid, ff.date_lim_reglement as datefin, ff.fk_statut';
2214  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as ff';
2215  if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
2216  $sql .= ' WHERE ff.paye=0';
2217  $sql .= ' AND ff.fk_statut > 0';
2218  $sql .= " AND ff.entity = ".$conf->entity;
2219  if ($user->socid) $sql .= ' AND ff.fk_soc = '.$user->socid;
2220  if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND ff.fk_soc = sc.fk_soc AND sc.fk_user = ".$user->id;
2221 
2222  $resql = $this->db->query($sql);
2223  if ($resql)
2224  {
2225  $langs->load("bills");
2226  $now = dol_now();
2227 
2228  $response = new WorkboardResponse();
2229  $response->warning_delay = $conf->facture->fournisseur->warning_delay / 60 / 60 / 24;
2230  $response->label = $langs->trans("SupplierBillsToPay");
2231  $response->labelShort = $langs->trans("StatusToPay");
2232 
2233  $response->url = DOL_URL_ROOT.'/fourn/facture/list.php?search_status=1&amp;mainmenu=billing&amp;leftmenu=suppliers_bills';
2234  $response->img = img_object($langs->trans("Bills"), "bill");
2235 
2236  $facturestatic = new FactureFournisseur($this->db);
2237 
2238  while ($obj = $this->db->fetch_object($resql))
2239  {
2240  $response->nbtodo++;
2241 
2242  $facturestatic->date_echeance = $this->db->jdate($obj->datefin);
2243  $facturestatic->statut = $obj->fk_statut;
2244 
2245  if ($facturestatic->hasDelay()) {
2246  $response->nbtodolate++;
2247  $response->url_late = DOL_URL_ROOT.'/fourn/facture/list.php?option=late&mainmenu=billing&leftmenu=suppliers_bills';
2248  }
2249  }
2250  $this->db->free($resql);
2251  return $response;
2252  } else {
2253  dol_print_error($this->db);
2254  $this->error = $this->db->error();
2255  return -1;
2256  }
2257  }
2258 
2259 
2273  public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
2274  {
2275  global $langs, $conf, $user;
2276 
2277  $result = '';
2278 
2279  if ($option == 'withdraw') $url = DOL_URL_ROOT.'/compta/facture/prelevement.php?facid='.$this->id.'&type=bank-transfer';
2280  elseif ($option == 'document') $url = DOL_URL_ROOT.'/fourn/facture/document.php?facid='.$this->id;
2281  else $url = DOL_URL_ROOT.'/fourn/facture/card.php?facid='.$this->id;
2282 
2283  if ($short) return $url;
2284 
2285  if ($option !== 'nolink')
2286  {
2287  // Add param to save lastsearch_values or not
2288  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
2289  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values = 1;
2290  if ($add_save_lastsearch_values) $url .= '&save_lastsearch_values=1';
2291  }
2292 
2293  $picto = $this->picto;
2294  if ($this->type == self::TYPE_REPLACEMENT) $picto .= 'r'; // Replacement invoice
2295  if ($this->type == self::TYPE_CREDIT_NOTE) $picto .= 'a'; // Credit note
2296  if ($this->type == self::TYPE_DEPOSIT) $picto .= 'd'; // Deposit invoice
2297 
2298  $label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("SupplierInvoice").'</u>';
2299  if ($this->type == self::TYPE_REPLACEMENT) $label = '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("InvoiceReplace").'</u>';
2300  elseif ($this->type == self::TYPE_CREDIT_NOTE) $label = '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("CreditNote").'</u>';
2301  elseif ($this->type == self::TYPE_DEPOSIT) $label = '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("Deposit").'</u>';
2302  if (isset($this->status)) {
2303  $alreadypaid = -1;
2304  $label .= ' '.$this->getLibStatut(5, $alreadypaid);
2305  }
2306  if (!empty($this->ref))
2307  $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
2308  if (!empty($this->ref_supplier))
2309  $label .= '<br><b>'.$langs->trans('RefSupplier').':</b> '.$this->ref_supplier;
2310  if (!empty($this->label))
2311  $label .= '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
2312  if (!empty($this->date))
2313  $label .= '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
2314  if (!empty($this->total_ht))
2315  $label .= '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
2316  if (!empty($this->total_tva))
2317  $label .= '<br><b>'.$langs->trans('AmountVAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
2318  if (!empty($this->total_ttc))
2319  $label .= '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
2320  if ($moretitle) $label .= ' - '.$moretitle;
2321  if (isset($this->statut) && isset($this->alreadypaid)) {
2322  $label .= '<br><b>'.$langs->trans("Status").":</b> ".$this->getLibStatut(5, $this->alreadypaid);
2323  }
2324 
2325  $ref = $this->ref;
2326  if (empty($ref)) $ref = $this->id;
2327 
2328  $linkclose = '';
2329  if (empty($notooltip))
2330  {
2331  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
2332  {
2333  $label = $langs->trans("ShowSupplierInvoice");
2334  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
2335  }
2336  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
2337  $linkclose .= ' class="classfortooltip"';
2338  }
2339 
2340  $linkstart = '<a href="'.$url.'"';
2341  $linkstart .= $linkclose.'>';
2342  $linkend = '</a>';
2343 
2344  $result .= $linkstart;
2345  if ($withpicto) $result .= img_object(($notooltip ? '' : $label), $picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
2346  if ($withpicto != 2) $result .= ($max ?dol_trunc($ref, $max) : $ref);
2347  $result .= $linkend;
2348 
2349  if ($addlinktonotes)
2350  {
2351  $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
2352  if ($txttoshow)
2353  {
2354  $notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
2355  $result .= ' <span class="note inline-block">';
2356  $result .= '<a href="'.DOL_URL_ROOT.'/fourn/facture/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
2357  $result .= img_picto('', 'note');
2358  $result .= '</a>';
2359  //$result.=img_picto($langs->trans("ViewNote"),'object_generic');
2360  //$result.='</a>';
2361  $result .= '</span>';
2362  }
2363  }
2364 
2365  return $result;
2366  }
2367 
2376  public function getNextNumRef($soc, $mode = 'next')
2377  {
2378  global $db, $langs, $conf;
2379  $langs->load("orders");
2380 
2381  // Clean parameters (if not defined or using deprecated value)
2382  if (empty($conf->global->INVOICE_SUPPLIER_ADDON_NUMBER)) $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER = 'mod_facture_fournisseur_cactus';
2383 
2384  $mybool = false;
2385 
2386  $file = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER.".php";
2387  $classname = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER;
2388 
2389  // Include file with class
2390  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2391 
2392  foreach ($dirmodels as $reldir) {
2393  $dir = dol_buildpath($reldir."core/modules/supplier_invoice/");
2394 
2395  // Load file with numbering class (if found)
2396  $mybool |= @include_once $dir.$file;
2397  }
2398 
2399  if ($mybool === false) {
2400  dol_print_error('', "Failed to include file ".$file);
2401  return '';
2402  }
2403 
2404  $obj = new $classname();
2405  $numref = "";
2406  $numref = $obj->getNumRef($soc, $this, $mode);
2407 
2408  if ($numref != "")
2409  {
2410  return $numref;
2411  } else {
2412  $this->error = $obj->error;
2413  return -1;
2414  }
2415  }
2416 
2417 
2426  public function initAsSpecimen($option = '')
2427  {
2428  global $langs, $conf;
2429  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
2430 
2431  $now = dol_now();
2432 
2433  // Load array of products prodids
2434  $num_prods = 0;
2435  $prodids = array();
2436 
2437  $sql = "SELECT rowid";
2438  $sql .= " FROM ".MAIN_DB_PREFIX."product";
2439  $sql .= " WHERE entity IN (".getEntity('product').")";
2440  $sql .= $this->db->plimit(100);
2441 
2442  $resql = $this->db->query($sql);
2443  if ($resql)
2444  {
2445  $num_prods = $this->db->num_rows($resql);
2446  $i = 0;
2447  while ($i < $num_prods)
2448  {
2449  $i++;
2450  $row = $this->db->fetch_row($resql);
2451  $prodids[$i] = $row[0];
2452  }
2453  }
2454 
2455  // Initialise parametres
2456  $this->id = 0;
2457  $this->ref = 'SPECIMEN';
2458  $this->ref_supplier = 'SUPPLIER_REF_SPECIMEN';
2459  $this->specimen = 1;
2460  $this->socid = 1;
2461  $this->date = $now;
2462  $this->date_lim_reglement = $this->date + 3600 * 24 * 30;
2463  $this->cond_reglement_code = 'RECEP';
2464  $this->mode_reglement_code = 'CHQ';
2465 
2466  $this->note_public = 'This is a comment (public)';
2467  $this->note_private = 'This is a comment (private)';
2468 
2469  $this->multicurrency_tx = 1;
2470  $this->multicurrency_code = $conf->currency;
2471 
2472  if (empty($option) || $option != 'nolines')
2473  {
2474  // Lines
2475  $nbp = 5;
2476  $xnbp = 0;
2477  while ($xnbp < $nbp)
2478  {
2479  $line = new SupplierInvoiceLine($this->db);
2480  $line->desc = $langs->trans("Description")." ".$xnbp;
2481  $line->qty = 1;
2482  $line->subprice = 100;
2483  $line->pu_ht = 100; // the canelle template use pu_ht and not subprice
2484  $line->price = 100;
2485  $line->tva_tx = 19.6;
2486  $line->localtax1_tx = 0;
2487  $line->localtax2_tx = 0;
2488  if ($xnbp == 2)
2489  {
2490  $line->total_ht = 50;
2491  $line->total_ttc = 59.8;
2492  $line->total_tva = 9.8;
2493  $line->remise_percent = 50;
2494  } else {
2495  $line->total_ht = 100;
2496  $line->total_ttc = 119.6;
2497  $line->total_tva = 19.6;
2498  $line->remise_percent = 0;
2499  }
2500 
2501  if ($num_prods > 0)
2502  {
2503  $prodid = mt_rand(1, $num_prods);
2504  $line->fk_product = $prodids[$prodid];
2505  }
2506  $line->product_type = 0;
2507 
2508  $this->lines[$xnbp] = $line;
2509 
2510  $this->total_ht += $line->total_ht;
2511  $this->total_tva += $line->total_tva;
2512  $this->total_ttc += $line->total_ttc;
2513 
2514  $xnbp++;
2515  }
2516  }
2517 
2518  $this->amount_ht = $xnbp * 100;
2519  $this->total_ht = $xnbp * 100;
2520  $this->total_tva = $xnbp * 19.6;
2521  $this->total_ttc = $xnbp * 119.6;
2522  }
2523 
2524  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2530  public function load_state_board()
2531  {
2532  // phpcs:enable
2533  global $conf, $user;
2534 
2535  $this->nb = array();
2536 
2537  $clause = "WHERE";
2538 
2539  $sql = "SELECT count(f.rowid) as nb";
2540  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2541  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
2542  if (!$user->rights->societe->client->voir && !$user->socid)
2543  {
2544  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
2545  $sql .= " WHERE sc.fk_user = ".$user->id;
2546  $clause = "AND";
2547  }
2548  $sql .= " ".$clause." f.entity = ".$conf->entity;
2549 
2550  $resql = $this->db->query($sql);
2551  if ($resql)
2552  {
2553  while ($obj = $this->db->fetch_object($resql))
2554  {
2555  $this->nb["supplier_invoices"] = $obj->nb;
2556  }
2557  $this->db->free($resql);
2558  return 1;
2559  } else {
2560  dol_print_error($this->db);
2561  $this->error = $this->db->error();
2562  return -1;
2563  }
2564  }
2565 
2574  public function createFromClone(User $user, $fromid, $invertdetail = 0)
2575  {
2576  global $langs;
2577 
2578  $error = 0;
2579 
2580  $object = new FactureFournisseur($this->db);
2581 
2582  $this->db->begin();
2583 
2584  // Load source object
2585  $object->fetch($fromid);
2586  $object->id = 0;
2587  $object->statut = self::STATUS_DRAFT;
2588 
2589  $object->fetch_thirdparty(); // We need it to recalculate VAT localtaxes according to main sale taxes and vendor
2590 
2591  // Clear fields
2592  $object->ref_supplier = (empty($this->ref_supplier) ? $langs->trans("CopyOf").' '.$object->ref_supplier : $this->ref_supplier);
2593  $object->author = $user->id;
2594  $object->user_valid = '';
2595  $object->fk_facture_source = 0;
2596  $object->date_creation = '';
2597  $object->date_validation = '';
2598  $object->date = (empty($this->date) ? '' : $this->date);
2599  $object->date_echeance = '';
2600  $object->ref_client = '';
2601  $object->close_code = '';
2602  $object->close_note = '';
2603 
2604  // Loop on each line of new invoice
2605  foreach ($object->lines as $i => $line)
2606  {
2607  if (isset($object->lines[$i]->info_bits) && ($object->lines[$i]->info_bits & 0x02) == 0x02) // We do not clone line of discounts
2608  {
2609  unset($object->lines[$i]);
2610  }
2611  }
2612 
2613  // Create clone
2614  $object->context['createfromclone'] = 'createfromclone';
2615  $result = $object->create($user);
2616 
2617  // Other options
2618  if ($result < 0)
2619  {
2620  $this->error = $object->error;
2621  $this->errors = $object->errors;
2622  $error++;
2623  }
2624 
2625  if (!$error)
2626  {
2627  }
2628 
2629  unset($object->context['createfromclone']);
2630 
2631  // End
2632  if (!$error)
2633  {
2634  $this->db->commit();
2635  return $object->id;
2636  } else {
2637  $this->db->rollback();
2638  return -1;
2639  }
2640  }
2641 
2653  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
2654  {
2655  global $conf, $user, $langs;
2656 
2657  $langs->load("suppliers");
2658  $outputlangs->load("products");
2659 
2660  // Set the model on the model name to use
2661  if (empty($modele))
2662  {
2663  if (!empty($conf->global->INVOICE_SUPPLIER_ADDON_PDF))
2664  {
2665  $modele = $conf->global->INVOICE_SUPPLIER_ADDON_PDF;
2666  } else {
2667  $modele = ''; // No default value. For supplier invoice, we allow to disable all PDF generation
2668  }
2669  }
2670 
2671  if (empty($modele))
2672  {
2673  return 0;
2674  } else {
2675  $modelpath = "core/modules/supplier_invoice/doc/";
2676 
2677  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2678  }
2679  }
2680 
2685  public function getRights()
2686  {
2687  global $user;
2688 
2689  return $user->rights->fournisseur->facture;
2690  }
2691 
2700  public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
2701  {
2702  $tables = array(
2703  'facture_fourn'
2704  );
2705 
2706  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
2707  }
2708 
2714  public function hasDelay()
2715  {
2716  global $conf;
2717 
2718  $now = dol_now();
2719 
2720  if (!$this->date_echeance) {
2721  return false;
2722  }
2723 
2724  return ($this->statut == self::STATUS_VALIDATED) && ($this->date_echeance < ($now - $conf->facture->fournisseur->warning_delay));
2725  }
2726 
2732  public function isCreditNoteUsed()
2733  {
2734  $isUsed = false;
2735 
2736  $sql = "SELECT fk_invoice_supplier FROM ".MAIN_DB_PREFIX."societe_remise_except WHERE fk_invoice_supplier_source=".$this->id;
2737  $resql = $this->db->query($sql);
2738  if (!empty($resql)) {
2739  $obj = $this->db->fetch_object($resql);
2740  if (!empty($obj->fk_invoice_supplier)) $isUsed = true;
2741  }
2742 
2743  return $isUsed;
2744  }
2745 }
2746 
2747 
2748 
2753 {
2757  public $element = 'facture_fourn_det';
2758 
2762  public $table_element = 'facture_fourn_det';
2763 
2764  public $oldline;
2765 
2770  public $ref;
2771 
2776  public $product_ref;
2777 
2783  public $ref_supplier;
2784 
2789  public $product_desc;
2790 
2797  public $pu_ht;
2798 
2803  public $subprice;
2804 
2809  public $pu_ttc;
2810 
2811 
2816  public $fk_facture_fourn;
2817 
2823  public $label;
2824 
2829  public $description;
2830 
2831  public $date_start;
2832  public $date_end;
2833 
2834  public $skip_update_total; // Skip update price total for special lines
2835 
2839  public $situation_percent;
2840 
2844  public $fk_prev_id;
2845 
2850  public $vat_src_code;
2851 
2856  public $tva_tx;
2857 
2862  public $localtax1_tx;
2863 
2868  public $localtax2_tx;
2869 
2874  public $qty;
2875 
2880  public $remise_percent;
2881 
2886  public $total_ht;
2887 
2892  public $total_ttc;
2893 
2898  public $total_tva;
2899 
2904  public $total_localtax1;
2905 
2910  public $total_localtax2;
2911 
2915  public $fk_product;
2916 
2921  public $product_type;
2922 
2927  public $product_label;
2928 
2935  public $info_bits;
2936 
2940  public $fk_parent_line;
2941 
2942  public $special_code;
2943 
2947  public $rang;
2948 
2953  public $localtax1_type;
2954 
2959  public $localtax2_type;
2960 
2961  // Multicurrency
2965  public $fk_multicurrency;
2966 
2967  public $multicurrency_code;
2968  public $multicurrency_subprice;
2969  public $multicurrency_total_ht;
2970  public $multicurrency_total_tva;
2971  public $multicurrency_total_ttc;
2972 
2973 
2979  public function __construct($db)
2980  {
2981  $this->db = $db;
2982  }
2983 
2990  public function fetch($rowid)
2991  {
2992  $sql = 'SELECT f.rowid, f.ref as ref_supplier, f.description, f.date_start, f.date_end, f.pu_ht, f.pu_ttc, f.qty, f.remise_percent, f.tva_tx';
2993  $sql .= ', f.localtax1_type, f.localtax2_type, f.localtax1_tx, f.localtax2_tx, f.total_localtax1, f.total_localtax2 ';
2994  $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';
2995  $sql .= ', p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.description as product_desc';
2996  $sql .= ', f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, multicurrency_total_ttc';
2997  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
2998  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
2999  $sql .= ' WHERE f.rowid = '.$rowid;
3000  $sql .= ' ORDER BY f.rang, f.rowid';
3001 
3002  $query = $this->db->query($sql);
3003 
3004  if (!$query) {
3005  $this->errors[] = $this->db->error();
3006  return -1;
3007  }
3008 
3009  if (!$this->db->num_rows($query)) {
3010  return 0;
3011  }
3012 
3013  $obj = $this->db->fetch_object($query);
3014 
3015  $this->id = $obj->rowid;
3016  $this->rowid = $obj->rowid;
3017  $this->fk_facture_fourn = $obj->fk_facture_fourn;
3018  $this->description = $obj->description;
3019  $this->date_start = $obj->date_start;
3020  $this->date_end = $obj->date_end;
3021  $this->product_ref = $obj->product_ref;
3022  $this->ref_supplier = $obj->ref_supplier;
3023  $this->product_desc = $obj->product_desc;
3024 
3025  $this->subprice = $obj->pu_ht;
3026  $this->pu_ht = $obj->pu_ht;
3027  $this->pu_ttc = $obj->pu_ttc;
3028  $this->tva_tx = $obj->tva_tx;
3029  $this->localtax1_tx = $obj->localtax1_tx;
3030  $this->localtax2_tx = $obj->localtax2_tx;
3031  $this->localtax1_type = $obj->localtax1_type;
3032  $this->localtax2_type = $obj->localtax2_type;
3033 
3034  $this->qty = $obj->qty;
3035  $this->remise_percent = $obj->remise_percent;
3036  $this->tva = $obj->total_tva; // deprecated
3037  $this->total_ht = $obj->total_ht;
3038  $this->total_tva = $obj->total_tva;
3039  $this->total_localtax1 = $obj->total_localtax1;
3040  $this->total_localtax2 = $obj->total_localtax2;
3041  $this->total_ttc = $obj->total_ttc;
3042  $this->fk_product = $obj->fk_product;
3043  $this->product_type = $obj->product_type;
3044  $this->product_label = $obj->product_label;
3045  $this->info_bits = $obj->info_bits;
3046  $this->tva_npr = ($obj->info_bits & 1 == 1) ? 1 : 0;
3047  $this->fk_parent_line = $obj->fk_parent_line;
3048  $this->special_code = $obj->special_code;
3049  $this->rang = $obj->rang;
3050  $this->fk_unit = $obj->fk_unit;
3051 
3052  $this->multicurrency_subprice = $obj->multicurrency_subprice;
3053  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
3054  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
3055  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
3056 
3057  $this->fetch_optionals();
3058 
3059  return 1;
3060  }
3061 
3068  public function delete($notrigger = 0)
3069  {
3070  global $user, $conf;
3071 
3072  dol_syslog(get_class($this)."::deleteline rowid=".$this->id, LOG_DEBUG);
3073 
3074  $error = 0;
3075 
3076  $this->db->begin();
3077 
3078  if (!$notrigger) {
3079  if ($this->call_trigger('LINEBILL_SUPPLIER_DELETE', $user) < 0) {
3080  $error++;
3081  }
3082  }
3083 
3084  $this->deleteObjectLinked();
3085 
3086  // Remove extrafields
3087  if (!$error)
3088  {
3089  $result = $this->deleteExtraFields();
3090  if ($result < 0)
3091  {
3092  $error++;
3093  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
3094  }
3095  }
3096 
3097  if (!$error) {
3098  // Supprime ligne
3099  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det ';
3100  $sql .= ' WHERE rowid = '.$this->id;
3101  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
3102  $resql = $this->db->query($sql);
3103  if (!$resql) {
3104  $error++;
3105  $this->error = $this->db->lasterror();
3106  }
3107  }
3108 
3109  if (!$error)
3110  {
3111  $this->db->commit();
3112  return 1;
3113  } else {
3114  $this->db->rollback();
3115  return -1;
3116  }
3117  }
3118 
3125  public function update($notrigger = 0)
3126  {
3127  global $conf;
3128 
3129  $pu = price2num($this->pu_ht);
3130  $qty = price2num($this->qty);
3131 
3132  // Check parameters
3133  if (empty($this->qty)) $this->qty = 0;
3134 
3135  if ($this->product_type < 0) {
3136  return -1;
3137  }
3138 
3139  // Clean parameters
3140  if (empty($this->remise_percent)) $this->remise_percent = 0;
3141  if (empty($this->tva_tx)) $this->tva_tx = 0;
3142  if (empty($this->localtax1_tx)) $this->localtax1_tx = 0;
3143  if (empty($this->localtax2_tx)) $this->localtax2_tx = 0;
3144 
3145  $this->db->begin();
3146 
3147  if (empty($this->fk_product))
3148  {
3149  $fk_product = "null";
3150  } else {
3151  $fk_product = $this->fk_product;
3152  }
3153 
3154  if (empty($this->fk_unit)) {
3155  $fk_unit = "null";
3156  } else {
3157  $fk_unit = "'".$this->db->escape($this->fk_unit)."'";
3158  }
3159 
3160  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
3161  $sql .= " description ='".$this->db->escape($this->description)."'";
3162  $sql .= ", ref ='".$this->db->escape($this->ref_supplier ? $this->ref_supplier : $this->ref)."'";
3163  $sql .= ", date_start = ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : "null");
3164  $sql .= ", date_end = ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : "null");
3165  $sql .= ", pu_ht = ".price2num($this->pu_ht);
3166  $sql .= ", pu_ttc = ".price2num($this->pu_ttc);
3167  $sql .= ", qty = ".price2num($this->qty);
3168  $sql .= ", remise_percent = ".price2num($this->remise_percent);
3169  $sql .= ", vat_src_code = '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."'";
3170  $sql .= ", tva_tx = ".price2num($this->tva_tx);
3171  $sql .= ", localtax1_tx = ".price2num($this->localtax1_tx);
3172  $sql .= ", localtax2_tx = ".price2num($this->localtax2_tx);
3173  $sql .= ", localtax1_type = '".$this->db->escape($this->localtax1_type)."'";
3174  $sql .= ", localtax2_type = '".$this->db->escape($this->localtax2_type)."'";
3175  $sql .= ", total_ht = ".price2num($this->total_ht);
3176  $sql .= ", tva= ".price2num($this->total_tva);
3177  $sql .= ", total_localtax1= ".price2num($this->total_localtax1);
3178  $sql .= ", total_localtax2= ".price2num($this->total_localtax2);
3179  $sql .= ", total_ttc = ".price2num($this->total_ttc);
3180  $sql .= ", fk_product = ".$fk_product;
3181  $sql .= ", product_type = ".$this->product_type;
3182  $sql .= ", info_bits = ".$this->info_bits;
3183  $sql .= ", fk_unit = ".$fk_unit;
3184 
3185  // Multicurrency
3186  $sql .= " , multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
3187  $sql .= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
3188  $sql .= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
3189  $sql .= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
3190 
3191  $sql .= " WHERE rowid = ".$this->id;
3192 
3193  dol_syslog(get_class($this)."::update", LOG_DEBUG);
3194  $resql = $this->db->query($sql);
3195 
3196  if (!$resql) {
3197  $this->db->rollback();
3198  $this->error = $this->db->lasterror();
3199  return -1;
3200  }
3201 
3202  $this->rowid = $this->id;
3203  $error = 0;
3204 
3205  if (!$error)
3206  {
3207  $result = $this->insertExtraFields();
3208  if ($result < 0)
3209  {
3210  $error++;
3211  }
3212  }
3213 
3214  if (!$error && !$notrigger)
3215  {
3216  global $langs, $user;
3217 
3218  // Call trigger
3219  if ($this->call_trigger('LINEBILL_SUPPLIER_UPDATE', $user) < 0) {
3220  $this->db->rollback();
3221  return -1;
3222  }
3223  // End call triggers
3224  }
3225 
3226  if ($error) {
3227  $this->db->rollback();
3228  return -1;
3229  }
3230 
3231  $this->db->commit();
3232  return 1;
3233  }
3234 
3241  public function insert($notrigger = 0)
3242  {
3243  global $user, $conf;
3244 
3245  $error = 0;
3246 
3247  dol_syslog(get_class($this)."::insert rang=".$this->rang, LOG_DEBUG);
3248 
3249  // Clean parameters
3250  $this->desc = trim($this->desc);
3251  if (empty($this->tva_tx)) $this->tva_tx = 0;
3252  if (empty($this->localtax1_tx)) $this->localtax1_tx = 0;
3253  if (empty($this->localtax2_tx)) $this->localtax2_tx = 0;
3254  if (empty($this->localtax1_type)) $this->localtax1_type = '0';
3255  if (empty($this->localtax2_type)) $this->localtax2_type = '0';
3256  if (empty($this->total_tva)) $this->total_tva = 0;
3257  if (empty($this->total_localtax1)) $this->total_localtax1 = 0;
3258  if (empty($this->total_localtax2)) $this->total_localtax2 = 0;
3259  if (empty($this->rang)) $this->rang = 0;
3260  if (empty($this->remise_percent)) $this->remise_percent = 0;
3261  if (empty($this->info_bits)) $this->info_bits = 0;
3262  if (empty($this->subprice)) $this->subprice = 0;
3263  if (empty($this->special_code)) $this->special_code = 0;
3264  if (empty($this->fk_parent_line)) $this->fk_parent_line = 0;
3265  if (!isset($this->situation_percent) || $this->situation_percent > 100 || (string) $this->situation_percent == '') $this->situation_percent = 100;
3266 
3267  if (empty($this->pa_ht)) $this->pa_ht = 0;
3268  if (empty($this->multicurrency_subprice)) $this->multicurrency_subprice = 0;
3269  if (empty($this->multicurrency_total_ht)) $this->multicurrency_total_ht = 0;
3270  if (empty($this->multicurrency_total_tva)) $this->multicurrency_total_tva = 0;
3271  if (empty($this->multicurrency_total_ttc)) $this->multicurrency_total_ttc = 0;
3272 
3273 
3274  // Check parameters
3275  if ($this->product_type < 0)
3276  {
3277  $this->error = 'ErrorProductTypeMustBe0orMore';
3278  return -1;
3279  }
3280  if (!empty($this->fk_product))
3281  {
3282  // Check product exists
3283  $result = Product::isExistingObject('product', $this->fk_product);
3284  if ($result <= 0)
3285  {
3286  $this->error = 'ErrorProductIdDoesNotExists';
3287  return -1;
3288  }
3289  }
3290 
3291  $this->db->begin();
3292 
3293  // Insertion dans base de la ligne
3294  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
3295  $sql .= ' (fk_facture_fourn, fk_parent_line, label, description, ref, qty,';
3296  $sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3297  $sql .= ' fk_product, product_type, remise_percent, pu_ht, pu_ttc,';
3298  $sql .= ' date_start, date_end, fk_code_ventilation, rang, special_code,';
3299  $sql .= ' info_bits, total_ht, tva, total_ttc, total_localtax1, total_localtax2, fk_unit';
3300  $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
3301  $sql .= ')';
3302  $sql .= " VALUES (".$this->fk_facture_fourn.",";
3303  $sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape($this->fk_parent_line)."'" : "null").",";
3304  $sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
3305  $sql .= " '".$this->db->escape($this->desc ? $this->desc : $this->description)."',";
3306  $sql .= " '".$this->db->escape($this->ref_supplier)."',";
3307  $sql .= " ".price2num($this->qty).",";
3308 
3309  $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape($this->vat_src_code)."'").",";
3310  $sql .= " ".price2num($this->tva_tx).",";
3311  $sql .= " ".price2num($this->localtax1_tx).",";
3312  $sql .= " ".price2num($this->localtax2_tx).",";
3313  $sql .= " '".$this->db->escape($this->localtax1_type)."',";
3314  $sql .= " '".$this->db->escape($this->localtax2_type)."',";
3315  $sql .= ' '.(!empty($this->fk_product) ? $this->fk_product : "null").',';
3316  $sql .= " ".$this->product_type.",";
3317  $sql .= " ".price2num($this->remise_percent).",";
3318  $sql .= " ".price2num($this->subprice).",";
3319  $sql .= " ".(!empty($this->qty) ?price2num($this->total_ttc / $this->qty) : price2num($this->total_ttc)).",";
3320  $sql .= " ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null").",";
3321  $sql .= " ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").",";
3322  $sql .= ' '.(!empty($this->fk_code_ventilation) ? $this->fk_code_ventilation : 0).',';
3323  $sql .= ' '.$this->rang.',';
3324  $sql .= ' '.$this->special_code.',';
3325  $sql .= " '".$this->db->escape($this->info_bits)."',";
3326  $sql .= " ".price2num($this->total_ht).",";
3327  $sql .= " ".price2num($this->total_tva).",";
3328  $sql .= " ".price2num($this->total_ttc).",";
3329  $sql .= " ".price2num($this->total_localtax1).",";
3330  $sql .= " ".price2num($this->total_localtax2);
3331  $sql .= ", ".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
3332  $sql .= ", ".(int) $this->fk_multicurrency;
3333  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
3334  $sql .= ", ".price2num($this->multicurrency_subprice);
3335  $sql .= ", ".price2num($this->multicurrency_total_ht);
3336  $sql .= ", ".price2num($this->multicurrency_total_tva);
3337  $sql .= ", ".price2num($this->multicurrency_total_ttc);
3338  $sql .= ')';
3339 
3340  $resql = $this->db->query($sql);
3341  if ($resql)
3342  {
3343  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
3344  $this->rowid = $this->id; // backward compatibility
3345 
3346  if (!$error)
3347  {
3348  $result = $this->insertExtraFields();
3349  if ($result < 0)
3350  {
3351  $error++;
3352  }
3353  }
3354 
3355  if (!$error && !$notrigger)
3356  {
3357  // Call trigger
3358  $result = $this->call_trigger('LINEBILL_SUPPLIER_CREATE', $user);
3359  if ($result < 0)
3360  {
3361  $this->db->rollback();
3362  return -2;
3363  }
3364  // End call triggers
3365  }
3366 
3367  $this->db->commit();
3368  return $this->id;
3369  } else {
3370  $this->error = $this->db->error();
3371  $this->db->rollback();
3372  return -2;
3373  }
3374  }
3375 
3376  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3382  public function update_total()
3383  {
3384  // phpcs:enable
3385  $this->db->begin();
3386 
3387  // Mise a jour ligne en base
3388  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
3389  $sql .= " total_ht='".price2num($this->total_ht)."'";
3390  $sql .= ", tva='".price2num($this->total_tva)."'";
3391  $sql .= ", total_localtax1='".price2num($this->total_localtax1)."'";
3392  $sql .= ", total_localtax2='".price2num($this->total_localtax2)."'";
3393  $sql .= ", total_ttc='".price2num($this->total_ttc)."'";
3394  $sql .= " WHERE rowid = ".$this->rowid;
3395 
3396  dol_syslog("FactureFournisseurLigne.class.php::update_total", LOG_DEBUG);
3397 
3398  $resql = $this->db->query($sql);
3399  if ($resql)
3400  {
3401  $this->db->commit();
3402  return 1;
3403  } else {
3404  $this->error = $this->db->error();
3405  $this->db->rollback();
3406  return -2;
3407  }
3408  }
3409 }
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= '', $special_code= '', $fk_parent_line=0)
Adds an invoice line (associated with no predefined product/service) The parameters are already suppo...
static replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
setDraft($user, $idwarehouse=-1)
Set draft status.
const TYPE_STANDARD
Standard invoice.
Class to manage stock movements.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto= 'UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
update($user=null, $notrigger=0)
Update database.
insert($notrigger=0)
Insert line into database.
static isExistingObject($element, $id, $ref= '', $ref_ext= '')
Check an object id/ref exists If you don&#39;t need/want to instantiate object and just need to know if o...
info($id)
Loads the info order information into the invoice object.
if(!empty($arrayfields['u.datec']['checked'])) print_liste_field_titre("DateCreationShort"u if(!empty($arrayfields['u.tms']['checked'])) print_liste_field_titre("DateModificationShort"u if(!empty($arrayfields['u.statut']['checked'])) print_liste_field_titre("Status"u statut
Definition: list.php:632
const TYPE_DEPOSIT
Deposit invoice.
static getIdAndTxFromCode($db, $code, $date_document= '')
Get id and rate of currency from code.
validate($user, $force_number= '', $idwarehouse=0, $notrigger=0)
Tag invoice as validated + call trigger BILL_VALIDATE.
</td > param sortfield sortorder printFieldListOption< tdclass="liste_titremaxwidthsearchright"></td ></tr >< trclass="liste_titre">< inputtype="checkbox"onClick="toggle(this)"/> Ref p ref Label p label Duration p duration center DesiredStock p desiredstock right StockLimitShort p seuil_stock_alerte right stock_physique right stock_real_warehouse right Ordered right StockToBuy right SupplierRef right param sortfield sortorder printFieldListTitle warehouseinternal SELECT description FROM product_lang WHERE qty< br > qty qty qty StockTooLow StockTooLow help help help< trclass="oddeven">< td >< inputtype="checkbox"class="check"name="choose'.$i.'"></td >< tdclass="nowrap"> stock</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:750
list_replacable_supplier_invoices($socid=0)
Return list of replaceable invoices Status valid or abandoned for other reason + not paid + no paymen...
set_paid($user, $close_code= '', $close_note= '')
Tag invoice as a paid invoice.
Class to manage line invoices.
createFromClone(User $user, $fromid, $invertdetail=0)
Load an object from its id and create a new one in database.
</td >< tdcolspan="3">< spanclass="opacitymedium"></span ></td ></tr >< trclass="liste_total"> CREANCES DETTES< tdcolspan="3"class="right"></td >< tdcolspan="3"class="right"></td ></tr > CREANCES DETTES RECETTES DEPENSES trips CREANCES DETTES Y m expensereport p date_valid Y m expensereport pe datep $db idate($date_start)."' AND $column < p rowid
Class to manage products or services.
dol_now($mode= 'auto')
Return date for now.
line_order($renum=false, $rowidorder= 'ASC', $fk_parent_line=true)
Save a new position (field rang) for details lines.
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller= '', $localtaxes_array= '', $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code= '')
Calculate totals (net, vat, ...) of a line.
Definition: price.lib.php:86
Class to manage Dolibarr users.
Definition: user.class.php:44
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.
getLibStatut($mode=0, $alreadypaid=-1)
Return label of object status.
load_board($user)
Load indicators for dashboard (this-&gt;nbtodo and this-&gt;nbtodolate)
const STATUS_VALIDATED
Validated (need to be paid)
Class to manage suppliers invoices.
load_state_board()
Load indicators for dashboard (this-&gt;nbtodo and this-&gt;nbtodolate)
fetch_thirdparty($force_thirdparty_id=0)
Load the third party of object, from id $this-&gt;socid or $this-&gt;fk_soc, into this-&gt;thirdparty.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
$conf db
API class for accounts.
Definition: inc.php:54
update_total()
Mise a jour de l&#39;objet ligne de commande en base.
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...
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
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, $ref_supplier= '')
Update a line detail into database.
insertExtraFields($trigger= '', $userused=null)
Add/Update all extra fields values for the current object.
set_unpaid($user)
Tag the invoice as not fully paid + trigger call BILL_UNPAYED Function used when a direct debit payme...
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
dol_strlen($string, $stringencoding= 'UTF-8')
Make a strlen call.
price2num($amount, $rounding= '', $option=0)
Function that return a number with universal decimal format (decimal separator is &#39;...
Classe permettant la generation de composants html autre Only common components are here...
initAsSpecimen($option= '')
Initialise an instance with random values.
deleteEcmFiles($mode=0)
Delete related files of object in database.
static commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
static getIdFromCode($db, $code)
Get id of currency from code.
img_picto($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt= '', $morecss= '', $marginleftonlyshort=2)
Show picto whatever it&#39;s its name (generic function)
list_qualified_avoir_supplier_invoices($socid=0)
Return list of qualifying invoices for correction by credit note Invoices that respect the following ...
getRights()
Returns the rights used for this class.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart= '')
Return a path to have a the directory according to object where files are stored. ...
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:1286
isCreditNoteUsed()
Is credit note used.
fetch($rowid)
Retrieves a supplier invoice line.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1)
Remove a file or several files with a mask.
Definition: files.lib.php:1144
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.
insert_discount($idremise)
Add a discount line into an invoice (as an invoice line) using an existing absolute discount (Consume...
dol_sanitizeFileName($str, $newstr= '_', $unaccent=1)
Clean a string to use it as a file name.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:60
update($notrigger=0)
Update a supplier invoice line.
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this-&gt;array_options This method is in most cases call...
deleteObjectLinked($sourceid=null, $sourcetype= '', $targetid=null, $targettype= '', $rowid= '')
Delete all links between an object $this.
deleteline($rowid, $notrigger=0)
Delete a detail line from database.
Superclass for invoices classes.
print $_SERVER["PHP_SELF"]
Edit parameters.
const STATUS_CLOSED
Classified paid.
const TYPE_CREDIT_NOTE
Credit note invoice.
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
call_trigger($triggerName, $user)
Call trigger based on this instance.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->don->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)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1232
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Class to manage absolute discounts.
hasDelay()
Is the payment of the supplier invoice having a delay?
getNomUrl($withpicto=0, $option= '', $max=0, $short=0, $moretitle= '', $notooltip=0, $save_lastsearch_value=-1, $addlinktonotes=0)
Return clicable name (with picto eventually)
const STATUS_ABANDONED
Classified abandoned and no payment done.
dol_trunc($string, $size=40, $trunc= 'right', $stringencoding= 'UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding &#39;...&#39; if string larger than length.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template model.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
getNextNumRef($soc, $mode= 'next')
Return next reference of supplier invoice not already used (or last reference) according to numbering...
add_object_linked($origin=null, $origin_id=null)
Add objects linked in llx_element_element.
create($user)
Create supplier invoice into database.
fetch($id= '', $ref= '')
Load object in memory from database.
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)...
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:105
fetch_lines()
Load this-&gt;lines.
if(!empty($search_group)) natural_search(array("g.nom"g note
Definition: list.php:122
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $keepmoretags= '', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields...