dolibarr  18.0.0
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-2022 Ferran Marcet <fmarcet@2byte.es>
13  * Copyright (C) 2016-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
14  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
15  * Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.fr>
16  * Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
17  *
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program. If not, see <https://www.gnu.org/licenses/>.
30  */
31 
38 include_once DOL_DOCUMENT_ROOT.'/core/class/commoninvoice.class.php';
39 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
40 require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
41 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
42 
43 if (isModEnabled('accounting')) {
44  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
45  require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
46 }
47 
52 {
56  public $element = 'invoice_supplier';
57 
61  public $table_element = 'facture_fourn';
62 
66  public $table_element_line = 'facture_fourn_det';
67 
71  public $fk_element = 'fk_facture_fourn';
72 
76  public $picto = 'supplier_invoice';
77 
82  public $ismultientitymanaged = 1;
83 
88  public $restrictiononfksoc = 1;
89 
93  protected $table_ref_field = 'ref';
94 
98  public $rowid;
99 
103  public $ref;
104 
108  public $ref_supplier;
109 
113  public $label;
114 
115  public $socid;
116 
117  //Check constants for types
118  public $type = self::TYPE_STANDARD;
119 
125  public $statut;
126 
132  public $status;
133 
139  public $close_code;
140 
145  public $close_note;
146 
151  public $paye;
152 
153  public $author;
154 
160  public $datec;
161 
167  public $tms;
168 
174  public $date;
175 
181  public $date_echeance;
182 
187  public $amount = 0;
192  public $remise = 0;
193 
198  public $tva;
199 
200  // Warning: Do not set default value into property defintion. it must stay null.
201  // For example to avoid to have substition done when object is generic and not yet defined.
202  public $localtax1;
203  public $localtax2;
204  public $total_ht;
205  public $total_tva;
206  public $total_localtax1;
207  public $total_localtax2;
208  public $total_ttc;
209 
214  public $note;
215 
216  public $note_private;
217  public $note_public;
218  public $propalid;
219 
220  public $cond_reglement_id;
221  public $cond_reglement_code;
222  public $cond_reglement_label;
223  public $cond_reglement_doc;
224 
228  public $fk_account; // default bank account
229 
230  public $mode_reglement_id;
231  public $mode_reglement_code;
232 
236  public $transport_mode_id;
237 
241  public $vat_reverse_charge;
242 
243  public $extraparams = array();
244 
249  public $lines = array();
250 
254  public $fournisseur;
255 
256  // Multicurrency
260  public $fk_multicurrency;
261 
262  public $multicurrency_code;
263  public $multicurrency_tx;
264  public $multicurrency_total_ht;
265  public $multicurrency_total_tva;
266  public $multicurrency_total_ttc;
268 
271  public $fk_facture_source;
272 
273  public $fac_rec;
274 
275 
276  public $fields = array(
277  'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
278  'ref' =>array('type'=>'varchar(255)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>15),
279  'ref_supplier' =>array('type'=>'varchar(255)', 'label'=>'RefSupplier', 'enabled'=>1, 'visible'=>-1, 'position'=>20),
280  'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>25, 'index'=>1),
281  'ref_ext' =>array('type'=>'varchar(255)', 'label'=>'RefExt', 'enabled'=>1, 'visible'=>0, 'position'=>30),
282  'type' =>array('type'=>'smallint(6)', 'label'=>'Type', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35),
283  'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>'isModEnabled("societe")', 'visible'=>-1, 'notnull'=>1, 'position'=>40),
284  'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
285  'datef' =>array('type'=>'date', 'label'=>'Date', 'enabled'=>1, 'visible'=>-1, 'position'=>50),
286  'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>55),
287  'libelle' =>array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>1, 'visible'=>-1, 'position'=>60),
288  'paye' =>array('type'=>'smallint(6)', 'label'=>'Paye', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>65),
289  'amount' =>array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>70),
290  'remise' =>array('type'=>'double(24,8)', 'label'=>'Discount', 'enabled'=>1, 'visible'=>-1, 'position'=>75),
291  'close_code' =>array('type'=>'varchar(16)', 'label'=>'CloseCode', 'enabled'=>1, 'visible'=>-1, 'position'=>80),
292  'close_note' =>array('type'=>'varchar(128)', 'label'=>'CloseNote', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
293  'tva' =>array('type'=>'double(24,8)', 'label'=>'Tva', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
294  'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>-1, 'position'=>95),
295  'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>-1, 'position'=>100),
296  'total_ht' =>array('type'=>'double(24,8)', 'label'=>'TotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
297  'total_tva' =>array('type'=>'double(24,8)', 'label'=>'TotalVAT', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
298  'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'TotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
299  'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-1, 'position'=>125),
300  'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>130),
301  'fk_user_valid' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>135),
302  'fk_facture_source' =>array('type'=>'integer', 'label'=>'Fk facture source', 'enabled'=>1, 'visible'=>-1, 'position'=>140),
303  'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label'=>'Project', 'enabled'=>"isModEnabled('project')", 'visible'=>-1, 'position'=>145),
304  'fk_account' =>array('type'=>'integer', 'label'=>'Account', 'enabled'=>'isModEnabled("banque")', 'visible'=>-1, 'position'=>150),
305  'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'PaymentTerm', 'enabled'=>1, 'visible'=>-1, 'position'=>155),
306  'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'PaymentMode', 'enabled'=>1, 'visible'=>-1, 'position'=>160),
307  'date_lim_reglement' =>array('type'=>'date', 'label'=>'DateLimReglement', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
308  'note_private' =>array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>170),
309  'note_public' =>array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>175),
310  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'ModelPdf', 'enabled'=>1, 'visible'=>0, 'position'=>180),
311  'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>190),
312  'fk_incoterms' =>array('type'=>'integer', 'label'=>'IncotermCode', 'enabled'=>1, 'visible'=>-1, 'position'=>195),
313  'location_incoterms' =>array('type'=>'varchar(255)', 'label'=>'IncotermLocation', 'enabled'=>1, 'visible'=>-1, 'position'=>200),
314  'fk_multicurrency' =>array('type'=>'integer', 'label'=>'MulticurrencyId', 'enabled'=>1, 'visible'=>-1, 'position'=>205),
315  'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'MulticurrencyCode', 'enabled'=>1, 'visible'=>-1, 'position'=>210),
316  'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyRate', 'enabled'=>1, 'visible'=>-1, 'position'=>215),
317  'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyTotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>220),
318  'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyTotalVAT', 'enabled'=>1, 'visible'=>-1, 'position'=>225),
319  'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyTotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>230),
320  'date_pointoftax' =>array('type'=>'date', 'label'=>'Date pointoftax', 'enabled'=>1, 'visible'=>-1, 'position'=>235),
321  'date_valid' =>array('type'=>'date', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>240),
322  'last_main_doc' =>array('type'=>'varchar(255)', 'label'=>'Last main doc', 'enabled'=>1, 'visible'=>-1, 'position'=>245),
323  'fk_statut' =>array('type'=>'smallint(6)', 'label'=>'Status', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>500),
324  'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>900),
325  );
326 
327 
331  const TYPE_STANDARD = 0;
332 
336  const TYPE_REPLACEMENT = 1;
337 
341  const TYPE_CREDIT_NOTE = 2;
342 
346  const TYPE_DEPOSIT = 3;
347 
351  const STATUS_DRAFT = 0;
352 
356  const STATUS_VALIDATED = 1;
357 
365  const STATUS_CLOSED = 2;
366 
374  const STATUS_ABANDONED = 3;
375 
376  const CLOSECODE_DISCOUNTVAT = 'discount_vat';
377  const CLOSECODE_BADCREDIT = 'badsupplier';
378  const CLOSECODE_ABANDONED = 'abandon';
379  const CLOSECODE_REPLACED = 'replaced';
380 
386  public function __construct($db)
387  {
388  $this->db = $db;
389  }
390 
397  public function create($user)
398  {
399  global $langs, $conf, $hookmanager;
400 
401  $error = 0;
402  $now = dol_now();
403 
404  // Clean parameters
405  if (isset($this->ref_supplier)) {
406  $this->ref_supplier = trim($this->ref_supplier);
407  }
408  if (empty($this->type)) {
409  $this->type = self::TYPE_STANDARD;
410  }
411  if (empty($this->date)) {
412  $this->date = $now;
413  }
414 
415  // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
416  if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) {
417  list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $this->date);
418  } else {
419  $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
420  }
421  if (empty($this->fk_multicurrency)) {
422  $this->multicurrency_code = $conf->currency;
423  $this->fk_multicurrency = 0;
424  $this->multicurrency_tx = 1;
425  }
426 
427  $this->db->begin();
428 
429  // Create invoice from a template recurring invoice
430  if ($this->fac_rec > 0) {
431  $this->fk_fac_rec_source = $this->fac_rec;
432 
433  require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture-rec.class.php';
434  $_facrec = new FactureFournisseurRec($this->db);
435  $result = $_facrec->fetch($this->fac_rec);
436  $result = $_facrec->fetchObjectLinked(null, '', null, '', 'OR', 1, 'sourcetype', 0); // This load $_facrec->linkedObjectsIds
437 
438  // Define some dates
439  if (!empty($_facrec->frequency)) {
440  $originaldatewhen = $_facrec->date_when;
441  $nextdatewhen = dol_time_plus_duree($originaldatewhen, $_facrec->frequency, $_facrec->unit_frequency);
442  $previousdaynextdatewhen = dol_time_plus_duree($nextdatewhen, -1, 'd');
443  $this->socid = $_facrec->socid;
444  }
445 
446  $this->entity = $_facrec->entity; // Invoice created in same entity than template
447 
448  // Fields coming from GUI (priority on template). TODO Value of template should be used as default value on GUI so we can use here always value from GUI
449  $this->fk_project = GETPOST('projectid', 'int') > 0 ? ((int) GETPOST('projectid', 'int')) : $_facrec->fk_projet;
450  $this->fk_projet = $this->fk_project;
451  $this->note_public = GETPOST('note_public', 'restricthtml') ? GETPOST('note_public', 'restricthtml') : $_facrec->note_public;
452  $this->note_private = GETPOST('note_private', 'restricthtml') ? GETPOST('note_private', 'restricthtml') : $_facrec->note_private;
453  $this->model_pdf = GETPOST('model', 'alpha') ? GETPOST('model', 'alpha') : $_facrec->model_pdf;
454  $this->cond_reglement_id = GETPOST('cond_reglement_id', 'int') > 0 ? ((int) GETPOST('cond_reglement_id', 'int')) : $_facrec->cond_reglement_id;
455  $this->mode_reglement_id = GETPOST('mode_reglement_id', 'int') > 0 ? ((int) GETPOST('mode_reglement_id', 'int')) : $_facrec->mode_reglement_id;
456  $this->fk_account = GETPOST('fk_account') > 0 ? ((int) GETPOST('fk_account')) : $_facrec->fk_account;
457 
458  // Set here to have this defined for substitution into notes, should be recalculated after adding lines to get same result
459  $this->total_ht = $_facrec->total_ht;
460  $this->total_ttc = $_facrec->total_ttc;
461 
462  // Fields always coming from template
463  $this->fk_incoterms = $_facrec->fk_incoterms;
464  $this->location_incoterms = $_facrec->location_incoterms;
465 
466  // Clean parameters
467  if (! $this->type) {
468  $this->type = self::TYPE_STANDARD;
469  }
470  if (!empty(GETPOST('ref_supplier'))) {
471  $this->ref_supplier = trim($this->ref_supplier);
472  } else {
473  $this->ref_supplier = trim($this->ref_supplier . '_' . ($_facrec->nb_gen_done + 1));
474  }
475  $this->note_public = trim($this->note_public);
476  $this->note_private = trim($this->note_private);
477  $this->note_private = dol_concatdesc($this->note_private, $langs->trans("GeneratedFromRecurringInvoice", $_facrec->titre));
478 
479  $this->array_options = $_facrec->array_options;
480 
481  if (! $this->mode_reglement_id) {
482  $this->mode_reglement_id = 0;
483  }
484  $this->brouillon = 1;
485  $this->status = self::STATUS_DRAFT;
486  $this->statut = self::STATUS_DRAFT;
487 
488  $this->linked_objects = $_facrec->linkedObjectsIds;
489  // We do not add link to template invoice or next invoice will be linked to all generated invoices
490  //$this->linked_objects['facturerec'][0] = $this->fac_rec;
491 
492  $forceduedate = $this->calculate_date_lim_reglement();
493 
494  // For recurring invoices, update date and number of last generation of recurring template invoice, before inserting new invoice
495  if ($_facrec->frequency > 0) {
496  dol_syslog("This is a recurring invoice so we set date_last_gen and next date_when");
497  if (empty($_facrec->date_when)) {
498  $_facrec->date_when = $now;
499  }
500  $next_date = $_facrec->getNextDate(); // Calculate next date
501  $result = $_facrec->setValueFrom('date_last_gen', $now, '', null, 'date', '', $user, '');
502  //$_facrec->setValueFrom('nb_gen_done', $_facrec->nb_gen_done + 1); // Not required, +1 already included into setNextDate when second param is 1.
503  $result = $_facrec->setNextDate($next_date, 1);
504  }
505 
506  // Define lang of customer
507  $outputlangs = $langs;
508  $newlang = '';
509 
510  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->thirdparty->default_lang)) {
511  $newlang = $this->thirdparty->default_lang; // for proposal, order, invoice, ...
512  }
513  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->default_lang)) {
514  $newlang = $this->default_lang; // for thirdparty
515  }
516  if (!empty($newlang)) {
517  $outputlangs = new Translate("", $conf);
518  $outputlangs->setDefaultLang($newlang);
519  }
520 
521  // Array of possible substitutions (See also file mailing-send.php that should manage same substitutions)
522  $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $this);
523  $substitutionarray['__INVOICE_PREVIOUS_MONTH__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'm'), '%m');
524  $substitutionarray['__INVOICE_MONTH__'] = dol_print_date($this->date, '%m');
525  $substitutionarray['__INVOICE_NEXT_MONTH__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'm'), '%m');
526  $substitutionarray['__INVOICE_PREVIOUS_MONTH_TEXT__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'm'), '%B');
527  $substitutionarray['__INVOICE_MONTH_TEXT__'] = dol_print_date($this->date, '%B');
528  $substitutionarray['__INVOICE_NEXT_MONTH_TEXT__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'm'), '%B');
529  $substitutionarray['__INVOICE_PREVIOUS_YEAR__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'y'), '%Y');
530  $substitutionarray['__INVOICE_YEAR__'] = dol_print_date($this->date, '%Y');
531  $substitutionarray['__INVOICE_NEXT_YEAR__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'y'), '%Y');
532  // Only for template invoice
533  $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_BEFORE_GEN__'] = dol_print_date($originaldatewhen, 'dayhour');
534  $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_AFTER_GEN__'] = dol_print_date($nextdatewhen, 'dayhour');
535  $substitutionarray['__INVOICE_PREVIOUS_DATE_NEXT_INVOICE_AFTER_GEN__'] = dol_print_date($previousdaynextdatewhen, 'dayhour');
536  $substitutionarray['__INVOICE_COUNTER_CURRENT__'] = $_facrec->nb_gen_done;
537  $substitutionarray['__INVOICE_COUNTER_MAX__'] = $_facrec->nb_gen_max;
538 
539  complete_substitutions_array($substitutionarray, $outputlangs);
540 
541  $this->note_public = make_substitutions($this->note_public, $substitutionarray);
542  $this->note_private = make_substitutions($this->note_private, $substitutionarray);
543  }
544 
545  // Define due date if not already defined
546  if (!empty($forceduedate)) {
547  $this->date_echeance = $forceduedate;
548  }
549 
550  $sql = "INSERT INTO ".MAIN_DB_PREFIX."facture_fourn (";
551  $sql .= "ref";
552  $sql .= ", ref_supplier";
553  $sql .= ", ref_ext";
554  $sql .= ", entity";
555  $sql .= ", type";
556  $sql .= ", libelle";
557  $sql .= ", fk_soc";
558  $sql .= ", datec";
559  $sql .= ", datef";
560  $sql .= ", vat_reverse_charge";
561  $sql .= ", fk_projet";
562  $sql .= ", fk_cond_reglement";
563  $sql .= ", fk_mode_reglement";
564  $sql .= ", fk_account";
565  $sql .= ", note_private";
566  $sql .= ", note_public";
567  $sql .= ", fk_user_author";
568  $sql .= ", date_lim_reglement";
569  $sql .= ", fk_incoterms, location_incoterms";
570  $sql .= ", fk_multicurrency";
571  $sql .= ", multicurrency_code";
572  $sql .= ", multicurrency_tx";
573  $sql .= ", fk_facture_source";
574  $sql .= ", fk_fac_rec_source";
575  $sql .= ")";
576  $sql .= " VALUES (";
577  $sql .= "'(PROV)'";
578  $sql .= ", '".$this->db->escape($this->ref_supplier)."'";
579  $sql .= ", '".$this->db->escape($this->ref_ext)."'";
580  $sql .= ", ".((int) $conf->entity);
581  $sql .= ", '".$this->db->escape($this->type)."'";
582  $sql .= ", '".$this->db->escape(isset($this->label) ? $this->label : (isset($this->libelle) ? $this->libelle : ''))."'";
583  $sql .= ", ".((int) $this->socid);
584  $sql .= ", '".$this->db->idate($now)."'";
585  $sql .= ", '".$this->db->idate($this->date)."'";
586  $sql .= ", ".($this->vat_reverse_charge != '' ? ((int) $this->db->escape($this->vat_reverse_charge)) : 0);
587  $sql .= ", ".($this->fk_project > 0 ? ((int) $this->fk_project) : "null");
588  $sql .= ", ".($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : "null");
589  $sql .= ", ".($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : "null");
590  $sql .= ", ".($this->fk_account > 0 ? ((int) $this->fk_account) : 'NULL');
591  $sql .= ", '".$this->db->escape($this->note_private)."'";
592  $sql .= ", '".$this->db->escape($this->note_public)."'";
593  $sql .= ", ".((int) $user->id).",";
594  $sql .= $this->date_echeance != '' ? "'".$this->db->idate($this->date_echeance)."'" : "null";
595  $sql .= ", ".(int) $this->fk_incoterms;
596  $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
597  $sql .= ", ".(int) $this->fk_multicurrency;
598  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
599  $sql .= ", ".(double) $this->multicurrency_tx;
600  $sql .= ", ".($this->fk_facture_source ? ((int) $this->fk_facture_source) : "null");
601  $sql .= ", ".(isset($this->fk_fac_rec_source) ? $this->fk_fac_rec_source : "NULL");
602  $sql .= ")";
603 
604  dol_syslog(get_class($this)."::create", LOG_DEBUG);
605  $resql = $this->db->query($sql);
606  if ($resql) {
607  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn');
608 
609  // Update ref with new one
610  $this->ref = '(PROV'.$this->id.')';
611  $sql = 'UPDATE '.MAIN_DB_PREFIX."facture_fourn SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".((int) $this->id);
612 
613  dol_syslog(get_class($this)."::create", LOG_DEBUG);
614  $resql = $this->db->query($sql);
615  if (!$resql) {
616  $error++;
617  }
618 
619  if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) { // To use new linkedObjectsIds instead of old linked_objects
620  $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
621  }
622 
623  // Add object linked
624  if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) {
625  foreach ($this->linked_objects as $origin => $tmp_origin_id) {
626  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, ...))
627  foreach ($tmp_origin_id as $origin_id) {
628  $ret = $this->add_object_linked($origin, $origin_id);
629  if (!$ret) {
630  dol_print_error($this->db);
631  $error++;
632  }
633  }
634  } else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
635  {
636  $origin_id = $tmp_origin_id;
637  $ret = $this->add_object_linked($origin, $origin_id);
638  if (!$ret) {
639  dol_print_error($this->db);
640  $error++;
641  }
642  }
643  }
644  }
645 
646  if (!$error && empty($this->fac_rec) && count($this->lines) && is_object($this->lines[0])) { // If this->lines is array of InvoiceLines (preferred mode)
647  dol_syslog("There is ".count($this->lines)." lines that are invoice lines objects");
648  foreach ($this->lines as $i => $val) {
649  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn, special_code, fk_remise_except)';
650  $sql .= " VALUES (".((int) $this->id).", ".((int) $this->lines[$i]->special_code).", ".($this->lines[$i]->fk_remise_except > 0 ? ((int) $this->lines[$i]->fk_remise_except) : 'NULL').')';
651 
652  $resql_insert = $this->db->query($sql);
653  if ($resql_insert) {
654  $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det');
655 
656  $res = $this->updateline(
657  $idligne,
658  $this->lines[$i]->description,
659  $this->lines[$i]->subprice,
660  $this->lines[$i]->tva_tx.($this->lines[$i]->vat_src_code ? ' ('.$this->lines[$i]->vat_src_code.')' : ''),
661  $this->lines[$i]->localtax1_tx,
662  $this->lines[$i]->localtax2_tx,
663  $this->lines[$i]->qty,
664  $this->lines[$i]->fk_product,
665  'HT',
666  (!empty($this->lines[$i]->info_bits) ? $this->lines[$i]->info_bits : ''),
667  $this->lines[$i]->product_type,
668  $this->lines[$i]->remise_percent,
669  false,
670  $this->lines[$i]->date_start,
671  $this->lines[$i]->date_end,
672  $this->lines[$i]->array_options,
673  $this->lines[$i]->fk_unit,
674  $this->lines[$i]->multicurrency_subprice,
675  $this->lines[$i]->ref_supplier
676  );
677  } else {
678  $this->error = $this->db->lasterror();
679  $this->db->rollback();
680  return -5;
681  }
682  }
683  } elseif (!$error && empty($this->fac_rec)) { // If this->lines is an array of invoice line arrays
684  dol_syslog("There is ".count($this->lines)." lines that are array lines");
685  foreach ($this->lines as $i => $val) {
686  $line = $this->lines[$i];
687 
688  // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
689  //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
690  if (!is_object($line)) {
691  $line = (object) $line;
692  }
693 
694  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn, special_code, fk_remise_except)';
695  $sql .= " VALUES (".((int) $this->id).", ".((int) $this->lines[$i]->special_code).", ".($this->lines[$i]->fk_remise_except > 0 ? ((int) $this->lines[$i]->fk_remise_except) : 'NULL').')';
696 
697  $resql_insert = $this->db->query($sql);
698  if ($resql_insert) {
699  $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det');
700 
701  $this->updateline(
702  $idligne,
703  $line->description,
704  $line->pu_ht,
705  $line->tva_tx,
706  $line->localtax1_tx,
707  $line->localtax2_tx,
708  $line->qty,
709  $line->fk_product,
710  'HT',
711  (!empty($line->info_bits) ? $line->info_bits : ''),
712  $line->product_type,
713  $line->remise_percent,
714  0,
715  $line->date_start,
716  $line->date_end,
717  $line->array_options,
718  $line->fk_unit,
719  $line->multicurrency_subprice,
720  $line->ref_supplier
721  );
722  } else {
723  $this->error = $this->db->lasterror();
724  $this->db->rollback();
725  return -5;
726  }
727  }
728  }
729 
730  /*
731  * Insert lines of template invoices
732  */
733  if (! $error && $this->fac_rec > 0) {
734  foreach ($_facrec->lines as $i => $val) {
735  if ($_facrec->lines[$i]->fk_product) {
736  $prod = new Product($this->db);
737  $res = $prod->fetch($_facrec->lines[$i]->fk_product);
738  }
739 
740  // For line from template invoice, we use data from template invoice
741  /*
742  $tva_tx = get_default_tva($mysoc,$soc,$prod->id);
743  $tva_npr = get_default_npr($mysoc,$soc,$prod->id);
744  if (empty($tva_tx)) $tva_npr=0;
745  $localtax1_tx=get_localtax($tva_tx,1,$soc,$mysoc,$tva_npr);
746  $localtax2_tx=get_localtax($tva_tx,2,$soc,$mysoc,$tva_npr);
747  */
748  $tva_tx = $_facrec->lines[$i]->tva_tx . ($_facrec->lines[$i]->vat_src_code ? '(' . $_facrec->lines[$i]->vat_src_code . ')' : '');
749  $tva_npr = $_facrec->lines[$i]->info_bits;
750  if (empty($tva_tx)) {
751  $tva_npr = 0;
752  }
753  $localtax1_tx = $_facrec->lines[$i]->localtax1_tx;
754  $localtax2_tx = $_facrec->lines[$i]->localtax2_tx;
755 
756  $fk_product_fournisseur_price = empty($_facrec->lines[$i]->fk_product_fournisseur_price) ? null : $_facrec->lines[$i]->fk_product_fournisseur_price;
757  $buyprice = empty($_facrec->lines[$i]->buyprice) ? 0 : $_facrec->lines[$i]->buyprice;
758 
759  // If buyprice not defined from template invoice, we try to guess the best value
760  if (! $buyprice && $_facrec->lines[$i]->fk_product > 0) {
761  require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php';
762  $producttmp = new ProductFournisseur($this->db);
763  $producttmp->fetch($_facrec->lines[$i]->fk_product);
764 
765  // If margin module defined on costprice, we try the costprice
766  // If not defined or if module margin defined and pmp and stock module enabled, we try pmp price
767  // else we get the best supplier price
768  if ($conf->global->MARGIN_TYPE == 'costprice' && !empty($producttmp->cost_price)) {
769  $buyprice = $producttmp->cost_price;
770  } elseif (isModEnabled('stock') && ($conf->global->MARGIN_TYPE == 'costprice' || $conf->global->MARGIN_TYPE == 'pmp') && !empty($producttmp->pmp)) {
771  $buyprice = $producttmp->pmp;
772  } else {
773  if ($producttmp->find_min_price_product_fournisseur($_facrec->lines[$i]->fk_product) > 0) {
774  if ($producttmp->product_fourn_price_id > 0) {
775  $buyprice = price2num($producttmp->fourn_unitprice * (1 - $producttmp->fourn_remise_percent / 100) + $producttmp->fourn_remise, 'MU');
776  }
777  }
778  }
779  }
780 
781  $result_insert = $this->addline(
782  $_facrec->lines[$i]->description,
783  $_facrec->lines[$i]->pu_ht,
784  $tva_tx,
785  $localtax1_tx,
786  $localtax2_tx,
787  $_facrec->lines[$i]->qty,
788  $_facrec->lines[$i]->fk_product,
789  $_facrec->lines[$i]->remise_percent,
790  ($_facrec->lines[$i]->date_start == 1 && $this->date) ? $this->date : '',
791  ($_facrec->lines[$i]->date_end == 1 && $previousdaynextdatewhen) ? $previousdaynextdatewhen : '',
792  0,
793  $_facrec->lines[$i]->info_bits,
794  'HT',
795  0,
796  $_facrec->lines[$i]->rang,
797  false,
798  $_facrec->lines[$i]->array_options,
799  $_facrec->lines[$i]->fk_unit,
800  0,
801  0,
802  $_facrec->lines[$i]->ref_supplier,
803  $_facrec->lines[$i]->special_code,
804  0,
805  0
806  );
807  if ($result_insert < 0) {
808  $error++;
809  $this->error = $this->db->error();
810  break;
811  }
812  }
813  }
814 
815 
816  // Update total price
817  $result = $this->update_price(1);
818  if ($result > 0) {
819  // Actions on extra fields
820  if (!$error) {
821  $result = $this->insertExtraFields(); // This also set $this->error or $this->errors if errors are found
822  if ($result < 0) {
823  $error++;
824  }
825  }
826 
827  if (!$error) {
828  // Call trigger
829  $result = $this->call_trigger('BILL_SUPPLIER_CREATE', $user);
830  if ($result < 0) {
831  $error++;
832  }
833  // End call triggers
834  }
835 
836  if (!$error) {
837  $this->db->commit();
838  return $this->id;
839  } else {
840  $this->db->rollback();
841  return -4;
842  }
843  } else {
844  $this->error = $langs->trans('FailedToUpdatePrice');
845  $this->db->rollback();
846  return -3;
847  }
848  } else {
849  if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
850  $this->error = $langs->trans('ErrorRefAlreadyExists');
851  $this->db->rollback();
852  return -1;
853  } else {
854  $this->error = $this->db->lasterror();
855  $this->db->rollback();
856  return -2;
857  }
858  }
859  }
860 
869  public function fetch($id = '', $ref = '', $ref_ext = '')
870  {
871  if (empty($id) && empty($ref) && empty($ref_ext)) {
872  return -1;
873  }
874 
875  $sql = "SELECT";
876  $sql .= " t.rowid,";
877  $sql .= " t.ref,";
878  $sql .= " t.ref_supplier,";
879  $sql .= " t.ref_ext,";
880  $sql .= " t.entity,";
881  $sql .= " t.type,";
882  $sql .= " t.fk_soc,";
883  $sql .= " t.datec,";
884  $sql .= " t.datef,";
885  $sql .= " t.tms,";
886  $sql .= " t.libelle as label,";
887  $sql .= " t.paye,";
888  $sql .= " t.close_code,";
889  $sql .= " t.close_note,";
890  $sql .= " t.tva,";
891  $sql .= " t.localtax1,";
892  $sql .= " t.localtax2,";
893  $sql .= " t.total_ht,";
894  $sql .= " t.total_tva,";
895  $sql .= " t.total_ttc,";
896  $sql .= " t.fk_statut as status,";
897  $sql .= " t.fk_user_author,";
898  $sql .= " t.fk_user_valid,";
899  $sql .= " t.fk_facture_source,";
900  $sql .= " t.vat_reverse_charge,";
901  $sql .= " t.fk_fac_rec_source,";
902  $sql .= " t.fk_projet as fk_project,";
903  $sql .= " t.fk_cond_reglement,";
904  $sql .= " t.fk_account,";
905  $sql .= " t.fk_mode_reglement,";
906  $sql .= " t.date_lim_reglement,";
907  $sql .= " t.note_private,";
908  $sql .= " t.note_public,";
909  $sql .= " t.model_pdf,";
910  $sql .= " t.import_key,";
911  $sql .= " t.extraparams,";
912  $sql .= " cr.code as cond_reglement_code, cr.libelle as cond_reglement_label, cr.libelle_facture as cond_reglement_doc,";
913  $sql .= " p.code as mode_reglement_code, p.libelle as mode_reglement_label,";
914  $sql .= ' s.nom as socnom, s.rowid as socid,';
915  $sql .= ' t.fk_incoterms, t.location_incoterms,';
916  $sql .= " i.libelle as label_incoterms,";
917  $sql .= ' t.fk_transport_mode,';
918  $sql .= ' t.fk_multicurrency, t.multicurrency_code, t.multicurrency_tx, t.multicurrency_total_ht, t.multicurrency_total_tva, t.multicurrency_total_ttc';
919  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as t';
920  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON (t.fk_soc = s.rowid)";
921  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_payment_term as cr ON t.fk_cond_reglement = cr.rowid";
922  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as p ON t.fk_mode_reglement = p.id";
923  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON t.fk_incoterms = i.rowid';
924  if ($id) {
925  $sql .= " WHERE t.rowid = ".((int) $id);
926  } else {
927  $sql .= ' WHERE t.entity IN ('.getEntity('supplier_invoice').')'; // Don't use entity if you use rowid
928  if ($ref) {
929  $sql .= " AND t.ref = '".$this->db->escape($ref)."'";
930  }
931  if ($ref_ext) {
932  $sql .= " AND t.ref_ext = '".$this->db->escape($ref_ext)."'";
933  }
934  }
935 
936  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
937  $resql = $this->db->query($sql);
938  if ($resql) {
939  if ($this->db->num_rows($resql)) {
940  $obj = $this->db->fetch_object($resql);
941 
942  $this->id = $obj->rowid;
943  $this->ref = $obj->ref ? $obj->ref : $obj->rowid; // We take rowid if ref is empty for backward compatibility
944 
945  $this->ref_supplier = $obj->ref_supplier;
946  $this->ref_ext = $obj->ref_ext;
947  $this->entity = $obj->entity;
948  $this->type = empty($obj->type) ? self::TYPE_STANDARD : $obj->type;
949  $this->fk_soc = $obj->fk_soc;
950  $this->datec = $this->db->jdate($obj->datec);
951  $this->date = $this->db->jdate($obj->datef);
952  $this->datep = $this->db->jdate($obj->datef);
953  $this->tms = $this->db->jdate($obj->tms);
954  $this->libelle = $obj->label; // deprecated
955  $this->label = $obj->label;
956  $this->paye = $obj->paye;
957  $this->paid = $obj->paye;
958  $this->close_code = $obj->close_code;
959  $this->close_note = $obj->close_note;
960  $this->total_localtax1 = $obj->localtax1;
961  $this->total_localtax2 = $obj->localtax2;
962  $this->total_ht = $obj->total_ht;
963  $this->total_tva = $obj->total_tva;
964  $this->total_ttc = $obj->total_ttc;
965  $this->status = $obj->status;
966  $this->statut = $obj->status; // For backward compatibility
967  $this->fk_statut = $obj->status; // For backward compatibility
968  $this->fk_user_author = $obj->fk_user_author;
969  $this->author = $obj->fk_user_author;
970  $this->fk_user_valid = $obj->fk_user_valid;
971  $this->fk_facture_source = $obj->fk_facture_source;
972  $this->vat_reverse_charge = empty($obj->vat_reverse_charge) ? '0' : '1';
973  $this->fk_fac_rec_source = $obj->fk_fac_rec_source;
974  $this->fk_project = $obj->fk_project;
975  $this->cond_reglement_id = $obj->fk_cond_reglement;
976  $this->cond_reglement_code = $obj->cond_reglement_code;
977  $this->cond_reglement = $obj->cond_reglement_label; // deprecated
978  $this->cond_reglement_label = $obj->cond_reglement_label;
979  $this->cond_reglement_doc = $obj->cond_reglement_doc;
980  $this->fk_account = $obj->fk_account;
981  $this->mode_reglement_id = $obj->fk_mode_reglement;
982  $this->mode_reglement_code = $obj->mode_reglement_code;
983  $this->mode_reglement = $obj->mode_reglement_label;
984  $this->date_echeance = $this->db->jdate($obj->date_lim_reglement);
985  $this->note = $obj->note_private; // deprecated
986  $this->note_private = $obj->note_private;
987  $this->note_public = $obj->note_public;
988  $this->model_pdf = $obj->model_pdf;
989  $this->modelpdf = $obj->model_pdf; // deprecated
990  $this->import_key = $obj->import_key;
991 
992  //Incoterms
993  $this->fk_incoterms = $obj->fk_incoterms;
994  $this->location_incoterms = $obj->location_incoterms;
995  $this->label_incoterms = $obj->label_incoterms;
996  $this->transport_mode_id = $obj->fk_transport_mode;
997 
998  // Multicurrency
999  $this->fk_multicurrency = $obj->fk_multicurrency;
1000  $this->multicurrency_code = $obj->multicurrency_code;
1001  $this->multicurrency_tx = $obj->multicurrency_tx;
1002  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
1003  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
1004  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
1005 
1006  $this->extraparams = isset($obj->extraparams) ? (array) json_decode($obj->extraparams, true) : array();
1007 
1008  $this->socid = $obj->socid;
1009  $this->socnom = $obj->socnom;
1010 
1011  // Retrieve all extrafield
1012  // fetch optionals attributes and labels
1013  $this->fetch_optionals();
1014 
1015  if ($this->statut == self::STATUS_DRAFT) {
1016  $this->brouillon = 1;
1017  }
1018 
1019  $result = $this->fetch_lines();
1020  if ($result < 0) {
1021  $this->error = $this->db->lasterror();
1022  return -3;
1023  }
1024  } else {
1025  $this->error = 'Bill with id '.$id.' not found';
1026  dol_syslog(get_class($this).'::fetch '.$this->error);
1027  return 0;
1028  }
1029 
1030  $this->db->free($resql);
1031  return 1;
1032  } else {
1033  $this->error = "Error ".$this->db->lasterror();
1034  return -1;
1035  }
1036  }
1037 
1038 
1039  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1045  public function fetch_lines()
1046  {
1047  // phpcs:enable
1048  $this->lines = array();
1049 
1050  $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';
1051  $sql .= ', f.localtax1_tx, f.localtax2_tx, f.localtax1_type, f.localtax2_type, f.total_localtax1, f.total_localtax2, f.fk_facture_fourn, f.fk_remise_except';
1052  $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';
1053  $sql .= ', p.rowid as product_id, p.ref as product_ref, p.label as label, p.description as product_desc';
1054  $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';
1055  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
1056  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
1057  $sql .= ' WHERE fk_facture_fourn='.((int) $this->id);
1058  $sql .= ' ORDER BY f.rang, f.rowid';
1059 
1060  dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
1061 
1062  $resql_rows = $this->db->query($sql);
1063  if ($resql_rows) {
1064  $num_rows = $this->db->num_rows($resql_rows);
1065  if ($num_rows) {
1066  $i = 0;
1067  while ($i < $num_rows) {
1068  $obj = $this->db->fetch_object($resql_rows);
1069 
1070  $line = new SupplierInvoiceLine($this->db);
1071 
1072  $line->id = $obj->rowid;
1073  $line->rowid = $obj->rowid;
1074  $line->description = $obj->description;
1075  $line->date_start = $obj->date_start;
1076  $line->date_end = $obj->date_end;
1077 
1078  $line->product_ref = $obj->product_ref;
1079  $line->ref = $obj->product_ref;
1080  $line->ref_supplier = $obj->ref_supplier;
1081  $line->libelle = $obj->label;
1082  $line->label = $obj->label;
1083  $line->product_desc = $obj->product_desc;
1084  $line->subprice = $obj->pu_ht;
1085  $line->pu_ht = $obj->pu_ht;
1086  $line->pu_ttc = $obj->pu_ttc;
1087 
1088  $line->vat_src_code = $obj->vat_src_code;
1089  $line->tva_tx = $obj->tva_tx;
1090  $line->localtax1_tx = $obj->localtax1_tx;
1091  $line->localtax2_tx = $obj->localtax2_tx;
1092  $line->localtax1_type = $obj->localtax1_type;
1093  $line->localtax2_type = $obj->localtax2_type;
1094  $line->qty = $obj->qty;
1095  $line->remise_percent = $obj->remise_percent;
1096  $line->fk_remise_except = $obj->fk_remise_except;
1097  //$line->tva = $obj->total_tva; // deprecated
1098  $line->total_ht = $obj->total_ht;
1099  $line->total_ttc = $obj->total_ttc;
1100  $line->total_tva = $obj->total_tva;
1101  $line->total_localtax1 = $obj->total_localtax1;
1102  $line->total_localtax2 = $obj->total_localtax2;
1103  $line->fk_facture_fourn = $obj->fk_facture_fourn;
1104  $line->fk_product = $obj->fk_product;
1105  $line->product_type = $obj->product_type;
1106  $line->product_label = $obj->label;
1107  $line->info_bits = $obj->info_bits;
1108  $line->fk_parent_line = $obj->fk_parent_line;
1109  $line->special_code = $obj->special_code;
1110  $line->rang = $obj->rang;
1111  $line->fk_unit = $obj->fk_unit;
1112 
1113  // Accountancy
1114  $line->code_ventilation = $obj->fk_code_ventilation;
1115  $line->fk_accounting_account = $obj->fk_code_ventilation;
1116 
1117  // Multicurrency
1118  $line->fk_multicurrency = $obj->fk_multicurrency;
1119  $line->multicurrency_code = $obj->multicurrency_code;
1120  $line->multicurrency_subprice = $obj->multicurrency_subprice;
1121  $line->multicurrency_total_ht = $obj->multicurrency_total_ht;
1122  $line->multicurrency_total_tva = $obj->multicurrency_total_tva;
1123  $line->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
1124 
1125  // Extra fields
1126  $line->fetch_optionals();
1127 
1128  $this->lines[$i] = $line;
1129 
1130  $i++;
1131  }
1132  }
1133  $this->db->free($resql_rows);
1134  return 1;
1135  } else {
1136  $this->error = $this->db->error();
1137  return -3;
1138  }
1139  }
1140 
1141 
1149  public function update($user = null, $notrigger = 0)
1150  {
1151  global $conf, $langs;
1152  $error = 0;
1153 
1154  // Clean parameters
1155  if (empty($this->type)) {
1156  $this->type = self::TYPE_STANDARD;
1157  }
1158  if (isset($this->ref)) {
1159  $this->ref = trim($this->ref);
1160  }
1161  if (isset($this->ref_supplier)) {
1162  $this->ref_supplier = trim($this->ref_supplier);
1163  }
1164  if (isset($this->ref_ext)) {
1165  $this->ref_ext = trim($this->ref_ext);
1166  }
1167  if (isset($this->entity)) {
1168  $this->entity = trim($this->entity);
1169  }
1170  if (isset($this->type)) {
1171  $this->type = trim($this->type);
1172  }
1173  if (isset($this->fk_soc)) {
1174  $this->fk_soc = trim($this->fk_soc);
1175  }
1176  if (isset($this->label)) {
1177  $this->label = trim($this->label);
1178  }
1179  if (isset($this->libelle)) {
1180  $this->libelle = trim($this->libelle); // deprecated
1181  }
1182  if (isset($this->paye)) {
1183  $this->paye = trim($this->paye);
1184  }
1185  if (isset($this->close_code)) {
1186  $this->close_code = trim($this->close_code);
1187  }
1188  if (isset($this->close_note)) {
1189  $this->close_note = trim($this->close_note);
1190  }
1191  if (isset($this->localtax1)) {
1192  $this->localtax1 = trim($this->localtax1);
1193  }
1194  if (isset($this->localtax2)) {
1195  $this->localtax2 = trim($this->localtax2);
1196  }
1197  if (empty($this->total_ht)) {
1198  $this->total_ht = 0;
1199  }
1200  if (empty($this->total_tva)) {
1201  $this->total_tva = 0;
1202  }
1203  // if (isset($this->total_localtax1)) $this->total_localtax1=trim($this->total_localtax1);
1204  // if (isset($this->total_localtax2)) $this->total_localtax2=trim($this->total_localtax2);
1205  if (isset($this->total_ttc)) {
1206  $this->total_ttc = trim($this->total_ttc);
1207  }
1208  if (isset($this->statut)) {
1209  $this->statut = (int) $this->statut;
1210  }
1211  if (isset($this->status)) {
1212  $this->status = (int) $this->status;
1213  }
1214  if (isset($this->author)) {
1215  $this->author = trim($this->author);
1216  }
1217  if (isset($this->fk_user_valid)) {
1218  $this->fk_user_valid = trim($this->fk_user_valid);
1219  }
1220  if (isset($this->fk_facture_source)) {
1221  $this->fk_facture_source = trim($this->fk_facture_source);
1222  }
1223  if (isset($this->fk_project)) {
1224  if (empty($this->fk_project)) $this->fk_project = null;
1225  else $this->fk_project = intval($this->fk_project);
1226  }
1227  if (isset($this->cond_reglement_id)) {
1228  $this->cond_reglement_id = trim($this->cond_reglement_id);
1229  }
1230  if (isset($this->note_private)) {
1231  $this->note = trim($this->note_private);
1232  }
1233  if (isset($this->note_public)) {
1234  $this->note_public = trim($this->note_public);
1235  }
1236  if (isset($this->model_pdf)) {
1237  $this->model_pdf = trim($this->model_pdf);
1238  }
1239  if (isset($this->import_key)) {
1240  $this->import_key = trim($this->import_key);
1241  }
1242 
1243 
1244  // Check parameters
1245  // Put here code to add control on parameters values
1246 
1247  // Update request
1248  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn SET";
1249  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
1250  $sql .= " ref_supplier=".(isset($this->ref_supplier) ? "'".$this->db->escape($this->ref_supplier)."'" : "null").",";
1251  $sql .= " ref_ext=".(isset($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : "null").",";
1252  $sql .= " entity=".(isset($this->entity) ? ((int) $this->entity) : "null").",";
1253  $sql .= " type=".(isset($this->type) ? ((int) $this->type) : "null").",";
1254  $sql .= " fk_soc=".(isset($this->fk_soc) ? ((int) $this->fk_soc) : "null").",";
1255  $sql .= " datec=".(dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
1256  $sql .= " datef=".(dol_strlen($this->date) != 0 ? "'".$this->db->idate($this->date)."'" : 'null').",";
1257  if (dol_strlen($this->tms) != 0) {
1258  $sql .= " tms=".(dol_strlen($this->tms) != 0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
1259  }
1260  $sql .= " libelle=".(isset($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
1261  $sql .= " paye=".(isset($this->paye) ? ((int) $this->paye) : "null").",";
1262  $sql .= " close_code=".(isset($this->close_code) ? "'".$this->db->escape($this->close_code)."'" : "null").",";
1263  $sql .= " close_note=".(isset($this->close_note) ? "'".$this->db->escape($this->close_note)."'" : "null").",";
1264  $sql .= " localtax1=".(isset($this->localtax1) ? ((float) $this->localtax1) : "null").",";
1265  $sql .= " localtax2=".(isset($this->localtax2) ? ((float) $this->localtax2) : "null").",";
1266  $sql .= " total_ht=".(isset($this->total_ht) ? ((float) $this->total_ht) : "null").",";
1267  $sql .= " total_tva=".(isset($this->total_tva) ? ((float) $this->total_tva) : "null").",";
1268  $sql .= " total_ttc=".(isset($this->total_ttc) ? ((float) $this->total_ttc) : "null").",";
1269  $sql .= " fk_statut=".(isset($this->status) ? ((int) $this->status) : (isset($this->statut) ? ((int) $this->statut) : "null")).",";
1270  $sql .= " fk_user_author=".(isset($this->author) ? ((int) $this->author) : "null").",";
1271  $sql .= " fk_user_valid=".(isset($this->fk_user_valid) ? ((int) $this->fk_user_valid) : "null").",";
1272  $sql .= " fk_facture_source=".($this->fk_facture_source ? ((int) $this->fk_facture_source) : "null").",";
1273  $sql .= " vat_reverse_charge = ".($this->vat_reverse_charge != '' ? ((int) $this->db->escape($this->vat_reverse_charge)) : 0).",";
1274  $sql .= " fk_projet=".(isset($this->fk_project) ? ((int) $this->fk_project) : "null").",";
1275  $sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? ((int) $this->cond_reglement_id) : "null").",";
1276  $sql .= " date_lim_reglement=".(dol_strlen($this->date_echeance) != 0 ? "'".$this->db->idate($this->date_echeance)."'" : 'null').",";
1277  $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
1278  $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
1279  $sql .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
1280  $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null");
1281  $sql .= " WHERE rowid=".((int) $this->id);
1282 
1283  $this->db->begin();
1284 
1285  dol_syslog(get_class($this)."::update", LOG_DEBUG);
1286  $resql = $this->db->query($sql);
1287 
1288  if (!$resql) {
1289  $error++;
1290 
1291  if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1292  $this->errors[] = $langs->trans('ErrorRefAlreadyExists');
1293  } else {
1294  $this->errors[] = "Error ".$this->db->lasterror();
1295  }
1296  }
1297 
1298  if (!$error) {
1299  $result = $this->insertExtraFields();
1300  if ($result < 0) {
1301  $error++;
1302  }
1303  }
1304 
1305  if (!$error) {
1306  if (!$notrigger) {
1307  // Call trigger
1308  $result = $this->call_trigger('BILL_SUPPLIER_MODIFY', $user);
1309  if ($result < 0) {
1310  $error++;
1311  }
1312  // End call triggers
1313  }
1314  }
1315 
1316  // Commit or rollback
1317  if ($error) {
1318  foreach ($this->errors as $errmsg) {
1319  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
1320  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1321  }
1322  $this->db->rollback();
1323  return -1 * $error;
1324  } else {
1325  $this->db->commit();
1326  return 1;
1327  }
1328  }
1329 
1330  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1337  public function insert_discount($idremise)
1338  {
1339  // phpcs:enable
1340  global $conf, $langs;
1341 
1342  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1343  include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
1344 
1345  $this->db->begin();
1346 
1347  $remise = new DiscountAbsolute($this->db);
1348  $result = $remise->fetch($idremise);
1349 
1350  if ($result > 0) {
1351  if ($remise->fk_invoice_supplier) { // Protection against multiple submission
1352  $this->error = $langs->trans("ErrorDiscountAlreadyUsed");
1353  $this->db->rollback();
1354  return -5;
1355  }
1356 
1357  $facligne = new SupplierInvoiceLine($this->db);
1358  $facligne->fk_facture_fourn = $this->id;
1359  $facligne->fk_remise_except = $remise->id;
1360  $facligne->desc = $remise->description; // Description ligne
1361  $facligne->vat_src_code = $remise->vat_src_code;
1362  $facligne->tva_tx = $remise->tva_tx;
1363  $facligne->subprice = -$remise->amount_ht;
1364  $facligne->fk_product = 0; // Id produit predefini
1365  $facligne->product_type = 0;
1366  $facligne->qty = 1;
1367  $facligne->remise_percent = 0;
1368  $facligne->rang = -1;
1369  $facligne->info_bits = 2;
1370 
1371  if (!empty($conf->global->MAIN_ADD_LINE_AT_POSITION)) {
1372  $facligne->rang = 1;
1373  $linecount = count($this->lines);
1374  for ($ii = 1; $ii <= $linecount; $ii++) {
1375  $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii+1);
1376  }
1377  }
1378 
1379  // Get buy/cost price of invoice that is source of discount
1380  if ($remise->fk_invoice_supplier_source > 0) {
1381  $srcinvoice = new FactureFournisseur($this->db);
1382  $srcinvoice->fetch($remise->fk_invoice_supplier_source);
1383  $totalcostpriceofinvoice = 0;
1384  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php'; // TODO Move this into commonobject
1385  $formmargin = new FormMargin($this->db);
1386  $arraytmp = $formmargin->getMarginInfosArray($srcinvoice, false);
1387  $facligne->pa_ht = $arraytmp['pa_total'];
1388  }
1389 
1390  $facligne->total_ht = -$remise->amount_ht;
1391  $facligne->total_tva = -$remise->amount_tva;
1392  $facligne->total_ttc = -$remise->amount_ttc;
1393 
1394  $facligne->multicurrency_subprice = -$remise->multicurrency_subprice;
1395  $facligne->multicurrency_total_ht = -$remise->multicurrency_total_ht;
1396  $facligne->multicurrency_total_tva = -$remise->multicurrency_total_tva;
1397  $facligne->multicurrency_total_ttc = -$remise->multicurrency_total_ttc;
1398 
1399  $lineid = $facligne->insert();
1400  if ($lineid > 0) {
1401  $result = $this->update_price(1);
1402  if ($result > 0) {
1403  // Create link between discount and invoice line
1404  $result = $remise->link_to_invoice($lineid, 0);
1405  if ($result < 0) {
1406  $this->error = $remise->error;
1407  $this->db->rollback();
1408  return -4;
1409  }
1410 
1411  $this->db->commit();
1412  return 1;
1413  } else {
1414  $this->error = $facligne->error;
1415  $this->db->rollback();
1416  return -1;
1417  }
1418  } else {
1419  $this->error = $facligne->error;
1420  $this->db->rollback();
1421  return -2;
1422  }
1423  } else {
1424  $this->db->rollback();
1425  return -3;
1426  }
1427  }
1428 
1429 
1437  public function delete(User $user, $notrigger = 0)
1438  {
1439  global $langs, $conf;
1440 
1441  $rowid = $this->id;
1442 
1443  dol_syslog("FactureFournisseur::delete rowid=".$rowid, LOG_DEBUG);
1444 
1445  // TODO Test if there is at least on payment. If yes, refuse to delete.
1446 
1447  $error = 0;
1448  $this->db->begin();
1449 
1450  if (!$error && !$notrigger) {
1451  // Call trigger
1452  $result = $this->call_trigger('BILL_SUPPLIER_DELETE', $user);
1453  if ($result < 0) {
1454  $this->db->rollback();
1455  return -1;
1456  }
1457  // Fin appel triggers
1458  }
1459 
1460  if (!$error) {
1461  // If invoice was converted into a discount not yet consumed, we remove discount
1462  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'societe_remise_except';
1463  $sql .= ' WHERE fk_invoice_supplier_source = '.((int) $rowid);
1464  $sql .= ' AND fk_invoice_supplier_line IS NULL';
1465  $resql = $this->db->query($sql);
1466 
1467  // If invoice has consumned discounts
1468  $this->fetch_lines();
1469  $list_rowid_det = array();
1470  foreach ($this->lines as $key => $invoiceline) {
1471  $list_rowid_det[] = $invoiceline->rowid;
1472  }
1473 
1474  // Consumned discounts are freed
1475  if (count($list_rowid_det)) {
1476  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
1477  $sql .= ' SET fk_invoice_supplier = NULL, fk_invoice_supplier_line = NULL';
1478  $sql .= ' WHERE fk_invoice_supplier_line IN ('.$this->db->sanitize(join(',', $list_rowid_det)).')';
1479 
1480  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1481  if (!$this->db->query($sql)) {
1482  $error++;
1483  }
1484  }
1485  }
1486 
1487  if (!$error) {
1488  $main = MAIN_DB_PREFIX.'facture_fourn_det';
1489  $ef = $main."_extrafields";
1490  $sqlef = "DELETE FROM $ef WHERE fk_object IN (SELECT rowid FROM ".$main." WHERE fk_facture_fourn = ".((int) $rowid).")";
1491  $resqlef = $this->db->query($sqlef);
1492  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det WHERE fk_facture_fourn = '.((int) $rowid);
1493  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1494  $resql = $this->db->query($sql);
1495  if ($resqlef && $resql) {
1496  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn WHERE rowid = '.((int) $rowid);
1497  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1498  $resql2 = $this->db->query($sql);
1499  if (!$resql2) {
1500  $error++;
1501  }
1502  } else {
1503  $error++;
1504  }
1505  }
1506 
1507  if (!$error) {
1508  // Delete linked object
1509  $res = $this->deleteObjectLinked();
1510  if ($res < 0) {
1511  $error++;
1512  }
1513  }
1514 
1515  if (!$error) {
1516  // Delete record into ECM index (Note that delete is also done when deleting files with the dol_delete_dir_recursive
1517  $this->deleteEcmFiles();
1518 
1519  // We remove directory
1520  if ($conf->fournisseur->facture->dir_output) {
1521  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1522 
1523  $ref = dol_sanitizeFileName($this->ref);
1524  $dir = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$ref;
1525  $file = $dir."/".$ref.".pdf";
1526  if (file_exists($file)) {
1527  if (!dol_delete_file($file, 0, 0, 0, $this)) { // For triggers
1528  $this->error = 'ErrorFailToDeleteFile';
1529  $error++;
1530  }
1531  }
1532  if (file_exists($dir)) {
1533  $res = @dol_delete_dir_recursive($dir);
1534 
1535  if (!$res) {
1536  $this->error = 'ErrorFailToDeleteDir';
1537  $error++;
1538  }
1539  }
1540  }
1541  }
1542 
1543  // Remove extrafields
1544  if (!$error) {
1545  $result = $this->deleteExtraFields();
1546  if ($result < 0) {
1547  $error++;
1548  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1549  }
1550  }
1551 
1552  if (!$error) {
1553  dol_syslog(get_class($this)."::delete $this->id by $user->id", LOG_DEBUG);
1554  $this->db->commit();
1555  return 1;
1556  } else {
1557  $this->error = $this->db->lasterror();
1558  $this->db->rollback();
1559  return -$error;
1560  }
1561  }
1562 
1563 
1564  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1575  public function set_paid($user, $close_code = '', $close_note = '')
1576  {
1577  // phpcs:enable
1578  dol_syslog(get_class($this)."::set_paid is deprecated, use setPaid instead", LOG_NOTICE);
1579  return $this->setPaid($user, $close_code, $close_note);
1580  }
1581 
1590  public function setPaid($user, $close_code = '', $close_note = '')
1591  {
1592  $error = 0;
1593 
1594  if ($this->paye != 1) {
1595  $this->db->begin();
1596 
1597  $now = dol_now();
1598 
1599  dol_syslog("FactureFournisseur::set_paid", LOG_DEBUG);
1600 
1601  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn SET';
1602  $sql .= ' fk_statut = '.self::STATUS_CLOSED;
1603  if (!$close_code) {
1604  $sql .= ', paye=1';
1605  }
1606  if ($close_code) {
1607  $sql .= ", close_code='".$this->db->escape($close_code)."'";
1608  }
1609  if ($close_note) {
1610  $sql .= ", close_note='".$this->db->escape($close_note)."'";
1611  }
1612  $sql .= ', fk_user_closing = '.((int) $user->id);
1613  $sql .= ", date_closing = '".$this->db->idate($now)."'";
1614  $sql .= ' WHERE rowid = '.((int) $this->id);
1615 
1616  $resql = $this->db->query($sql);
1617  if ($resql) {
1618  // Call trigger
1619  $result = $this->call_trigger('BILL_SUPPLIER_PAYED', $user);
1620  if ($result < 0) {
1621  $error++;
1622  }
1623  // End call triggers
1624  } else {
1625  $error++;
1626  $this->error = $this->db->error();
1627  dol_print_error($this->db);
1628  }
1629 
1630  if (!$error) {
1631  $this->db->commit();
1632  return 1;
1633  } else {
1634  $this->db->rollback();
1635  return -1;
1636  }
1637  } else {
1638  return 0;
1639  }
1640  }
1641 
1642  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1653  public function set_unpaid($user)
1654  {
1655  // phpcs:enable
1656  dol_syslog(get_class($this)."::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE);
1657  return $this->setUnpaid($user);
1658  }
1659 
1668  public function setUnpaid($user)
1669  {
1670  $error = 0;
1671 
1672  $this->db->begin();
1673 
1674  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn';
1675  $sql .= ' SET paye=0, fk_statut='.self::STATUS_VALIDATED.', close_code=null, close_note=null,';
1676  $sql .= ' date_closing=null,';
1677  $sql .= ' fk_user_closing=null';
1678  $sql .= ' WHERE rowid = '.((int) $this->id);
1679 
1680  dol_syslog(get_class($this)."::set_unpaid", LOG_DEBUG);
1681  $resql = $this->db->query($sql);
1682  if ($resql) {
1683  // Call trigger
1684  $result = $this->call_trigger('BILL_SUPPLIER_UNPAYED', $user);
1685  if ($result < 0) {
1686  $error++;
1687  }
1688  // End call triggers
1689  } else {
1690  $error++;
1691  $this->error = $this->db->error();
1692  dol_print_error($this->db);
1693  }
1694 
1695  if (!$error) {
1696  $this->db->commit();
1697  return 1;
1698  } else {
1699  $this->db->rollback();
1700  return -1;
1701  }
1702  }
1703 
1714  public function setCanceled($user, $close_code = '', $close_note = '')
1715  {
1716  dol_syslog(get_class($this)."::setCanceled rowid=".((int) $this->id), LOG_DEBUG);
1717 
1718  $this->db->begin();
1719 
1720  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn SET';
1721  $sql .= ' fk_statut='.self::STATUS_ABANDONED;
1722  if ($close_code) {
1723  $sql .= ", close_code='".$this->db->escape($close_code)."'";
1724  }
1725  if ($close_note) {
1726  $sql .= ", close_note='".$this->db->escape($close_note)."'";
1727  }
1728  $sql .= " WHERE rowid = ".((int) $this->id);
1729 
1730  $resql = $this->db->query($sql);
1731  if ($resql) {
1732  // Bound discounts are deducted from the invoice
1733  // as they have not been used since the invoice is abandoned.
1734  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
1735  $sql .= ' SET fk_invoice_supplier = NULL';
1736  $sql .= ' WHERE fk_invoice_supplier = '.((int) $this->id);
1737 
1738  $resql = $this->db->query($sql);
1739  if ($resql) {
1740  // Call trigger
1741  $result = $this->call_trigger('BILL_SUPPLIER_CANCEL', $user);
1742  if ($result < 0) {
1743  $this->db->rollback();
1744  return -1;
1745  }
1746  // End call triggers
1747 
1748  $this->db->commit();
1749  return 1;
1750  } else {
1751  $this->error = $this->db->error()." sql=".$sql;
1752  $this->db->rollback();
1753  return -1;
1754  }
1755  } else {
1756  $this->error = $this->db->error()." sql=".$sql;
1757  $this->db->rollback();
1758  return -2;
1759  }
1760  }
1761 
1771  public function validate($user, $force_number = '', $idwarehouse = 0, $notrigger = 0)
1772  {
1773  global $conf, $langs;
1774 
1775  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1776 
1777  $now = dol_now();
1778 
1779  $error = 0;
1780  dol_syslog(get_class($this).'::validate user='.$user->id.', force_number='.$force_number.', idwarehouse='.$idwarehouse);
1781 
1782  // Force to have object complete for checks
1783  $this->fetch_thirdparty();
1784  $this->fetch_lines();
1785 
1786  // Check parameters
1787  if ($this->statut > self::STATUS_DRAFT) { // This is to avoid to validate twice (avoid errors on logs and stock management)
1788  dol_syslog(get_class($this)."::validate no draft status", LOG_WARNING);
1789  return 0;
1790  }
1791  if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ').'/', $this->ref_supplier)) {
1792  $langs->load("errors");
1793  $this->error = $langs->trans("ErrorFieldFormat", $langs->transnoentities("RefSupplier")).'. '.$langs->trans('RemoveString', $langs->transnoentitiesnoconv("CopyOf"));
1794  return -1;
1795  }
1796  if (count($this->lines) <= 0) {
1797  $langs->load("errors");
1798  $this->error = $langs->trans("ErrorObjectMustHaveLinesToBeValidated", $this->ref);
1799  return -1;
1800  }
1801 
1802  $this->db->begin();
1803 
1804  // Define new ref
1805  if ($force_number) {
1806  $num = $force_number;
1807  } elseif (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
1808  $num = $this->getNextNumRef($this->thirdparty);
1809  } else {
1810  $num = $this->ref;
1811  }
1812  $this->newref = dol_sanitizeFileName($num);
1813 
1814  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1815  $sql .= " SET ref='".$this->db->escape($num)."', fk_statut = 1, fk_user_valid = ".((int) $user->id).", date_valid = '".$this->db->idate($now)."'";
1816  $sql .= " WHERE rowid = ".((int) $this->id);
1817 
1818  dol_syslog(get_class($this)."::validate", LOG_DEBUG);
1819  $resql = $this->db->query($sql);
1820  if ($resql) {
1821  // Si on incrémente le produit principal et ses composants à la validation de facture fournisseur
1822  if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) {
1823  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1824  $langs->load("agenda");
1825 
1826  $cpt = count($this->lines);
1827  for ($i = 0; $i < $cpt; $i++) {
1828  if ($this->lines[$i]->fk_product > 0) {
1829  $mouvP = new MouvementStock($this->db);
1830  $mouvP->origin = &$this;
1831  $mouvP->setOrigin($this->element, $this->id);
1832  // We increase stock for product
1833  $up_ht_disc = $this->lines[$i]->subprice;
1834  if (!empty($this->lines[$i]->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) {
1835  $up_ht_disc = price2num($up_ht_disc * (100 - $this->lines[$i]->remise_percent) / 100, 'MU');
1836  }
1838  $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1839  } else {
1840  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1841  }
1842  if ($result < 0) {
1843  $error++;
1844  }
1845  }
1846  }
1847  }
1848 
1849  // Triggers call
1850  if (!$error && empty($notrigger)) {
1851  // Call trigger
1852  $result = $this->call_trigger('BILL_SUPPLIER_VALIDATE', $user);
1853  if ($result < 0) {
1854  $error++;
1855  }
1856  // End call triggers
1857  }
1858 
1859  if (!$error) {
1860  $this->oldref = $this->ref;
1861 
1862  // Rename directory if dir was a temporary ref
1863  if (preg_match('/^[\(]?PROV/i', $this->ref)) {
1864  // Now we rename also files into index
1865  $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)."'";
1866  $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;
1867  $resql = $this->db->query($sql);
1868  if (!$resql) {
1869  $error++; $this->error = $this->db->lasterror();
1870  }
1871 
1872  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1873  $oldref = dol_sanitizeFileName($this->ref);
1874  $newref = dol_sanitizeFileName($num);
1875  $dirsource = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$oldref;
1876  $dirdest = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$newref;
1877  if (!$error && file_exists($dirsource)) {
1878  dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest);
1879 
1880  if (@rename($dirsource, $dirdest)) {
1881  dol_syslog("Rename ok");
1882  // Rename docs starting with $oldref with $newref
1883  $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, '/'));
1884  foreach ($listoffiles as $fileentry) {
1885  $dirsource = $fileentry['name'];
1886  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1887  $dirsource = $fileentry['path'].'/'.$dirsource;
1888  $dirdest = $fileentry['path'].'/'.$dirdest;
1889  @rename($dirsource, $dirdest);
1890  }
1891  }
1892  }
1893  }
1894  }
1895 
1896  // Set new ref and define current statut
1897  if (!$error) {
1898  $this->ref = $num;
1899  $this->statut = self::STATUS_VALIDATED;
1900  //$this->date_validation=$now; this is stored into log table
1901  }
1902 
1903  if (!$error) {
1904  $this->db->commit();
1905  return 1;
1906  } else {
1907  $this->db->rollback();
1908  return -1;
1909  }
1910  } else {
1911  $this->error = $this->db->error();
1912  $this->db->rollback();
1913  return -1;
1914  }
1915  }
1916 
1924  public function setDraft($user, $idwarehouse = -1)
1925  {
1926  // phpcs:enable
1927  global $conf, $langs;
1928 
1929  $error = 0;
1930 
1931  if ($this->statut == self::STATUS_DRAFT) {
1932  dol_syslog(__METHOD__." already draft status", LOG_WARNING);
1933  return 0;
1934  }
1935 
1936  dol_syslog(__METHOD__, LOG_DEBUG);
1937 
1938  $this->db->begin();
1939 
1940  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1941  $sql .= " SET fk_statut = ".self::STATUS_DRAFT;
1942  $sql .= " WHERE rowid = ".((int) $this->id);
1943 
1944  $result = $this->db->query($sql);
1945  if ($result) {
1946  if (!$error) {
1947  $this->oldcopy = clone $this;
1948  }
1949 
1950  // Si on incremente le produit principal et ses composants a la validation de facture fournisseur, on decremente
1951  if ($result >= 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) {
1952  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1953  $langs->load("agenda");
1954 
1955  $cpt = count($this->lines);
1956  for ($i = 0; $i < $cpt; $i++) {
1957  if ($this->lines[$i]->fk_product > 0) {
1958  $mouvP = new MouvementStock($this->db);
1959  $mouvP->origin = &$this;
1960  $mouvP->setOrigin($this->element, $this->id);
1961  // We increase stock for product
1963  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
1964  } else {
1965  $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
1966  }
1967  }
1968  }
1969  }
1970  // Triggers call
1971  if (!$error && empty($notrigger)) {
1972  // Call trigger
1973  $result = $this->call_trigger('BILL_SUPPLIER_UNVALIDATE', $user);
1974  if ($result < 0) {
1975  $error++;
1976  }
1977  // End call triggers
1978  }
1979  if ($error == 0) {
1980  $this->db->commit();
1981  return 1;
1982  } else {
1983  $this->db->rollback();
1984  return -1;
1985  }
1986  } else {
1987  $this->error = $this->db->error();
1988  $this->db->rollback();
1989  return -1;
1990  }
1991  }
1992 
1993 
2027  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_devise = 0, $ref_supplier = '', $special_code = '', $fk_parent_line = 0, $fk_remise_except = 0)
2028  {
2029  global $langs, $mysoc, $conf;
2030 
2031  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,fk_remise_except=$fk_remise_except", LOG_DEBUG);
2032  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2033 
2034  if ($this->statut == self::STATUS_DRAFT) {
2035  // Clean parameters
2036  if (empty($remise_percent)) {
2037  $remise_percent = 0;
2038  }
2039  if (empty($qty)) {
2040  $qty = 0;
2041  }
2042  if (empty($info_bits)) {
2043  $info_bits = 0;
2044  }
2045  if (empty($rang)) {
2046  $rang = 0;
2047  }
2048  if (empty($ventil)) {
2049  $ventil = 0;
2050  }
2051  if (empty($txtva)) {
2052  $txtva = 0;
2053  }
2054  if (empty($txlocaltax1)) {
2055  $txlocaltax1 = 0;
2056  }
2057  if (empty($txlocaltax2)) {
2058  $txlocaltax2 = 0;
2059  }
2060 
2061  $remise_percent = price2num($remise_percent);
2062  $qty = price2num($qty);
2063  $pu = price2num($pu);
2064  if (!preg_match('/\((.*)\)/', $txtva)) {
2065  $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
2066  }
2067  $txlocaltax1 = price2num($txlocaltax1);
2068  $txlocaltax2 = price2num($txlocaltax2);
2069 
2070  if ($date_start && $date_end && $date_start > $date_end) {
2071  $langs->load("errors");
2072  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
2073  return -1;
2074  }
2075 
2076  $this->db->begin();
2077 
2078  if ($fk_product > 0) {
2079  if (!empty($conf->global->SUPPLIER_INVOICE_WITH_PREDEFINED_PRICES_ONLY)) {
2080  // Check quantity is enough
2081  dol_syslog(get_class($this)."::addline we check supplier prices fk_product=".$fk_product." qty=".$qty." ref_supplier=".$ref_supplier);
2082  $prod = new ProductFournisseur($this->db);
2083  if ($prod->fetch($fk_product) > 0) {
2084  $product_type = $prod->type;
2085  $label = $prod->label;
2086  $fk_prod_fourn_price = 0;
2087 
2088  // We use 'none' instead of $ref_supplier, because $ref_supplier may not exists anymore. So we will take the first supplier price ok.
2089  // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
2090  $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
2091  if ($result > 0) {
2092  if (empty($pu)) {
2093  $pu = $prod->fourn_pu; // Unit price supplier price set by get_buyprice
2094  }
2095  $ref_supplier = $prod->ref_supplier; // Ref supplier price set by get_buyprice
2096  // is remise percent not keyed but present for the product we add it
2097  if ($remise_percent == 0 && $prod->remise_percent != 0) {
2098  $remise_percent = $prod->remise_percent;
2099  }
2100  }
2101  if ($result == 0) { // If result == 0, we failed to found the supplier reference price
2102  $langs->load("errors");
2103  $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
2104  $this->db->rollback();
2105  dol_syslog(get_class($this)."::addline we did not found supplier price, so we can't guess unit price");
2106  //$pu = $prod->fourn_pu; // We do not overwrite unit price
2107  //$ref = $prod->ref_fourn; // We do not overwrite ref supplier price
2108  return -1;
2109  }
2110  if ($result == -1) {
2111  $langs->load("errors");
2112  $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
2113  $this->db->rollback();
2114  dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_DEBUG);
2115  return -1;
2116  }
2117  if ($result < -1) {
2118  $this->error = $prod->error;
2119  $this->db->rollback();
2120  dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_ERR);
2121  return -1;
2122  }
2123  } else {
2124  $this->error = $prod->error;
2125  $this->db->rollback();
2126  return -1;
2127  }
2128  }
2129  } else {
2130  $product_type = $type;
2131  }
2132 
2133  if (isModEnabled("multicurrency") && $pu_devise > 0) {
2134  $pu = 0;
2135  }
2136 
2137  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $mysoc, $this->thirdparty);
2138 
2139  // Clean vat code
2140  $reg = array();
2141  $vat_src_code = '';
2142  if (preg_match('/\((.*)\)/', $txtva, $reg)) {
2143  $vat_src_code = $reg[1];
2144  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
2145  }
2146 
2147  // Calcul du total TTC et de la TVA pour la ligne a partir de
2148  // qty, pu, remise_percent et txtva
2149  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2150  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2151 
2152  $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_devise);
2153  $total_ht = $tabprice[0];
2154  $total_tva = $tabprice[1];
2155  $total_ttc = $tabprice[2];
2156  $total_localtax1 = $tabprice[9];
2157  $total_localtax2 = $tabprice[10];
2158  $pu_ht = $tabprice[3];
2159 
2160  // MultiCurrency
2161  $multicurrency_total_ht = $tabprice[16];
2162  $multicurrency_total_tva = $tabprice[17];
2163  $multicurrency_total_ttc = $tabprice[18];
2164  $pu_ht_devise = $tabprice[19];
2165 
2166  // Check parameters
2167  if ($type < 0) {
2168  return -1;
2169  }
2170 
2171  if ($rang < 0) {
2172  $rangmax = $this->line_max();
2173  $rang = $rangmax + 1;
2174  }
2175 
2176  // Insert line
2177  $supplierinvoiceline = new SupplierInvoiceLine($this->db);
2178 
2179  $supplierinvoiceline->context = $this->context;
2180 
2181  $supplierinvoiceline->fk_facture_fourn = $this->id;
2182  //$supplierinvoiceline->label=$label; // deprecated
2183  $supplierinvoiceline->desc = $desc;
2184  $supplierinvoiceline->ref_supplier = $ref_supplier;
2185 
2186  $supplierinvoiceline->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs($qty) : $qty); // For credit note, quantity is always positive and unit price negative
2187  $supplierinvoiceline->subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2188 
2189  $supplierinvoiceline->vat_src_code = $vat_src_code;
2190  $supplierinvoiceline->tva_tx = $txtva;
2191  $supplierinvoiceline->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
2192  $supplierinvoiceline->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
2193  $supplierinvoiceline->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
2194  $supplierinvoiceline->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
2195 
2196  $supplierinvoiceline->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
2197  $supplierinvoiceline->total_tva = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_tva) : $total_tva); // For credit note and if qty is negative, total is negative
2198  $supplierinvoiceline->total_localtax1 = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_localtax1) : $total_localtax1); // For credit note and if qty is negative, total is negative
2199  $supplierinvoiceline->total_localtax2 = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_localtax2) : $total_localtax2); // For credit note and if qty is negative, total is negative
2200  $supplierinvoiceline->total_ttc = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_ttc) : $total_ttc); // For credit note and if qty is negative, total is negative
2201 
2202  $supplierinvoiceline->fk_product = $fk_product;
2203  $supplierinvoiceline->product_type = $type;
2204  $supplierinvoiceline->remise_percent = $remise_percent;
2205  $supplierinvoiceline->date_start = $date_start;
2206  $supplierinvoiceline->date_end = $date_end;
2207  $supplierinvoiceline->fk_code_ventilation = $ventil;
2208  $supplierinvoiceline->rang = $rang;
2209  $supplierinvoiceline->info_bits = $info_bits;
2210  $supplierinvoiceline->fk_remise_except = $fk_remise_except;
2211 
2212  $supplierinvoiceline->special_code = ((string) $special_code != '' ? $special_code : $this->special_code);
2213  $supplierinvoiceline->fk_parent_line = $fk_parent_line;
2214  $supplierinvoiceline->origin = $this->origin;
2215  $supplierinvoiceline->origin_id = $origin_id;
2216  $supplierinvoiceline->fk_unit = $fk_unit;
2217 
2218  // Multicurrency
2219  $supplierinvoiceline->fk_multicurrency = $this->fk_multicurrency;
2220  $supplierinvoiceline->multicurrency_code = $this->multicurrency_code;
2221  $supplierinvoiceline->multicurrency_subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht_devise) : $pu_ht_devise); // For credit note, unit price always negative, always positive otherwise
2222 
2223  $supplierinvoiceline->multicurrency_total_ht = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($multicurrency_total_ht) : $multicurrency_total_ht); // For credit note and if qty is negative, total is negative
2224  $supplierinvoiceline->multicurrency_total_tva = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($multicurrency_total_tva) : $multicurrency_total_tva); // For credit note and if qty is negative, total is negative
2225  $supplierinvoiceline->multicurrency_total_ttc = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($multicurrency_total_ttc) : $multicurrency_total_ttc); // For credit note and if qty is negative, total is negative
2226 
2227  if (is_array($array_options) && count($array_options) > 0) {
2228  $supplierinvoiceline->array_options = $array_options;
2229  }
2230 
2231  $result = $supplierinvoiceline->insert($notrigger);
2232  if ($result > 0) {
2233  // Reorder if child line
2234  if (!empty($fk_parent_line)) {
2235  $this->line_order(true, 'DESC');
2236  } elseif ($rang > 0 && $rang <= count($this->lines)) { // Update all rank of all other lines
2237  $linecount = count($this->lines);
2238  for ($ii = $rang; $ii <= $linecount; $ii++) {
2239  $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1);
2240  }
2241  }
2242 
2243  // Mise a jour informations denormalisees au niveau de la facture meme
2244  $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.
2245  if ($result > 0) {
2246  $this->db->commit();
2247  return $supplierinvoiceline->id;
2248  } else {
2249  $this->error = $this->db->error();
2250  $this->db->rollback();
2251  return -1;
2252  }
2253  } else {
2254  $this->error = $supplierinvoiceline->error;
2255  $this->errors = $supplierinvoiceline->errors;
2256  $this->db->rollback();
2257  return -2;
2258  }
2259  } else {
2260  return 0;
2261  }
2262  }
2263 
2289  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_devise = 0, $ref_supplier = '', $rang = 0)
2290  {
2291  global $mysoc, $langs;
2292 
2293  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_devise,$ref_supplier", LOG_DEBUG);
2294  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2295 
2296  $pu = price2num($pu);
2297  $qty = price2num($qty);
2298  $remise_percent = price2num($remise_percent);
2299  $pu_devise = price2num($pu_devise);
2300 
2301  // Check parameters
2302  //if (! is_numeric($pu) || ! is_numeric($qty)) return -1;
2303  if ($type < 0) {
2304  return -1;
2305  }
2306 
2307  if ($date_start && $date_end && $date_start > $date_end) {
2308  $langs->load("errors");
2309  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
2310  return -1;
2311  }
2312 
2313  // Clean parameters
2314  if (empty($vatrate)) {
2315  $vatrate = 0;
2316  }
2317  if (empty($txlocaltax1)) {
2318  $txlocaltax1 = 0;
2319  }
2320  if (empty($txlocaltax2)) {
2321  $txlocaltax2 = 0;
2322  }
2323 
2324  $txlocaltax1 = price2num($txlocaltax1);
2325  $txlocaltax2 = price2num($txlocaltax2);
2326 
2327  // Calcul du total TTC et de la TVA pour la ligne a partir de
2328  // qty, pu, remise_percent et txtva
2329  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2330  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2331 
2332  $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $mysoc, $this->thirdparty);
2333 
2334  $reg = array();
2335 
2336  // Clean vat code
2337  $vat_src_code = '';
2338  if (preg_match('/\((.*)\)/', $vatrate, $reg)) {
2339  $vat_src_code = $reg[1];
2340  $vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate.
2341  }
2342 
2343  $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_devise);
2344  $total_ht = $tabprice[0];
2345  $total_tva = $tabprice[1];
2346  $total_ttc = $tabprice[2];
2347  $pu_ht = $tabprice[3];
2348  $pu_tva = $tabprice[4];
2349  $pu_ttc = $tabprice[5];
2350  $total_localtax1 = $tabprice[9];
2351  $total_localtax2 = $tabprice[10];
2352 
2353  // MultiCurrency
2354  $multicurrency_total_ht = $tabprice[16];
2355  $multicurrency_total_tva = $tabprice[17];
2356  $multicurrency_total_ttc = $tabprice[18];
2357  $pu_ht_devise = $tabprice[19];
2358 
2359  if (empty($info_bits)) {
2360  $info_bits = 0;
2361  }
2362 
2363  //Fetch current line from the database and then clone the object and set it in $oldline property
2364  $line = new SupplierInvoiceLine($this->db);
2365  $line->fetch($id);
2366  $line->fetch_optionals();
2367 
2368  $staticline = clone $line;
2369 
2370  if ($idproduct) {
2371  $product = new Product($this->db);
2372  $result = $product->fetch($idproduct);
2373  $product_type = $product->type;
2374  } else {
2375  $idproduct = $staticline->fk_product;
2376  $product_type = $type;
2377  }
2378 
2379  $line->oldline = $staticline;
2380  $line->context = $this->context;
2381 
2382  $line->description = $desc;
2383 
2384  $line->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs($qty) : $qty); // For credit note, quantity is always positive and unit price negative
2385  $line->subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2386  $line->pu_ht = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2387  $line->pu_ttc = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ttc) : $pu_ttc); // For credit note, unit price always negative, always positive otherwise
2388 
2389  $line->remise_percent = $remise_percent;
2390  $line->ref_supplier = $ref_supplier;
2391 
2392  $line->date_start = $date_start;
2393  $line->date_end = $date_end;
2394 
2395  $line->vat_src_code = $vat_src_code;
2396  $line->tva_tx = $vatrate;
2397  $line->localtax1_tx = $txlocaltax1;
2398  $line->localtax2_tx = $txlocaltax2;
2399  $line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
2400  $line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
2401 
2402  $line->total_ht = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_ht) : $total_ht);
2403  $line->total_tva = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_tva) : $total_tva);
2404  $line->total_localtax1 = $total_localtax1;
2405  $line->total_localtax2 = $total_localtax2;
2406  $line->total_ttc = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_ttc) : $total_ttc);
2407 
2408  $line->fk_product = $idproduct;
2409  $line->product_type = $product_type;
2410  $line->info_bits = $info_bits;
2411  $line->fk_unit = $fk_unit;
2412  $line->rang = $rang;
2413 
2414  if (is_array($array_options) && count($array_options) > 0) {
2415  // We replace values in this->line->array_options only for entries defined into $array_options
2416  foreach ($array_options as $key => $value) {
2417  $line->array_options[$key] = $array_options[$key];
2418  }
2419  }
2420 
2421  // Multicurrency
2422  $line->multicurrency_subprice = $pu_ht_devise;
2423  $line->multicurrency_total_ht = $multicurrency_total_ht;
2424  $line->multicurrency_total_tva = $multicurrency_total_tva;
2425  $line->multicurrency_total_ttc = $multicurrency_total_ttc;
2426 
2427  $res = $line->update($notrigger);
2428 
2429  if ($res < 1) {
2430  $this->errors[] = $line->error;
2431  } else {
2432  // Update total price into invoice record
2433  $res = $this->update_price('1', 'auto', 0, $this->thirdparty);
2434  }
2435 
2436  return $res;
2437  }
2438 
2446  public function deleteline($rowid, $notrigger = 0)
2447  {
2448  if (!$rowid) {
2449  $rowid = $this->id;
2450  }
2451 
2452  $this->db->begin();
2453 
2454  // Free the discount linked to a line of invoice
2455  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
2456  $sql .= ' SET fk_invoice_supplier_line = NULL';
2457  $sql .= ' WHERE fk_invoice_supplier_line = '.((int) $rowid);
2458 
2459  dol_syslog(get_class($this)."::deleteline", LOG_DEBUG);
2460  $result = $this->db->query($sql);
2461  if (!$result) {
2462  $this->error = $this->db->error();
2463  $this->db->rollback();
2464  return -2;
2465  }
2466 
2467  $line = new SupplierInvoiceLine($this->db);
2468 
2469  if ($line->fetch($rowid) < 1) {
2470  return -1;
2471  }
2472 
2473  $res = $line->delete($notrigger);
2474 
2475  if ($res < 1) {
2476  $this->errors[] = $line->error;
2477  $this->db->rollback();
2478  return -3;
2479  } else {
2480  $res = $this->update_price(1);
2481 
2482  if ($res > 0) {
2483  $this->db->commit();
2484  return 1;
2485  } else {
2486  $this->db->rollback();
2487  $this->error = $this->db->lasterror();
2488  return -4;
2489  }
2490  }
2491  }
2492 
2493 
2500  public function info($id)
2501  {
2502  $sql = 'SELECT c.rowid, datec, tms as datem, ';
2503  $sql .= ' fk_user_author, fk_user_modif, fk_user_valid';
2504  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as c';
2505  $sql .= ' WHERE c.rowid = '.((int) $id);
2506 
2507  $result = $this->db->query($sql);
2508  if ($result) {
2509  if ($this->db->num_rows($result)) {
2510  $obj = $this->db->fetch_object($result);
2511 
2512  $this->id = $obj->rowid;
2513  if ($obj->fk_user_author) {
2514  $cuser = new User($this->db);
2515  $cuser->fetch($obj->fk_user_author);
2516  $this->user_creation = $cuser;
2517  }
2518  if ($obj->fk_user_valid) {
2519  $vuser = new User($this->db);
2520  $vuser->fetch($obj->fk_user_valid);
2521  $this->user_validation = $vuser;
2522  }
2523  if ($obj->fk_user_modif) {
2524  $muser = new User($this->db);
2525  $muser->fetch($obj->fk_user_modif);
2526  $this->user_modification = $muser;
2527  }
2528  $this->date_creation = $this->db->jdate($obj->datec);
2529  $this->date_modification = $this->db->jdate($obj->datem);
2530  //$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)
2531  }
2532  $this->db->free($result);
2533  } else {
2534  dol_print_error($this->db);
2535  }
2536  }
2537 
2538  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2547  public function list_replacable_supplier_invoices($socid = 0)
2548  {
2549  // phpcs:enable
2550  global $conf;
2551 
2552  $return = array();
2553 
2554  $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut,";
2555  $sql .= " ff.rowid as rowidnext";
2556  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2557  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2558  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture_fourn as ff ON f.rowid = ff.fk_facture_source";
2559  $sql .= " WHERE (f.fk_statut = ".self::STATUS_VALIDATED." OR (f.fk_statut = ".self::STATUS_ABANDONED." AND f.close_code = '".self::CLOSECODE_ABANDONED."'))";
2560  $sql .= " AND f.entity = ".$conf->entity;
2561  $sql .= " AND f.paye = 0"; // Pas classee payee completement
2562  $sql .= " AND pf.fk_paiementfourn IS NULL"; // Aucun paiement deja fait
2563  $sql .= " AND ff.fk_statut IS NULL"; // Renvoi vrai si pas facture de remplacement
2564  if ($socid > 0) {
2565  $sql .= " AND f.fk_soc = ".((int) $socid);
2566  }
2567  $sql .= " ORDER BY f.ref";
2568 
2569  dol_syslog(get_class($this)."::list_replacable_supplier_invoices", LOG_DEBUG);
2570  $resql = $this->db->query($sql);
2571  if ($resql) {
2572  while ($obj = $this->db->fetch_object($resql)) {
2573  $return[$obj->rowid] = array(
2574  'id' => $obj->rowid,
2575  'ref' => $obj->ref,
2576  'status' => $obj->fk_statut
2577  );
2578  }
2579  //print_r($return);
2580  return $return;
2581  } else {
2582  $this->error = $this->db->error();
2583  return -1;
2584  }
2585  }
2586 
2587  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2597  public function list_qualified_avoir_supplier_invoices($socid = 0)
2598  {
2599  // phpcs:enable
2600  global $conf;
2601 
2602  $return = array();
2603 
2604  $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.paye, pf.fk_paiementfourn";
2605  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2606  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2607  $sql .= " WHERE f.entity = ".$conf->entity;
2608  $sql .= " AND f.fk_statut in (".self::STATUS_VALIDATED.",".self::STATUS_CLOSED.")";
2609  $sql .= " AND NOT EXISTS (SELECT rowid from ".MAIN_DB_PREFIX."facture_fourn as ff WHERE f.rowid = ff.fk_facture_source";
2610  $sql .= " AND ff.type=".self::TYPE_REPLACEMENT.")";
2611  $sql .= " AND f.type != ".self::TYPE_CREDIT_NOTE; // Type non 2 si facture non avoir
2612  if ($socid > 0) {
2613  $sql .= " AND f.fk_soc = ".((int) $socid);
2614  }
2615  $sql .= " ORDER BY f.ref";
2616 
2617  dol_syslog(get_class($this)."::list_qualified_avoir_supplier_invoices", LOG_DEBUG);
2618  $resql = $this->db->query($sql);
2619  if ($resql) {
2620  while ($obj = $this->db->fetch_object($resql)) {
2621  $qualified = 0;
2622  if ($obj->fk_statut == self::STATUS_VALIDATED) {
2623  $qualified = 1;
2624  }
2625  if ($obj->fk_statut == self::STATUS_CLOSED) {
2626  $qualified = 1;
2627  }
2628  if ($qualified) {
2629  $paymentornot = ($obj->fk_paiementfourn ? 1 : 0);
2630  $return[$obj->rowid] = array('ref'=>$obj->ref, 'status'=>$obj->fk_statut, 'type'=>$obj->type, 'paye'=>$obj->paye, 'paymentornot'=>$paymentornot);
2631  }
2632  }
2633 
2634  return $return;
2635  } else {
2636  $this->error = $this->db->error();
2637  return -1;
2638  }
2639  }
2640 
2641  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2648  public function load_board($user)
2649  {
2650  // phpcs:enable
2651  global $conf, $langs;
2652 
2653  $sql = 'SELECT ff.rowid, ff.date_lim_reglement as datefin, ff.fk_statut as status, ff.total_ht, ff.total_ttc';
2654  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as ff';
2655  if (!$user->hasRight("societe", "client", "voir") && !$user->socid) {
2656  $sql .= " JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ff.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
2657  }
2658  $sql .= ' WHERE ff.paye = 0';
2659  $sql .= ' AND ff.fk_statut > 0';
2660  $sql .= " AND ff.entity = ".$conf->entity;
2661  if ($user->socid) {
2662  $sql .= ' AND ff.fk_soc = '.((int) $user->socid);
2663  }
2664 
2665  $resql = $this->db->query($sql);
2666  if ($resql) {
2667  $langs->load("bills");
2668  $now = dol_now();
2669 
2670  $response = new WorkboardResponse();
2671  $response->warning_delay = $conf->facture->fournisseur->warning_delay / 60 / 60 / 24;
2672  $response->label = $langs->trans("SupplierBillsToPay");
2673  $response->labelShort = $langs->trans("StatusToPay");
2674 
2675  $response->url = DOL_URL_ROOT.'/fourn/facture/list.php?search_status=1&mainmenu=billing&leftmenu=suppliers_bills';
2676  $response->img = img_object($langs->trans("Bills"), "bill");
2677 
2678  $facturestatic = new FactureFournisseur($this->db);
2679 
2680  while ($obj = $this->db->fetch_object($resql)) {
2681  $facturestatic->date_echeance = $this->db->jdate($obj->datefin);
2682  $facturestatic->statut = $obj->status; // For backward compatibility
2683  $facturestatic->status = $obj->status;
2684 
2685  $response->nbtodo++;
2686  $response->total += $obj->total_ht;
2687 
2688  if ($facturestatic->hasDelay()) {
2689  $response->nbtodolate++;
2690  $response->url_late = DOL_URL_ROOT.'/fourn/facture/list.php?search_option=late&mainmenu=billing&leftmenu=suppliers_bills';
2691  }
2692  }
2693 
2694  $this->db->free($resql);
2695  return $response;
2696  } else {
2697  dol_print_error($this->db);
2698  $this->error = $this->db->error();
2699  return -1;
2700  }
2701  }
2702 
2710  public function getTooltipContentArray($params)
2711  {
2712  global $conf, $langs;
2713 
2714  $langs->load('bills');
2715 
2716  $datas = [];
2717  $moretitle = $params['moretitle'] ?? '';
2718  $picto = $this->picto;
2719  if ($this->type == self::TYPE_REPLACEMENT) {
2720  $picto .= 'r'; // Replacement invoice
2721  }
2722  if ($this->type == self::TYPE_CREDIT_NOTE) {
2723  $picto .= 'a'; // Credit note
2724  }
2725  if ($this->type == self::TYPE_DEPOSIT) {
2726  $picto .= 'd'; // Deposit invoice
2727  }
2728 
2729  $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("SupplierInvoice").'</u>';
2730  if ($this->type == self::TYPE_REPLACEMENT) {
2731  $datas['picto'] .= '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("InvoiceReplace").'</u>';
2732  } elseif ($this->type == self::TYPE_CREDIT_NOTE) {
2733  $datas['picto'] .= '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("CreditNote").'</u>';
2734  } elseif ($this->type == self::TYPE_DEPOSIT) {
2735  $datas['picto'] .= '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("Deposit").'</u>';
2736  }
2737  if (isset($this->status)) {
2738  $alreadypaid = -1;
2739  if (isset($this->alreadypaid)) {
2740  $alreadypaid = $this->alreadypaid;
2741  }
2742 
2743  $datas['picto'] .= ' '.$this->getLibStatut(5, $alreadypaid);
2744  }
2745  if ($moretitle) {
2746  $datas['picto'] .= ' - '.$moretitle;
2747  }
2748  if (!empty($this->ref)) {
2749  $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
2750  }
2751  if (!empty($this->ref_supplier)) {
2752  $datas['refsupplier'] = '<br><b>'.$langs->trans('RefSupplier').':</b> '.$this->ref_supplier;
2753  }
2754  if (!empty($this->label)) {
2755  $datas['label'] = '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
2756  }
2757  if (!empty($this->date)) {
2758  $datas['date'] = '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
2759  }
2760  if (!empty($this->date_echeance)) {
2761  $datas['date_echeance'] = '<br><b>'.$langs->trans('DateDue').':</b> '.dol_print_date($this->date_echeance, 'day');
2762  }
2763  if (!empty($this->total_ht)) {
2764  $datas['amountht'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
2765  }
2766  if (!empty($this->total_tva)) {
2767  $datas['totaltva'] = '<br><b>'.$langs->trans('AmountVAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
2768  }
2769  if (!empty($this->total_ttc)) {
2770  $datas['totalttc'] = '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
2771  }
2772  return $datas;
2773  }
2774 
2788  public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
2789  {
2790  global $langs, $conf, $user, $hookmanager;
2791 
2792  $result = '';
2793 
2794  if ($option == 'withdraw') {
2795  $url = DOL_URL_ROOT.'/compta/facture/prelevement.php?facid='.$this->id.'&type=bank-transfer';
2796  } elseif ($option == 'document') {
2797  $url = DOL_URL_ROOT.'/fourn/facture/document.php?facid='.$this->id;
2798  } else {
2799  $url = DOL_URL_ROOT.'/fourn/facture/card.php?facid='.$this->id;
2800  }
2801 
2802  if ($short) {
2803  return $url;
2804  }
2805 
2806  if ($option !== 'nolink') {
2807  // Add param to save lastsearch_values or not
2808  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
2809  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
2810  $add_save_lastsearch_values = 1;
2811  }
2812  if ($add_save_lastsearch_values) {
2813  $url .= '&save_lastsearch_values=1';
2814  }
2815  }
2816 
2817  $picto = $this->picto;
2818  if ($this->type == self::TYPE_REPLACEMENT) {
2819  $picto .= 'r'; // Replacement invoice
2820  }
2821  if ($this->type == self::TYPE_CREDIT_NOTE) {
2822  $picto .= 'a'; // Credit note
2823  }
2824  if ($this->type == self::TYPE_DEPOSIT) {
2825  $picto .= 'd'; // Deposit invoice
2826  }
2827  $params = [
2828  'id' => $this->id,
2829  'objecttype' => $this->element,
2830  'option' => $option,
2831  'moretitle' => $moretitle,
2832  ];
2833  $classfortooltip = 'classfortooltip';
2834  $dataparams = '';
2835  if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
2836  $classfortooltip = 'classforajaxtooltip';
2837  $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
2838  $label = '';
2839  } else {
2840  $label = implode($this->getTooltipContentArray($params));
2841  }
2842 
2843  $ref = $this->ref;
2844  if (empty($ref)) {
2845  $ref = $this->id;
2846  }
2847 
2848  $linkclose = '';
2849  if (empty($notooltip)) {
2850  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2851  $label = $langs->trans("ShowSupplierInvoice");
2852  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
2853  }
2854  $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
2855  $linkclose .= $dataparams.' class="'.$classfortooltip.'"';
2856  }
2857 
2858  $linkstart = '<a href="'.$url.'"';
2859  $linkstart .= $linkclose.'>';
2860  $linkend = '</a>';
2861 
2862  $result .= $linkstart;
2863  if ($withpicto) {
2864  $result .= img_object(($notooltip ? '' : $label), $picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : $dataparams.' class="'.(($withpicto != 2) ? 'paddingright ' : '').$classfortooltip.'"'), 0, 0, $notooltip ? 0 : 1);
2865  }
2866  if ($withpicto != 2) {
2867  $result .= ($max ?dol_trunc($ref, $max) : $ref);
2868  }
2869  $result .= $linkend;
2870 
2871  if ($addlinktonotes) {
2872  $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
2873  if ($txttoshow) {
2874  $notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
2875  $result .= ' <span class="note inline-block">';
2876  $result .= '<a href="'.DOL_URL_ROOT.'/fourn/facture/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
2877  $result .= img_picto('', 'note');
2878  $result .= '</a>';
2879  $result .= '</span>';
2880  }
2881  }
2882  global $action;
2883  $hookmanager->initHooks(array($this->element . 'dao'));
2884  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
2885  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2886  if ($reshook > 0) {
2887  $result = $hookmanager->resPrint;
2888  } else {
2889  $result .= $hookmanager->resPrint;
2890  }
2891  return $result;
2892  }
2893 
2902  public function getNextNumRef($soc, $mode = 'next')
2903  {
2904  global $db, $langs, $conf;
2905  $langs->load("orders");
2906 
2907  // Clean parameters (if not defined or using deprecated value)
2908  if (empty($conf->global->INVOICE_SUPPLIER_ADDON_NUMBER)) {
2909  $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER = 'mod_facture_fournisseur_cactus';
2910  }
2911 
2912  $mybool = false;
2913 
2914  $file = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER.".php";
2915  $classname = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER;
2916 
2917  // Include file with class
2918  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2919 
2920  foreach ($dirmodels as $reldir) {
2921  $dir = dol_buildpath($reldir."core/modules/supplier_invoice/");
2922 
2923  // Load file with numbering class (if found)
2924  $mybool |= @include_once $dir.$file;
2925  }
2926 
2927  if ($mybool === false) {
2928  dol_print_error('', "Failed to include file ".$file);
2929  return '';
2930  }
2931 
2932  $obj = new $classname();
2933  $numref = "";
2934  $numref = $obj->getNumRef($soc, $this, $mode);
2935 
2936  if ($numref != "") {
2937  return $numref;
2938  } else {
2939  $this->error = $obj->error;
2940  return -1;
2941  }
2942  }
2943 
2944 
2953  public function initAsSpecimen($option = '')
2954  {
2955  global $langs, $conf;
2956  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
2957 
2958  $now = dol_now();
2959 
2960  // Load array of products prodids
2961  $num_prods = 0;
2962  $prodids = array();
2963 
2964  $sql = "SELECT rowid";
2965  $sql .= " FROM ".MAIN_DB_PREFIX."product";
2966  $sql .= " WHERE entity IN (".getEntity('product').")";
2967  $sql .= $this->db->plimit(100);
2968 
2969  $resql = $this->db->query($sql);
2970  if ($resql) {
2971  $num_prods = $this->db->num_rows($resql);
2972  $i = 0;
2973  while ($i < $num_prods) {
2974  $i++;
2975  $row = $this->db->fetch_row($resql);
2976  $prodids[$i] = $row[0];
2977  }
2978  }
2979 
2980  // Initialise parametres
2981  $this->id = 0;
2982  $this->ref = 'SPECIMEN';
2983  $this->ref_supplier = 'SUPPLIER_REF_SPECIMEN';
2984  $this->specimen = 1;
2985  $this->socid = 1;
2986  $this->date = $now;
2987  $this->date_lim_reglement = $this->date + 3600 * 24 * 30;
2988  $this->cond_reglement_code = 'RECEP';
2989  $this->mode_reglement_code = 'CHQ';
2990 
2991  $this->note_public = 'This is a comment (public)';
2992  $this->note_private = 'This is a comment (private)';
2993 
2994  $this->multicurrency_tx = 1;
2995  $this->multicurrency_code = $conf->currency;
2996 
2997  $xnbp = 0;
2998  if (empty($option) || $option != 'nolines') {
2999  // Lines
3000  $nbp = 5;
3001  while ($xnbp < $nbp) {
3002  $line = new SupplierInvoiceLine($this->db);
3003  $line->desc = $langs->trans("Description")." ".$xnbp;
3004  $line->qty = 1;
3005  $line->subprice = 100;
3006  $line->pu_ht = 100; // the canelle template use pu_ht and not subprice
3007  $line->price = 100;
3008  $line->tva_tx = 19.6;
3009  $line->localtax1_tx = 0;
3010  $line->localtax2_tx = 0;
3011  if ($xnbp == 2) {
3012  $line->total_ht = 50;
3013  $line->total_ttc = 59.8;
3014  $line->total_tva = 9.8;
3015  $line->remise_percent = 50;
3016  } else {
3017  $line->total_ht = 100;
3018  $line->total_ttc = 119.6;
3019  $line->total_tva = 19.6;
3020  $line->remise_percent = 0;
3021  }
3022 
3023  if ($num_prods > 0) {
3024  $prodid = mt_rand(1, $num_prods);
3025  $line->fk_product = $prodids[$prodid];
3026  }
3027  $line->product_type = 0;
3028 
3029  $this->lines[$xnbp] = $line;
3030 
3031  $this->total_ht += $line->total_ht;
3032  $this->total_tva += $line->total_tva;
3033  $this->total_ttc += $line->total_ttc;
3034 
3035  $xnbp++;
3036  }
3037  }
3038 
3039  $this->amount_ht = $xnbp * 100;
3040  $this->total_ht = $xnbp * 100;
3041  $this->total_tva = $xnbp * 19.6;
3042  $this->total_ttc = $xnbp * 119.6;
3043  }
3044 
3045  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3051  public function load_state_board()
3052  {
3053  // phpcs:enable
3054  global $conf, $user;
3055 
3056  $this->nb = array();
3057 
3058  $clause = "WHERE";
3059 
3060  $sql = "SELECT count(f.rowid) as nb";
3061  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
3062  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
3063  if (!$user->hasRight("societe", "client", "voir") && !$user->socid) {
3064  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
3065  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3066  $clause = "AND";
3067  }
3068  $sql .= " ".$clause." f.entity = ".$conf->entity;
3069 
3070  $resql = $this->db->query($sql);
3071  if ($resql) {
3072  while ($obj = $this->db->fetch_object($resql)) {
3073  $this->nb["supplier_invoices"] = $obj->nb;
3074  }
3075  $this->db->free($resql);
3076  return 1;
3077  } else {
3078  dol_print_error($this->db);
3079  $this->error = $this->db->error();
3080  return -1;
3081  }
3082  }
3083 
3092  public function createFromClone(User $user, $fromid, $invertdetail = 0)
3093  {
3094  global $conf, $langs;
3095 
3096  $error = 0;
3097 
3098  $object = new FactureFournisseur($this->db);
3099 
3100  $this->db->begin();
3101 
3102  // Load source object
3103  $object->fetch($fromid);
3104  $object->id = 0;
3105  $object->statut = self::STATUS_DRAFT; // For backward compatibility
3106  $object->status = self::STATUS_DRAFT;
3107 
3108  $object->fetch_thirdparty(); // We need it to recalculate VAT localtaxes according to main sale taxes and vendor
3109 
3110  // Clear fields
3111  $object->ref_supplier = (empty($this->ref_supplier) ? $langs->trans("CopyOf").' '.$object->ref_supplier : $this->ref_supplier);
3112  $object->author = $user->id;
3113  $object->user_valid = 0;
3114  $object->fk_facture_source = 0;
3115  $object->date_creation = '';
3116  $object->date_validation = '';
3117  $object->date = (empty($this->date) ? dol_now() : $this->date);
3118  $object->ref_client = '';
3119  $object->close_code = '';
3120  $object->close_note = '';
3121  if (getDolGlobalInt('MAIN_DONT_KEEP_NOTE_ON_CLONING') == 1) {
3122  $object->note_private = '';
3123  $object->note_public = '';
3124  }
3125 
3126  $object->date_echeance = $object->calculate_date_lim_reglement();
3127 
3128  // Loop on each line of new invoice
3129  foreach ($object->lines as $i => $line) {
3130  if (isset($object->lines[$i]->info_bits) && ($object->lines[$i]->info_bits & 0x02) == 0x02) { // We do not clone line of discounts
3131  unset($object->lines[$i]);
3132  }
3133  }
3134 
3135  // Create clone
3136  $object->context['createfromclone'] = 'createfromclone';
3137  $result = $object->create($user);
3138 
3139  // Other options
3140  if ($result < 0) {
3141  $this->error = $object->error;
3142  $this->errors = $object->errors;
3143  $error++;
3144  }
3145 
3146  if (!$error) {
3147  }
3148 
3149  unset($object->context['createfromclone']);
3150 
3151  // End
3152  if (!$error) {
3153  $this->db->commit();
3154  return $object->id;
3155  } else {
3156  $this->db->rollback();
3157  return -1;
3158  }
3159  }
3160 
3172  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
3173  {
3174  global $conf, $user, $langs;
3175 
3176  $langs->load("suppliers");
3177  $outputlangs->load("products");
3178 
3179  // Set the model on the model name to use
3180  if (empty($modele)) {
3181  if (!empty($conf->global->INVOICE_SUPPLIER_ADDON_PDF)) {
3182  $modele = $conf->global->INVOICE_SUPPLIER_ADDON_PDF;
3183  } else {
3184  $modele = ''; // No default value. For supplier invoice, we allow to disable all PDF generation
3185  }
3186  }
3187 
3188  if (empty($modele)) {
3189  return 0;
3190  } else {
3191  $modelpath = "core/modules/supplier_invoice/doc/";
3192 
3193  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
3194  }
3195  }
3196 
3201  public function getRights()
3202  {
3203  global $user;
3204 
3205  return $user->hasRight("fournisseur", "facture");
3206  }
3207 
3216  public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
3217  {
3218  $tables = array(
3219  'facture_fourn'
3220  );
3221 
3222  return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
3223  }
3224 
3233  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
3234  {
3235  $tables = array(
3236  'facture_fourn_det'
3237  );
3238 
3239  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
3240  }
3241 
3247  public function hasDelay()
3248  {
3249  global $conf;
3250 
3251  $now = dol_now();
3252 
3253  if (!$this->date_echeance) {
3254  return false;
3255  }
3256 
3257  $status = isset($this->status) ? $this->status : $this->statut;
3258 
3259  return ($status == self::STATUS_VALIDATED) && ($this->date_echeance < ($now - $conf->facture->fournisseur->warning_delay));
3260  }
3261 
3267  public function isCreditNoteUsed()
3268  {
3269  $isUsed = false;
3270 
3271  $sql = "SELECT fk_invoice_supplier FROM ".MAIN_DB_PREFIX."societe_remise_except WHERE fk_invoice_supplier_source = ".((int) $this->id);
3272  $resql = $this->db->query($sql);
3273  if (!empty($resql)) {
3274  $obj = $this->db->fetch_object($resql);
3275  if (!empty($obj->fk_invoice_supplier)) {
3276  $isUsed = true;
3277  }
3278  }
3279 
3280  return $isUsed;
3281  }
3289  public function getKanbanView($option = '', $arraydata = null)
3290  {
3291  global $langs;
3292 
3293  $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
3294 
3295  $return = '<div class="box-flex-item box-flex-grow-zero">';
3296  $return .= '<div class="info-box info-box-sm">';
3297  $return .= '<span class="info-box-icon bg-infobox-action">';
3298  $return .= img_picto('', $this->picto);
3299  $return .= '</span>';
3300  $return .= '<div class="info-box-content">';
3301  $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
3302  $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
3303  if (!empty($arraydata['thirdparty'])) {
3304  $return .= '<br><span class="info-box-label">'.$arraydata['thirdparty'].'</span>';
3305  }
3306  if (property_exists($this, 'date')) {
3307  $return .= '<br><span class="info-box-label">'.dol_print_date($this->date, 'day').'</span>';
3308  }
3309  if (property_exists($this, 'total_ht')) {
3310  $return .= ' &nbsp; <span class="info-box-label amount" title="'.dol_escape_htmltag($langs->trans("AmountHT")).'">'.price($this->total_ht);
3311  $return .= ' '.$langs->trans("HT");
3312  $return .= '</span>';
3313  }
3314  if (method_exists($this, 'getLibStatut')) {
3315  $alreadypaid = (empty($arraydata['alreadypaid']) ? 0 : $arraydata['alreadypaid']);
3316  $return .= '<br><div class="info-box-status margintoponly">'.$this->getLibStatut(3, $alreadypaid).'</div>';
3317  }
3318  $return .= '</div>';
3319  $return .= '</div>';
3320  $return .= '</div>';
3321  return $return;
3322  }
3323 
3330  public function setVATReverseCharge($vatreversecharge)
3331  {
3332  if (!$this->table_element) {
3333  dol_syslog(get_class($this)."::setVATReverseCharge was called on objet with property table_element not defined", LOG_ERR);
3334  return -1;
3335  }
3336 
3337  dol_syslog(get_class($this).'::setVATReverseCharge('.$vatreversecharge.')');
3338 
3339  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3340  $sql .= " SET vat_reverse_charge = ".((int) $vatreversecharge);
3341  $sql .= " WHERE rowid=".((int) $this->id);
3342 
3343  if ($this->db->query($sql)) {
3344  $this->vat_reverse_charge = ($vatreversecharge == 0) ? 0 : 1;
3345  return 1;
3346  } else {
3347  dol_syslog(get_class($this).'::setVATReverseCharge Error ', LOG_DEBUG);
3348  $this->error = $this->db->error();
3349  return 0;
3350  }
3351  }
3352 }
3353 
3354 
3355 
3360 {
3364  public $element = 'facture_fourn_det';
3365 
3369  public $table_element = 'facture_fourn_det';
3370 
3371  public $oldline;
3372 
3377  public $ref;
3378 
3383  public $product_ref;
3384 
3390  public $ref_supplier;
3391 
3396  public $product_desc;
3397 
3404  public $pu_ht;
3405 
3410  public $subprice;
3411 
3416  public $pu_ttc;
3417 
3418 
3423  public $fk_facture_fourn;
3424 
3430  public $label;
3431 
3436  public $description;
3437 
3438  public $date_start;
3439  public $date_end;
3440 
3441  public $skip_update_total; // Skip update price total for special lines
3442 
3446  public $situation_percent;
3447 
3451  public $fk_prev_id;
3452 
3457  public $vat_src_code;
3458 
3463  public $tva_tx;
3464 
3469  public $localtax1_tx;
3470 
3475  public $localtax2_tx;
3476 
3481  public $qty;
3482 
3487  public $remise_percent;
3488 
3493  public $pa_ht;
3494 
3499  public $total_ht;
3500 
3505  public $total_ttc;
3506 
3511  public $total_tva;
3512 
3517  public $total_localtax1;
3518 
3523  public $total_localtax2;
3524 
3528  public $fk_product;
3529 
3534  public $product_type;
3535 
3540  public $product_label;
3541 
3548  public $info_bits;
3549 
3554  public $fk_remise_except;
3555 
3559  public $fk_parent_line;
3560 
3561  public $special_code;
3562 
3566  public $rang;
3567 
3572  public $localtax1_type;
3573 
3578  public $localtax2_type;
3579 
3580  // Multicurrency
3584  public $fk_multicurrency;
3585 
3586  public $multicurrency_code;
3587  public $multicurrency_subprice;
3588  public $multicurrency_total_ht;
3589  public $multicurrency_total_tva;
3590  public $multicurrency_total_ttc;
3591 
3592 
3598  public function __construct($db)
3599  {
3600  $this->db = $db;
3601  }
3602 
3609  public function fetch($rowid)
3610  {
3611  $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';
3612  $sql .= ', f.localtax1_type, f.localtax2_type, f.localtax1_tx, f.localtax2_tx, f.total_localtax1, f.total_localtax2, f.fk_remise_except';
3613  $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';
3614  $sql .= ', p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.description as product_desc';
3615  $sql .= ', f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, multicurrency_total_ttc';
3616  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
3617  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
3618  $sql .= ' WHERE f.rowid = '.((int) $rowid);
3619  $sql .= ' ORDER BY f.rang, f.rowid';
3620 
3621  $query = $this->db->query($sql);
3622 
3623  if (!$query) {
3624  $this->errors[] = $this->db->error();
3625  return -1;
3626  }
3627 
3628  if (!$this->db->num_rows($query)) {
3629  return 0;
3630  }
3631 
3632  $obj = $this->db->fetch_object($query);
3633 
3634  $this->id = $obj->rowid;
3635  $this->rowid = $obj->rowid;
3636  $this->fk_facture_fourn = $obj->fk_facture_fourn;
3637  $this->description = $obj->description;
3638  $this->date_start = $obj->date_start;
3639  $this->date_end = $obj->date_end;
3640  $this->product_ref = $obj->product_ref;
3641  $this->ref_supplier = $obj->ref_supplier;
3642  $this->product_desc = $obj->product_desc;
3643 
3644  $this->subprice = $obj->pu_ht;
3645  $this->pu_ht = $obj->pu_ht;
3646  $this->pu_ttc = $obj->pu_ttc;
3647  $this->tva_tx = $obj->tva_tx;
3648  $this->localtax1_tx = $obj->localtax1_tx;
3649  $this->localtax2_tx = $obj->localtax2_tx;
3650  $this->localtax1_type = $obj->localtax1_type;
3651  $this->localtax2_type = $obj->localtax2_type;
3652 
3653  $this->qty = $obj->qty;
3654  $this->remise_percent = $obj->remise_percent;
3655  $this->fk_remise_except = $obj->fk_remise_except;
3656  //$this->tva = $obj->total_tva; // deprecated
3657  $this->total_ht = $obj->total_ht;
3658  $this->total_tva = $obj->total_tva;
3659  $this->total_localtax1 = $obj->total_localtax1;
3660  $this->total_localtax2 = $obj->total_localtax2;
3661  $this->total_ttc = $obj->total_ttc;
3662  $this->fk_product = $obj->fk_product;
3663  $this->product_type = $obj->product_type;
3664  $this->product_label = $obj->product_label;
3665  $this->info_bits = $obj->info_bits;
3666  $this->tva_npr = ($obj->info_bits & 1 == 1) ? 1 : 0;
3667  $this->fk_parent_line = $obj->fk_parent_line;
3668  $this->special_code = $obj->special_code;
3669  $this->rang = $obj->rang;
3670  $this->fk_unit = $obj->fk_unit;
3671 
3672  $this->multicurrency_subprice = $obj->multicurrency_subprice;
3673  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
3674  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
3675  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
3676 
3677  $this->fetch_optionals();
3678 
3679  return 1;
3680  }
3681 
3688  public function delete($notrigger = 0)
3689  {
3690  global $user, $conf;
3691 
3692  dol_syslog(get_class($this)."::deleteline rowid=".((int) $this->id), LOG_DEBUG);
3693 
3694  $error = 0;
3695 
3696  $this->db->begin();
3697 
3698  if (!$notrigger) {
3699  if ($this->call_trigger('LINEBILL_SUPPLIER_DELETE', $user) < 0) {
3700  $error++;
3701  }
3702  }
3703 
3704  $this->deleteObjectLinked();
3705 
3706  // Remove extrafields
3707  if (!$error) {
3708  $result = $this->deleteExtraFields();
3709  if ($result < 0) {
3710  $error++;
3711  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
3712  }
3713  }
3714 
3715  if (!$error) {
3716  // Supprime ligne
3717  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det ';
3718  $sql .= " WHERE rowid = ".((int) $this->id);
3719  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
3720  $resql = $this->db->query($sql);
3721  if (!$resql) {
3722  $error++;
3723  $this->error = $this->db->lasterror();
3724  }
3725  }
3726 
3727  if (!$error) {
3728  $this->db->commit();
3729  return 1;
3730  } else {
3731  $this->db->rollback();
3732  return -1;
3733  }
3734  }
3735 
3742  public function update($notrigger = 0)
3743  {
3744  global $conf;
3745 
3746  $pu = price2num($this->pu_ht);
3747  $qty = price2num($this->qty);
3748 
3749  // Check parameters
3750  if (empty($this->qty)) {
3751  $this->qty = 0;
3752  }
3753 
3754  if ($this->product_type < 0) {
3755  return -1;
3756  }
3757 
3758  // Clean parameters
3759  if (empty($this->remise_percent)) {
3760  $this->remise_percent = 0;
3761  }
3762  if (empty($this->tva_tx)) {
3763  $this->tva_tx = 0;
3764  }
3765  if (empty($this->localtax1_tx)) {
3766  $this->localtax1_tx = 0;
3767  }
3768  if (empty($this->localtax2_tx)) {
3769  $this->localtax2_tx = 0;
3770  }
3771 
3772  if (empty($this->pa_ht)) {
3773  $this->pa_ht = 0;
3774  }
3775  if (empty($this->multicurrency_subprice)) {
3776  $this->multicurrency_subprice = 0;
3777  }
3778  if (empty($this->multicurrency_total_ht)) {
3779  $this->multicurrency_total_ht = 0;
3780  }
3781  if (empty($this->multicurrency_total_tva)) {
3782  $this->multicurrency_total_tva = 0;
3783  }
3784  if (empty($this->multicurrency_total_ttc)) {
3785  $this->multicurrency_total_ttc = 0;
3786  }
3787 
3788  $fk_product = (int) $this->fk_product;
3789  $fk_unit = (int) $this->fk_unit;
3790 
3791  $this->db->begin();
3792 
3793  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
3794  $sql .= " description = '".$this->db->escape($this->description)."'";
3795  $sql .= ", ref = '".$this->db->escape($this->ref_supplier ? $this->ref_supplier : $this->ref)."'";
3796  $sql .= ", date_start = ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : "null");
3797  $sql .= ", date_end = ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : "null");
3798  $sql .= ", pu_ht = ".price2num($this->pu_ht);
3799  $sql .= ", pu_ttc = ".price2num($this->pu_ttc);
3800  $sql .= ", qty = ".price2num($this->qty);
3801  $sql .= ", remise_percent = ".price2num($this->remise_percent);
3802  if ($this->fk_remise_except > 0) $sql .= ", fk_remise_except=".((int) $this->fk_remise_except);
3803  else $sql .= ", fk_remise_except=null";
3804  $sql .= ", vat_src_code = '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."'";
3805  $sql .= ", tva_tx = ".price2num($this->tva_tx);
3806  $sql .= ", localtax1_tx = ".price2num($this->localtax1_tx);
3807  $sql .= ", localtax2_tx = ".price2num($this->localtax2_tx);
3808  $sql .= ", localtax1_type = '".$this->db->escape($this->localtax1_type)."'";
3809  $sql .= ", localtax2_type = '".$this->db->escape($this->localtax2_type)."'";
3810  $sql .= ", total_ht = ".price2num($this->total_ht);
3811  $sql .= ", tva= ".price2num($this->total_tva);
3812  $sql .= ", total_localtax1= ".price2num($this->total_localtax1);
3813  $sql .= ", total_localtax2= ".price2num($this->total_localtax2);
3814  $sql .= ", total_ttc = ".price2num($this->total_ttc);
3815  $sql .= ", fk_product = ".($fk_product > 0 ? (int) $fk_product : 'null');
3816  $sql .= ", product_type = ".((int) $this->product_type);
3817  $sql .= ", info_bits = ".((int) $this->info_bits);
3818  $sql .= ", fk_unit = ".($fk_unit > 0 ? (int) $fk_unit : 'null');
3819 
3820  if (!empty($this->rang)) {
3821  $sql .= ", rang=".((int) $this->rang);
3822  }
3823 
3824  // Multicurrency
3825  $sql .= " , multicurrency_subprice=".price2num($this->multicurrency_subprice);
3826  $sql .= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht);
3827  $sql .= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva);
3828  $sql .= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc);
3829 
3830  $sql .= " WHERE rowid = ".((int) $this->id);
3831 
3832  dol_syslog(get_class($this)."::update", LOG_DEBUG);
3833  $resql = $this->db->query($sql);
3834 
3835  if (!$resql) {
3836  $this->db->rollback();
3837  $this->error = $this->db->lasterror();
3838  return -1;
3839  }
3840 
3841  $this->rowid = $this->id;
3842  $error = 0;
3843 
3844  if (!$error) {
3845  $result = $this->insertExtraFields();
3846  if ($result < 0) {
3847  $error++;
3848  }
3849  }
3850 
3851  if (!$error && !$notrigger) {
3852  global $langs, $user;
3853 
3854  // Call trigger
3855  if ($this->call_trigger('LINEBILL_SUPPLIER_MODIFY', $user) < 0) {
3856  $this->db->rollback();
3857  return -1;
3858  }
3859  // End call triggers
3860  }
3861 
3862  if ($error) {
3863  $this->db->rollback();
3864  return -1;
3865  }
3866 
3867  $this->db->commit();
3868  return 1;
3869  }
3870 
3877  public function insert($notrigger = 0)
3878  {
3879  global $user, $conf, $langs;
3880 
3881  $error = 0;
3882 
3883  dol_syslog(get_class($this)."::insert rang=".$this->rang, LOG_DEBUG);
3884 
3885  // Clean parameters
3886  $this->desc = trim($this->desc);
3887  if (empty($this->tva_tx)) {
3888  $this->tva_tx = 0;
3889  }
3890  if (empty($this->localtax1_tx)) {
3891  $this->localtax1_tx = 0;
3892  }
3893  if (empty($this->localtax2_tx)) {
3894  $this->localtax2_tx = 0;
3895  }
3896  if (empty($this->localtax1_type)) {
3897  $this->localtax1_type = '0';
3898  }
3899  if (empty($this->localtax2_type)) {
3900  $this->localtax2_type = '0';
3901  }
3902  if (empty($this->total_tva)) {
3903  $this->total_tva = 0;
3904  }
3905  if (empty($this->total_localtax1)) {
3906  $this->total_localtax1 = 0;
3907  }
3908  if (empty($this->total_localtax2)) {
3909  $this->total_localtax2 = 0;
3910  }
3911  if (empty($this->rang)) {
3912  $this->rang = 0;
3913  }
3914  if (empty($this->remise_percent)) {
3915  $this->remise_percent = 0;
3916  }
3917  if (empty($this->info_bits)) {
3918  $this->info_bits = 0;
3919  }
3920  if (empty($this->subprice)) {
3921  $this->subprice = 0;
3922  }
3923  if (empty($this->special_code)) {
3924  $this->special_code = 0;
3925  }
3926  if (empty($this->fk_parent_line)) {
3927  $this->fk_parent_line = 0;
3928  }
3929  if (!isset($this->situation_percent) || $this->situation_percent > 100 || (string) $this->situation_percent == '') {
3930  $this->situation_percent = 100;
3931  }
3932 
3933  if (empty($this->pa_ht)) {
3934  $this->pa_ht = 0;
3935  }
3936  if (empty($this->multicurrency_subprice)) {
3937  $this->multicurrency_subprice = 0;
3938  }
3939  if (empty($this->multicurrency_total_ht)) {
3940  $this->multicurrency_total_ht = 0;
3941  }
3942  if (empty($this->multicurrency_total_tva)) {
3943  $this->multicurrency_total_tva = 0;
3944  }
3945  if (empty($this->multicurrency_total_ttc)) {
3946  $this->multicurrency_total_ttc = 0;
3947  }
3948 
3949 
3950  // Check parameters
3951  if ($this->product_type < 0) {
3952  $this->error = 'ErrorProductTypeMustBe0orMore';
3953  return -1;
3954  }
3955  if (!empty($this->fk_product) && $this->fk_product > 0) {
3956  // Check product exists
3957  $result = Product::isExistingObject('product', $this->fk_product);
3958  if ($result <= 0) {
3959  $this->error = 'ErrorProductIdDoesNotExists';
3960  return -1;
3961  }
3962  }
3963 
3964  $this->db->begin();
3965 
3966  // Insertion dans base de la ligne
3967  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
3968  $sql .= ' (fk_facture_fourn, fk_parent_line, label, description, ref, qty,';
3969  $sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3970  $sql .= ' fk_product, product_type, remise_percent, fk_remise_except, pu_ht, pu_ttc,';
3971  $sql .= ' date_start, date_end, fk_code_ventilation, rang, special_code,';
3972  $sql .= ' info_bits, total_ht, tva, total_ttc, total_localtax1, total_localtax2, fk_unit';
3973  $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
3974  $sql .= ')';
3975  $sql .= " VALUES (".$this->fk_facture_fourn.",";
3976  $sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape($this->fk_parent_line)."'" : "null").",";
3977  $sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
3978  $sql .= " '".$this->db->escape($this->desc ? $this->desc : $this->description)."',";
3979  $sql .= " '".$this->db->escape($this->ref_supplier)."',";
3980  $sql .= " ".price2num($this->qty).",";
3981 
3982  $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape($this->vat_src_code)."'").",";
3983  $sql .= " ".price2num($this->tva_tx).",";
3984  $sql .= " ".price2num($this->localtax1_tx).",";
3985  $sql .= " ".price2num($this->localtax2_tx).",";
3986  $sql .= " '".$this->db->escape($this->localtax1_type)."',";
3987  $sql .= " '".$this->db->escape($this->localtax2_type)."',";
3988  $sql .= ' '.((!empty($this->fk_product) && $this->fk_product > 0) ? $this->fk_product : "null").',';
3989  $sql .= " ".((int) $this->product_type).",";
3990  $sql .= " ".price2num($this->remise_percent).",";
3991  $sql .= ' '.(!empty($this->fk_remise_except) ? ((int) $this->fk_remise_except) : "null").',';
3992  $sql .= " ".price2num($this->subprice).",";
3993  $sql .= " ".(!empty($this->qty) ?price2num($this->total_ttc / $this->qty) : price2num($this->total_ttc)).",";
3994  $sql .= " ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null").",";
3995  $sql .= " ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").",";
3996  $sql .= ' '.(!empty($this->fk_code_ventilation) ? $this->fk_code_ventilation : 0).',';
3997  $sql .= ' '.((int) $this->rang).',';
3998  $sql .= ' '.((int) $this->special_code).',';
3999  $sql .= " ".((int) $this->info_bits).",";
4000  $sql .= " ".price2num($this->total_ht).",";
4001  $sql .= " ".price2num($this->total_tva).",";
4002  $sql .= " ".price2num($this->total_ttc).",";
4003  $sql .= " ".price2num($this->total_localtax1).",";
4004  $sql .= " ".price2num($this->total_localtax2);
4005  $sql .= ", ".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
4006  $sql .= ", ".(int) $this->fk_multicurrency;
4007  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
4008  $sql .= ", ".price2num($this->multicurrency_subprice);
4009  $sql .= ", ".price2num($this->multicurrency_total_ht);
4010  $sql .= ", ".price2num($this->multicurrency_total_tva);
4011  $sql .= ", ".price2num($this->multicurrency_total_ttc);
4012  $sql .= ')';
4013 
4014  $resql = $this->db->query($sql);
4015  if ($resql) {
4016  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
4017  $this->rowid = $this->id; // backward compatibility
4018 
4019  if (!$error) {
4020  $result = $this->insertExtraFields();
4021  if ($result < 0) {
4022  $error++;
4023  }
4024  }
4025 
4026  // Si fk_remise_except defini, on lie la remise a la facture
4027  // ce qui la flague comme "consommee".
4028  if ($this->fk_remise_except) {
4029  $discount = new DiscountAbsolute($this->db);
4030  $result = $discount->fetch($this->fk_remise_except);
4031  if ($result >= 0) {
4032  // Check if discount was found
4033  if ($result > 0) {
4034  // Check if discount not already affected to another invoice
4035  if ($discount->fk_facture_line > 0) {
4036  if (empty($noerrorifdiscountalreadylinked)) {
4037  $this->error = $langs->trans("ErrorDiscountAlreadyUsed", $discount->id);
4038  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
4039  $this->db->rollback();
4040  return -3;
4041  }
4042  } else {
4043  $result = $discount->link_to_invoice($this->rowid, 0);
4044  if ($result < 0) {
4045  $this->error = $discount->error;
4046  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
4047  $this->db->rollback();
4048  return -3;
4049  }
4050  }
4051  } else {
4052  $this->error = $langs->trans("ErrorADiscountThatHasBeenRemovedIsIncluded");
4053  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
4054  $this->db->rollback();
4055  return -3;
4056  }
4057  } else {
4058  $this->error = $discount->error;
4059  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
4060  $this->db->rollback();
4061  return -3;
4062  }
4063  }
4064 
4065  if (!$error && !$notrigger) {
4066  // Call trigger
4067  $result = $this->call_trigger('LINEBILL_SUPPLIER_CREATE', $user);
4068  if ($result < 0) {
4069  $this->db->rollback();
4070  return -2;
4071  }
4072  // End call triggers
4073  }
4074 
4075  $this->db->commit();
4076  return $this->id;
4077  } else {
4078  $this->error = $this->db->error();
4079  $this->db->rollback();
4080  return -2;
4081  }
4082  }
4083 
4084  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4090  public function update_total()
4091  {
4092  // phpcs:enable
4093  $this->db->begin();
4094 
4095  // Mise a jour ligne en base
4096  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
4097  $sql .= " total_ht = ".price2num($this->total_ht);
4098  $sql .= ", tva= ".price2num($this->total_tva);
4099  $sql .= ", total_localtax1 = ".price2num($this->total_localtax1);
4100  $sql .= ", total_localtax2 = ".price2num($this->total_localtax2);
4101  $sql .= ", total_ttc = ".price2num($this->total_ttc);
4102  $sql .= " WHERE rowid = ".((int) $this->rowid);
4103 
4104  dol_syslog("FactureFournisseurLigne.class.php::update_total", LOG_DEBUG);
4105 
4106  $resql = $this->db->query($sql);
4107  if ($resql) {
4108  $this->db->commit();
4109  return 1;
4110  } else {
4111  $this->error = $this->db->error();
4112  $this->db->rollback();
4113  return -2;
4114  }
4115  }
4116 }
FactureFournisseur\update
update($user=null, $notrigger=0)
Update database.
Definition: fournisseur.facture.class.php:1149
make_substitutions
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
Definition: functions.lib.php:8366
FactureFournisseur\fetch_lines
fetch_lines()
Load this->lines.
Definition: fournisseur.facture.class.php:1045
getLocalTaxesFromRate
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
Definition: functions.lib.php:6398
dol_trunc
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
Definition: functions.lib.php:4059
SupplierInvoiceLine\fetch
fetch($rowid)
Retrieves a supplier invoice line.
Definition: fournisseur.facture.class.php:3609
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1323
description
print *****$script_file(".$version.") pid cd cd cd description as description
Definition: email_expire_services_to_customers.php:83
FactureFournisseur\TYPE_CREDIT_NOTE
const TYPE_CREDIT_NOTE
Credit note invoice.
Definition: fournisseur.facture.class.php:341
FactureFournisseur\$note
$note
Definition: fournisseur.facture.class.php:214
dol_delete_dir_recursive
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
Definition: files.lib.php:1485
FactureFournisseur\info
info($id)
Loads the info order information into the invoice object.
Definition: fournisseur.facture.class.php:2500
DoliDB
Class to manage Dolibarr database access.
Definition: DoliDB.class.php:30
dol_escape_htmltag
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
Definition: functions.lib.php:1600
ProductFournisseur
Class to manage predefined suppliers products.
Definition: fournisseur.product.class.php:40
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:609
CommonObject\updateRangOfLine
updateRangOfLine($rowid, $rang)
Update position of line (rang)
Definition: commonobject.class.php:3159
FactureFournisseur
Class to manage suppliers invoices.
Definition: fournisseur.facture.class.php:51
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:5107
FactureFournisseur\hasDelay
hasDelay()
Is the payment of the supplier invoice having a delay?
Definition: fournisseur.facture.class.php:3247
FactureFournisseur\getKanbanView
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually picto)
Definition: fournisseur.facture.class.php:3289
Translate
Class to manage translations.
Definition: translate.class.php:30
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1158
dol_dir_list
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:62
SupplierInvoiceLine\update
update($notrigger=0)
Update a supplier invoice line.
Definition: fournisseur.facture.class.php:3742
FactureFournisseur\updateline
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_devise=0, $ref_supplier='', $rang=0)
Update a line detail into database.
Definition: fournisseur.facture.class.php:2289
MultiCurrency\getIdFromCode
static getIdFromCode($dbs, $code)
Get id of currency from code.
Definition: multicurrency.class.php:503
FactureFournisseur\deleteline
deleteline($rowid, $notrigger=0)
Delete a detail line from database.
Definition: fournisseur.facture.class.php:2446
CommonObject\deleteObjectLinked
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='', $f_user=null, $notrigger=0)
Delete all links between an object $this.
Definition: commonobject.class.php:4170
FactureFournisseur\create
create($user)
Create supplier invoice into database.
Definition: fournisseur.facture.class.php:397
FactureFournisseur\validate
validate($user, $force_number='', $idwarehouse=0, $notrigger=0)
Tag invoice as validated + call trigger BILL_VALIDATE.
Definition: fournisseur.facture.class.php:1771
FactureFournisseur\STATUS_VALIDATED
const STATUS_VALIDATED
Validated (need to be paid)
Definition: fournisseur.facture.class.php:356
FactureFournisseur\initAsSpecimen
initAsSpecimen($option='')
Initialise an instance with random values.
Definition: fournisseur.facture.class.php:2953
SupplierInvoiceLine\$ref
$ref
Definition: fournisseur.facture.class.php:3377
FormMargin
Classe permettant la generation de composants html autre Only common components are here.
Definition: html.formmargin.class.php:29
FactureFournisseur\__construct
__construct($db)
Constructor.
Definition: fournisseur.facture.class.php:386
CommonObjectLine
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Definition: commonobjectline.class.php:32
FactureFournisseur\$remise
$remise
Definition: fournisseur.facture.class.php:192
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5955
SupplierInvoiceLine
Class to manage line invoices.
Definition: fournisseur.facture.class.php:3359
FactureFournisseur\load_board
load_board($user)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: fournisseur.facture.class.php:2648
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2675
FactureFournisseur\replaceThirdparty
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
Definition: fournisseur.facture.class.php:3216
WorkboardResponse
Definition: workboardresponse.class.php:24
CommonObject\fetch_thirdparty
fetch_thirdparty($force_thirdparty_id=0)
Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty.
Definition: commonobject.class.php:1634
dol_concatdesc
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
Definition: functions.lib.php:7734
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:4135
FactureFournisseur\isCreditNoteUsed
isCreditNoteUsed()
Is credit note used.
Definition: fournisseur.facture.class.php:3267
FactureFournisseur\getNextNumRef
getNextNumRef($soc, $mode='next')
Return next reference of supplier invoice not already used (or last reference) according to numbering...
Definition: fournisseur.facture.class.php:2902
rowid
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid
Definition: email_expire_services_to_representatives.php:79
FactureFournisseurRec
Class to manage invoice templates.
Definition: fournisseur.facture-rec.class.php:40
CommonObject\commonGenerateDocument
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
Definition: commonobject.class.php:5361
calcul_price_total
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
dol_delete_file
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
Definition: files.lib.php:1334
SupplierInvoiceLine\__construct
__construct($db)
Constructor.
Definition: fournisseur.facture.class.php:3598
FactureFournisseur\setPaid
setPaid($user, $close_code='', $close_note='')
Tag invoice as a paid invoice.
Definition: fournisseur.facture.class.php:1590
CommonObject\update_price
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).
Definition: commonobject.class.php:3471
get_exdir
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
Definition: functions.lib.php:6882
FactureFournisseur\replaceProduct
static replaceProduct(DoliDB $db, $origin_id, $dest_id)
Function used to replace a product id with another one.
Definition: fournisseur.facture.class.php:3233
FactureFournisseur\fetch
fetch($id='', $ref='', $ref_ext='')
Load object in memory from database.
Definition: fournisseur.facture.class.php:869
SupplierInvoiceLine\insert
insert($notrigger=0)
Insert line into database.
Definition: fournisseur.facture.class.php:3877
MouvementStock
Class to manage stock movements.
Definition: mouvementstock.class.php:31
CommonObject\insertExtraFields
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
Definition: commonobject.class.php:6137
CommonObject\isExistingObject
static isExistingObject($element, $id, $ref='', $ref_ext='')
Check an object id/ref exists If you don't need/want to instantiate object and just need to know if o...
Definition: commonobject.class.php:689
FactureFournisseur\setDraft
setDraft($user, $idwarehouse=-1)
Set draft status.
Definition: fournisseur.facture.class.php:1924
dol_string_nohtmltag
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
Definition: functions.lib.php:7046
CommonObject\commonReplaceProduct
static commonReplaceProduct(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a product id with another one.
Definition: commonobject.class.php:8533
FactureFournisseur\insert_discount
insert_discount($idremise)
Add a discount line into an invoice (as an invoice line) using an existing absolute discount (Consume...
Definition: fournisseur.facture.class.php:1337
CommonObject\deleteEcmFiles
deleteEcmFiles($mode=0)
Delete related files of object in database.
Definition: commonobject.class.php:10135
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1741
DiscountAbsolute
Class to manage absolute discounts.
Definition: discount.class.php:29
FactureFournisseur\addline
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_devise=0, $ref_supplier='', $special_code='', $fk_parent_line=0, $fk_remise_except=0)
Adds an invoice line (associated with no predefined product/service) The parameters are already suppo...
Definition: fournisseur.facture.class.php:2027
FactureFournisseur\list_qualified_avoir_supplier_invoices
list_qualified_avoir_supplier_invoices($socid=0)
Return list of qualifying invoices for correction by credit note Invoices that respect the following ...
Definition: fournisseur.facture.class.php:2597
MultiCurrency\getIdAndTxFromCode
static getIdAndTxFromCode($dbs, $code, $date_document='')
Get id and rate of currency from code.
Definition: multicurrency.class.php:528
CommonObject\line_max
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
Definition: commonobject.class.php:3317
CommonObject\fetch_optionals
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
Definition: commonobject.class.php:5986
FactureFournisseur\set_unpaid
set_unpaid($user)
Tag the invoice as not fully paid + trigger call BILL_UNPAYED Function used when a direct debit payme...
Definition: fournisseur.facture.class.php:1653
FactureFournisseur\setVATReverseCharge
setVATReverseCharge($vatreversecharge)
Change the option VAT reverse charge.
Definition: fournisseur.facture.class.php:3330
$sql
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3997
FactureFournisseur\$fournisseur
$fournisseur
Definition: fournisseur.facture.class.php:254
FactureFournisseur\$table_ref_field
$table_ref_field
{}
Definition: fournisseur.facture.class.php:93
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:207
ref
$object ref
Definition: info.php:78
dol_time_plus_duree
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition: date.lib.php:122
FactureFournisseur\getTooltipContentArray
getTooltipContentArray($params)
getTooltipContentArray
Definition: fournisseur.facture.class.php:2710
User
Class to manage Dolibarr users.
Definition: user.class.php:47
FactureFournisseur\set_paid
set_paid($user, $close_code='', $close_note='')
Tag invoice as a paid invoice.
Definition: fournisseur.facture.class.php:1575
FactureFournisseur\STATUS_DRAFT
const STATUS_DRAFT
Draft.
Definition: fournisseur.facture.class.php:351
FactureFournisseur\STATUS_CLOSED
const STATUS_CLOSED
Classified paid.
Definition: fournisseur.facture.class.php:365
CommonInvoice
Superclass for invoices classes.
Definition: commoninvoice.class.php:32
FactureFournisseur\TYPE_DEPOSIT
const TYPE_DEPOSIT
Deposit invoice.
Definition: fournisseur.facture.class.php:346
CommonObject\deleteExtraFields
deleteExtraFields()
Delete all extra fields values for the current object.
Definition: commonobject.class.php:6097
Product
Class to manage products or services.
Definition: product.class.php:46
CommonObject\add_object_linked
add_object_linked($origin=null, $origin_id=null, $f_user=null, $notrigger=0)
Add an object link into llx_element_element.
Definition: commonobject.class.php:3760
FactureFournisseur\setCanceled
setCanceled($user, $close_code='', $close_note='')
Tag invoice as canceled, with no payment on it (example for replacement invoice or payment never rece...
Definition: fournisseur.facture.class.php:1714
FactureFournisseur\getRights
getRights()
Returns the rights used for this class.
Definition: fournisseur.facture.class.php:3201
FactureFournisseur\setUnpaid
setUnpaid($user)
Tag the invoice as not fully paid + trigger call BILL_UNPAYED Function used when a direct debit payme...
Definition: fournisseur.facture.class.php:1668
img_object
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
Definition: functions.lib.php:4473
FactureFournisseur\TYPE_STANDARD
const TYPE_STANDARD
Standard invoice.
Definition: fournisseur.facture.class.php:331
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:3056
price
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.
Definition: functions.lib.php:5829
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5770
FactureFournisseur\createFromClone
createFromClone(User $user, $fromid, $invertdetail=0)
Load an object from its id and create a new one in database.
Definition: fournisseur.facture.class.php:3092
FactureFournisseur\STATUS_ABANDONED
const STATUS_ABANDONED
Classified abandoned and no payment done.
Definition: fournisseur.facture.class.php:374
FactureFournisseur\getNomUrl
getNomUrl($withpicto=0, $option='', $max=0, $short=0, $moretitle='', $notooltip=0, $save_lastsearch_value=-1, $addlinktonotes=0)
Return clicable name (with picto eventually)
Definition: fournisseur.facture.class.php:2788
FactureFournisseur\load_state_board
load_state_board()
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: fournisseur.facture.class.php:3051
CommonInvoice\calculate_date_lim_reglement
calculate_date_lim_reglement($cond_reglement=0)
Returns an invoice payment deadline based on the invoice settlement conditions and billing date.
Definition: commoninvoice.class.php:682
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:156
FactureFournisseur\generateDocument
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template model.
Definition: fournisseur.facture.class.php:3172
CommonObject\line_order
line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
Save a new position (field rang) for details lines.
Definition: commonobject.class.php:2995
CommonObject\commonReplaceThirdparty
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
Definition: commonobject.class.php:8504
type
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:120
SupplierInvoiceLine\update_total
update_total()
Mise a jour de l'objet ligne de commande en base.
Definition: fournisseur.facture.class.php:4090
FactureFournisseur\$amount
$amount
Definition: fournisseur.facture.class.php:187
getCommonSubstitutionArray
getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $object=null, $include=null)
Return array of possible common substitutions.
Definition: functions.lib.php:7762
complete_substitutions_array
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
Definition: functions.lib.php:8489
FactureFournisseur\list_replacable_supplier_invoices
list_replacable_supplier_invoices($socid=0)
Return list of replaceable invoices Status valid or abandoned for other reason + not paid + no paymen...
Definition: fournisseur.facture.class.php:2547
float
div float
Buy price without taxes.
Definition: style.css.php:921
if
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Definition: journals_list.php:25
FactureFournisseur\TYPE_REPLACEMENT
const TYPE_REPLACEMENT
Replacement invoice.
Definition: fournisseur.facture.class.php:336