dolibarr  18.0.0-beta
fournisseur.facture.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2002-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2004 Christophe Combelles <ccomb@free.fr>
5  * Copyright (C) 2005 Marc Barilley <marc@ocebo.com>
6  * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@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 = (array) json_decode($obj->extraparams, true);
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 linked object
1517  $res = $this->deleteObjectLinked();
1518  if ($res < 0) {
1519  $error++;
1520  }
1521  }
1522 
1523  if (!$error) {
1524  // Delete record into ECM index (Note that delete is also done when deleting files with the dol_delete_dir_recursive
1525  $this->deleteEcmFiles();
1526 
1527  // We remove directory
1528  if ($conf->fournisseur->facture->dir_output) {
1529  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1530 
1531  $ref = dol_sanitizeFileName($this->ref);
1532  $dir = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$ref;
1533  $file = $dir."/".$ref.".pdf";
1534  if (file_exists($file)) {
1535  if (!dol_delete_file($file, 0, 0, 0, $this)) { // For triggers
1536  $this->error = 'ErrorFailToDeleteFile';
1537  $error++;
1538  }
1539  }
1540  if (file_exists($dir)) {
1541  $res = @dol_delete_dir_recursive($dir);
1542 
1543  if (!$res) {
1544  $this->error = 'ErrorFailToDeleteDir';
1545  $error++;
1546  }
1547  }
1548  }
1549  }
1550 
1551  // Remove extrafields
1552  if (!$error) {
1553  $result = $this->deleteExtraFields();
1554  if ($result < 0) {
1555  $error++;
1556  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1557  }
1558  }
1559 
1560  if (!$error) {
1561  dol_syslog(get_class($this)."::delete $this->id by $user->id", LOG_DEBUG);
1562  $this->db->commit();
1563  return 1;
1564  } else {
1565  $this->error = $this->db->lasterror();
1566  $this->db->rollback();
1567  return -$error;
1568  }
1569  }
1570 
1571 
1572  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1583  public function set_paid($user, $close_code = '', $close_note = '')
1584  {
1585  // phpcs:enable
1586  dol_syslog(get_class($this)."::set_paid is deprecated, use setPaid instead", LOG_NOTICE);
1587  return $this->setPaid($user, $close_code, $close_note);
1588  }
1589 
1598  public function setPaid($user, $close_code = '', $close_note = '')
1599  {
1600  $error = 0;
1601 
1602  if ($this->paye != 1) {
1603  $this->db->begin();
1604 
1605  $now = dol_now();
1606 
1607  dol_syslog("FactureFournisseur::set_paid", LOG_DEBUG);
1608 
1609  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn SET';
1610  $sql .= ' fk_statut = '.self::STATUS_CLOSED;
1611  if (!$close_code) {
1612  $sql .= ', paye=1';
1613  }
1614  if ($close_code) {
1615  $sql .= ", close_code='".$this->db->escape($close_code)."'";
1616  }
1617  if ($close_note) {
1618  $sql .= ", close_note='".$this->db->escape($close_note)."'";
1619  }
1620  $sql .= ', fk_user_closing = '.((int) $user->id);
1621  $sql .= ", date_closing = '".$this->db->idate($now)."'";
1622  $sql .= ' WHERE rowid = '.((int) $this->id);
1623 
1624  $resql = $this->db->query($sql);
1625  if ($resql) {
1626  // Call trigger
1627  $result = $this->call_trigger('BILL_SUPPLIER_PAYED', $user);
1628  if ($result < 0) {
1629  $error++;
1630  }
1631  // End call triggers
1632  } else {
1633  $error++;
1634  $this->error = $this->db->error();
1635  dol_print_error($this->db);
1636  }
1637 
1638  if (!$error) {
1639  $this->db->commit();
1640  return 1;
1641  } else {
1642  $this->db->rollback();
1643  return -1;
1644  }
1645  } else {
1646  return 0;
1647  }
1648  }
1649 
1650  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1661  public function set_unpaid($user)
1662  {
1663  // phpcs:enable
1664  dol_syslog(get_class($this)."::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE);
1665  return $this->setUnpaid($user);
1666  }
1667 
1676  public function setUnpaid($user)
1677  {
1678  $error = 0;
1679 
1680  $this->db->begin();
1681 
1682  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn';
1683  $sql .= ' SET paye=0, fk_statut='.self::STATUS_VALIDATED.', close_code=null, close_note=null,';
1684  $sql .= ' date_closing=null,';
1685  $sql .= ' fk_user_closing=null';
1686  $sql .= ' WHERE rowid = '.((int) $this->id);
1687 
1688  dol_syslog(get_class($this)."::set_unpaid", LOG_DEBUG);
1689  $resql = $this->db->query($sql);
1690  if ($resql) {
1691  // Call trigger
1692  $result = $this->call_trigger('BILL_SUPPLIER_UNPAYED', $user);
1693  if ($result < 0) {
1694  $error++;
1695  }
1696  // End call triggers
1697  } else {
1698  $error++;
1699  $this->error = $this->db->error();
1700  dol_print_error($this->db);
1701  }
1702 
1703  if (!$error) {
1704  $this->db->commit();
1705  return 1;
1706  } else {
1707  $this->db->rollback();
1708  return -1;
1709  }
1710  }
1711 
1722  public function setCanceled($user, $close_code = '', $close_note = '')
1723  {
1724  dol_syslog(get_class($this)."::setCanceled rowid=".((int) $this->id), LOG_DEBUG);
1725 
1726  $this->db->begin();
1727 
1728  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn SET';
1729  $sql .= ' fk_statut='.self::STATUS_ABANDONED;
1730  if ($close_code) {
1731  $sql .= ", close_code='".$this->db->escape($close_code)."'";
1732  }
1733  if ($close_note) {
1734  $sql .= ", close_note='".$this->db->escape($close_note)."'";
1735  }
1736  $sql .= " WHERE rowid = ".((int) $this->id);
1737 
1738  $resql = $this->db->query($sql);
1739  if ($resql) {
1740  // Bound discounts are deducted from the invoice
1741  // as they have not been used since the invoice is abandoned.
1742  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
1743  $sql .= ' SET fk_invoice_supplier = NULL';
1744  $sql .= ' WHERE fk_invoice_supplier = '.((int) $this->id);
1745 
1746  $resql = $this->db->query($sql);
1747  if ($resql) {
1748  // Call trigger
1749  $result = $this->call_trigger('BILL_SUPPLIER_CANCEL', $user);
1750  if ($result < 0) {
1751  $this->db->rollback();
1752  return -1;
1753  }
1754  // End call triggers
1755 
1756  $this->db->commit();
1757  return 1;
1758  } else {
1759  $this->error = $this->db->error()." sql=".$sql;
1760  $this->db->rollback();
1761  return -1;
1762  }
1763  } else {
1764  $this->error = $this->db->error()." sql=".$sql;
1765  $this->db->rollback();
1766  return -2;
1767  }
1768  }
1769 
1779  public function validate($user, $force_number = '', $idwarehouse = 0, $notrigger = 0)
1780  {
1781  global $conf, $langs;
1782 
1783  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1784 
1785  $now = dol_now();
1786 
1787  $error = 0;
1788  dol_syslog(get_class($this).'::validate user='.$user->id.', force_number='.$force_number.', idwarehouse='.$idwarehouse);
1789 
1790  // Force to have object complete for checks
1791  $this->fetch_thirdparty();
1792  $this->fetch_lines();
1793 
1794  // Check parameters
1795  if ($this->statut > self::STATUS_DRAFT) { // This is to avoid to validate twice (avoid errors on logs and stock management)
1796  dol_syslog(get_class($this)."::validate no draft status", LOG_WARNING);
1797  return 0;
1798  }
1799  if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ').'/', $this->ref_supplier)) {
1800  $langs->load("errors");
1801  $this->error = $langs->trans("ErrorFieldFormat", $langs->transnoentities("RefSupplier")).'. '.$langs->trans('RemoveString', $langs->transnoentitiesnoconv("CopyOf"));
1802  return -1;
1803  }
1804  if (count($this->lines) <= 0) {
1805  $langs->load("errors");
1806  $this->error = $langs->trans("ErrorObjectMustHaveLinesToBeValidated", $this->ref);
1807  return -1;
1808  }
1809 
1810  $this->db->begin();
1811 
1812  // Define new ref
1813  if ($force_number) {
1814  $num = $force_number;
1815  } elseif (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
1816  $num = $this->getNextNumRef($this->thirdparty);
1817  } else {
1818  $num = $this->ref;
1819  }
1820  $this->newref = dol_sanitizeFileName($num);
1821 
1822  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1823  $sql .= " SET ref='".$this->db->escape($num)."', fk_statut = 1, fk_user_valid = ".((int) $user->id).", date_valid = '".$this->db->idate($now)."'";
1824  $sql .= " WHERE rowid = ".((int) $this->id);
1825 
1826  dol_syslog(get_class($this)."::validate", LOG_DEBUG);
1827  $resql = $this->db->query($sql);
1828  if ($resql) {
1829  // Si on incrémente le produit principal et ses composants à la validation de facture fournisseur
1830  if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) {
1831  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1832  $langs->load("agenda");
1833 
1834  $cpt = count($this->lines);
1835  for ($i = 0; $i < $cpt; $i++) {
1836  if ($this->lines[$i]->fk_product > 0) {
1837  $mouvP = new MouvementStock($this->db);
1838  $mouvP->origin = &$this;
1839  $mouvP->setOrigin($this->element, $this->id);
1840  // We increase stock for product
1841  $up_ht_disc = $this->lines[$i]->subprice;
1842  if (!empty($this->lines[$i]->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) {
1843  $up_ht_disc = price2num($up_ht_disc * (100 - $this->lines[$i]->remise_percent) / 100, 'MU');
1844  }
1846  $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1847  } else {
1848  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1849  }
1850  if ($result < 0) {
1851  $error++;
1852  }
1853  }
1854  }
1855  }
1856 
1857  // Triggers call
1858  if (!$error && empty($notrigger)) {
1859  // Call trigger
1860  $result = $this->call_trigger('BILL_SUPPLIER_VALIDATE', $user);
1861  if ($result < 0) {
1862  $error++;
1863  }
1864  // End call triggers
1865  }
1866 
1867  if (!$error) {
1868  $this->oldref = $this->ref;
1869 
1870  // Rename directory if dir was a temporary ref
1871  if (preg_match('/^[\(]?PROV/i', $this->ref)) {
1872  // Now we rename also files into index
1873  $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)."'";
1874  $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;
1875  $resql = $this->db->query($sql);
1876  if (!$resql) {
1877  $error++; $this->error = $this->db->lasterror();
1878  }
1879 
1880  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1881  $oldref = dol_sanitizeFileName($this->ref);
1882  $newref = dol_sanitizeFileName($num);
1883  $dirsource = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$oldref;
1884  $dirdest = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$newref;
1885  if (!$error && file_exists($dirsource)) {
1886  dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest);
1887 
1888  if (@rename($dirsource, $dirdest)) {
1889  dol_syslog("Rename ok");
1890  // Rename docs starting with $oldref with $newref
1891  $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, '/'));
1892  foreach ($listoffiles as $fileentry) {
1893  $dirsource = $fileentry['name'];
1894  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1895  $dirsource = $fileentry['path'].'/'.$dirsource;
1896  $dirdest = $fileentry['path'].'/'.$dirdest;
1897  @rename($dirsource, $dirdest);
1898  }
1899  }
1900  }
1901  }
1902  }
1903 
1904  // Set new ref and define current statut
1905  if (!$error) {
1906  $this->ref = $num;
1907  $this->statut = self::STATUS_VALIDATED;
1908  //$this->date_validation=$now; this is stored into log table
1909  }
1910 
1911  if (!$error) {
1912  $this->db->commit();
1913  return 1;
1914  } else {
1915  $this->db->rollback();
1916  return -1;
1917  }
1918  } else {
1919  $this->error = $this->db->error();
1920  $this->db->rollback();
1921  return -1;
1922  }
1923  }
1924 
1932  public function setDraft($user, $idwarehouse = -1)
1933  {
1934  // phpcs:enable
1935  global $conf, $langs;
1936 
1937  $error = 0;
1938 
1939  if ($this->statut == self::STATUS_DRAFT) {
1940  dol_syslog(__METHOD__." already draft status", LOG_WARNING);
1941  return 0;
1942  }
1943 
1944  dol_syslog(__METHOD__, LOG_DEBUG);
1945 
1946  $this->db->begin();
1947 
1948  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1949  $sql .= " SET fk_statut = ".self::STATUS_DRAFT;
1950  $sql .= " WHERE rowid = ".((int) $this->id);
1951 
1952  $result = $this->db->query($sql);
1953  if ($result) {
1954  if (!$error) {
1955  $this->oldcopy = clone $this;
1956  }
1957 
1958  // Si on incremente le produit principal et ses composants a la validation de facture fournisseur, on decremente
1959  if ($result >= 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) {
1960  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1961  $langs->load("agenda");
1962 
1963  $cpt = count($this->lines);
1964  for ($i = 0; $i < $cpt; $i++) {
1965  if ($this->lines[$i]->fk_product > 0) {
1966  $mouvP = new MouvementStock($this->db);
1967  $mouvP->origin = &$this;
1968  $mouvP->setOrigin($this->element, $this->id);
1969  // We increase stock for product
1971  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
1972  } else {
1973  $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
1974  }
1975  }
1976  }
1977  }
1978  // Triggers call
1979  if (!$error && empty($notrigger)) {
1980  // Call trigger
1981  $result = $this->call_trigger('BILL_SUPPLIER_UNVALIDATE', $user);
1982  if ($result < 0) {
1983  $error++;
1984  }
1985  // End call triggers
1986  }
1987  if ($error == 0) {
1988  $this->db->commit();
1989  return 1;
1990  } else {
1991  $this->db->rollback();
1992  return -1;
1993  }
1994  } else {
1995  $this->error = $this->db->error();
1996  $this->db->rollback();
1997  return -1;
1998  }
1999  }
2000 
2001 
2035  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)
2036  {
2037  global $langs, $mysoc, $conf;
2038 
2039  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);
2040  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2041 
2042  if ($this->statut == self::STATUS_DRAFT) {
2043  // Clean parameters
2044  if (empty($remise_percent)) {
2045  $remise_percent = 0;
2046  }
2047  if (empty($qty)) {
2048  $qty = 0;
2049  }
2050  if (empty($info_bits)) {
2051  $info_bits = 0;
2052  }
2053  if (empty($rang)) {
2054  $rang = 0;
2055  }
2056  if (empty($ventil)) {
2057  $ventil = 0;
2058  }
2059  if (empty($txtva)) {
2060  $txtva = 0;
2061  }
2062  if (empty($txlocaltax1)) {
2063  $txlocaltax1 = 0;
2064  }
2065  if (empty($txlocaltax2)) {
2066  $txlocaltax2 = 0;
2067  }
2068 
2069  $remise_percent = price2num($remise_percent);
2070  $qty = price2num($qty);
2071  $pu = price2num($pu);
2072  if (!preg_match('/\((.*)\)/', $txtva)) {
2073  $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
2074  }
2075  $txlocaltax1 = price2num($txlocaltax1);
2076  $txlocaltax2 = price2num($txlocaltax2);
2077 
2078  if ($date_start && $date_end && $date_start > $date_end) {
2079  $langs->load("errors");
2080  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
2081  return -1;
2082  }
2083 
2084  $this->db->begin();
2085 
2086  if ($fk_product > 0) {
2087  if (!empty($conf->global->SUPPLIER_INVOICE_WITH_PREDEFINED_PRICES_ONLY)) {
2088  // Check quantity is enough
2089  dol_syslog(get_class($this)."::addline we check supplier prices fk_product=".$fk_product." qty=".$qty." ref_supplier=".$ref_supplier);
2090  $prod = new ProductFournisseur($this->db);
2091  if ($prod->fetch($fk_product) > 0) {
2092  $product_type = $prod->type;
2093  $label = $prod->label;
2094  $fk_prod_fourn_price = 0;
2095 
2096  // We use 'none' instead of $ref_supplier, because $ref_supplier may not exists anymore. So we will take the first supplier price ok.
2097  // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
2098  $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
2099  if ($result > 0) {
2100  if (empty($pu)) {
2101  $pu = $prod->fourn_pu; // Unit price supplier price set by get_buyprice
2102  }
2103  $ref_supplier = $prod->ref_supplier; // Ref supplier price set by get_buyprice
2104  // is remise percent not keyed but present for the product we add it
2105  if ($remise_percent == 0 && $prod->remise_percent != 0) {
2106  $remise_percent = $prod->remise_percent;
2107  }
2108  }
2109  if ($result == 0) { // If result == 0, we failed to found the supplier reference price
2110  $langs->load("errors");
2111  $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
2112  $this->db->rollback();
2113  dol_syslog(get_class($this)."::addline we did not found supplier price, so we can't guess unit price");
2114  //$pu = $prod->fourn_pu; // We do not overwrite unit price
2115  //$ref = $prod->ref_fourn; // We do not overwrite ref supplier price
2116  return -1;
2117  }
2118  if ($result == -1) {
2119  $langs->load("errors");
2120  $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
2121  $this->db->rollback();
2122  dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_DEBUG);
2123  return -1;
2124  }
2125  if ($result < -1) {
2126  $this->error = $prod->error;
2127  $this->db->rollback();
2128  dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_ERR);
2129  return -1;
2130  }
2131  } else {
2132  $this->error = $prod->error;
2133  $this->db->rollback();
2134  return -1;
2135  }
2136  }
2137  } else {
2138  $product_type = $type;
2139  }
2140 
2141  if (isModEnabled("multicurrency") && $pu_devise > 0) {
2142  $pu = 0;
2143  }
2144 
2145  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $mysoc, $this->thirdparty);
2146 
2147  // Clean vat code
2148  $reg = array();
2149  $vat_src_code = '';
2150  if (preg_match('/\((.*)\)/', $txtva, $reg)) {
2151  $vat_src_code = $reg[1];
2152  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
2153  }
2154 
2155  // Calcul du total TTC et de la TVA pour la ligne a partir de
2156  // qty, pu, remise_percent et txtva
2157  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2158  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2159 
2160  $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);
2161  $total_ht = $tabprice[0];
2162  $total_tva = $tabprice[1];
2163  $total_ttc = $tabprice[2];
2164  $total_localtax1 = $tabprice[9];
2165  $total_localtax2 = $tabprice[10];
2166  $pu_ht = $tabprice[3];
2167 
2168  // MultiCurrency
2169  $multicurrency_total_ht = $tabprice[16];
2170  $multicurrency_total_tva = $tabprice[17];
2171  $multicurrency_total_ttc = $tabprice[18];
2172  $pu_ht_devise = $tabprice[19];
2173 
2174  // Check parameters
2175  if ($type < 0) {
2176  return -1;
2177  }
2178 
2179  if ($rang < 0) {
2180  $rangmax = $this->line_max();
2181  $rang = $rangmax + 1;
2182  }
2183 
2184  // Insert line
2185  $supplierinvoiceline = new SupplierInvoiceLine($this->db);
2186 
2187  $supplierinvoiceline->context = $this->context;
2188 
2189  $supplierinvoiceline->fk_facture_fourn = $this->id;
2190  //$supplierinvoiceline->label=$label; // deprecated
2191  $supplierinvoiceline->desc = $desc;
2192  $supplierinvoiceline->ref_supplier = $ref_supplier;
2193 
2194  $supplierinvoiceline->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs($qty) : $qty); // For credit note, quantity is always positive and unit price negative
2195  $supplierinvoiceline->subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2196 
2197  $supplierinvoiceline->vat_src_code = $vat_src_code;
2198  $supplierinvoiceline->tva_tx = $txtva;
2199  $supplierinvoiceline->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
2200  $supplierinvoiceline->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
2201  $supplierinvoiceline->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
2202  $supplierinvoiceline->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
2203 
2204  $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
2205  $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
2206  $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
2207  $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
2208  $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
2209 
2210  $supplierinvoiceline->fk_product = $fk_product;
2211  $supplierinvoiceline->product_type = $type;
2212  $supplierinvoiceline->remise_percent = $remise_percent;
2213  $supplierinvoiceline->date_start = $date_start;
2214  $supplierinvoiceline->date_end = $date_end;
2215  $supplierinvoiceline->fk_code_ventilation = $ventil;
2216  $supplierinvoiceline->rang = $rang;
2217  $supplierinvoiceline->info_bits = $info_bits;
2218  $supplierinvoiceline->fk_remise_except = $fk_remise_except;
2219 
2220  $supplierinvoiceline->special_code = ((string) $special_code != '' ? $special_code : $this->special_code);
2221  $supplierinvoiceline->fk_parent_line = $fk_parent_line;
2222  $supplierinvoiceline->origin = $this->origin;
2223  $supplierinvoiceline->origin_id = $origin_id;
2224  $supplierinvoiceline->fk_unit = $fk_unit;
2225 
2226  // Multicurrency
2227  $supplierinvoiceline->fk_multicurrency = $this->fk_multicurrency;
2228  $supplierinvoiceline->multicurrency_code = $this->multicurrency_code;
2229  $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
2230 
2231  $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
2232  $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
2233  $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
2234 
2235  if (is_array($array_options) && count($array_options) > 0) {
2236  $supplierinvoiceline->array_options = $array_options;
2237  }
2238 
2239  $result = $supplierinvoiceline->insert($notrigger);
2240  if ($result > 0) {
2241  // Reorder if child line
2242  if (!empty($fk_parent_line)) {
2243  $this->line_order(true, 'DESC');
2244  } elseif ($rang > 0 && $rang <= count($this->lines)) { // Update all rank of all other lines
2245  $linecount = count($this->lines);
2246  for ($ii = $rang; $ii <= $linecount; $ii++) {
2247  $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1);
2248  }
2249  }
2250 
2251  // Mise a jour informations denormalisees au niveau de la facture meme
2252  $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.
2253  if ($result > 0) {
2254  $this->db->commit();
2255  return $supplierinvoiceline->id;
2256  } else {
2257  $this->error = $this->db->error();
2258  $this->db->rollback();
2259  return -1;
2260  }
2261  } else {
2262  $this->error = $supplierinvoiceline->error;
2263  $this->errors = $supplierinvoiceline->errors;
2264  $this->db->rollback();
2265  return -2;
2266  }
2267  } else {
2268  return 0;
2269  }
2270  }
2271 
2297  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)
2298  {
2299  global $mysoc, $langs;
2300 
2301  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);
2302  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2303 
2304  $pu = price2num($pu);
2305  $qty = price2num($qty);
2306  $remise_percent = price2num($remise_percent);
2307  $pu_devise = price2num($pu_devise);
2308 
2309  // Check parameters
2310  //if (! is_numeric($pu) || ! is_numeric($qty)) return -1;
2311  if ($type < 0) {
2312  return -1;
2313  }
2314 
2315  if ($date_start && $date_end && $date_start > $date_end) {
2316  $langs->load("errors");
2317  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
2318  return -1;
2319  }
2320 
2321  // Clean parameters
2322  if (empty($vatrate)) {
2323  $vatrate = 0;
2324  }
2325  if (empty($txlocaltax1)) {
2326  $txlocaltax1 = 0;
2327  }
2328  if (empty($txlocaltax2)) {
2329  $txlocaltax2 = 0;
2330  }
2331 
2332  $txlocaltax1 = price2num($txlocaltax1);
2333  $txlocaltax2 = price2num($txlocaltax2);
2334 
2335  // Calcul du total TTC et de la TVA pour la ligne a partir de
2336  // qty, pu, remise_percent et txtva
2337  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2338  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2339 
2340  $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $mysoc, $this->thirdparty);
2341 
2342  $reg = array();
2343 
2344  // Clean vat code
2345  $vat_src_code = '';
2346  if (preg_match('/\((.*)\)/', $vatrate, $reg)) {
2347  $vat_src_code = $reg[1];
2348  $vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate.
2349  }
2350 
2351  $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);
2352  $total_ht = $tabprice[0];
2353  $total_tva = $tabprice[1];
2354  $total_ttc = $tabprice[2];
2355  $pu_ht = $tabprice[3];
2356  $pu_tva = $tabprice[4];
2357  $pu_ttc = $tabprice[5];
2358  $total_localtax1 = $tabprice[9];
2359  $total_localtax2 = $tabprice[10];
2360 
2361  // MultiCurrency
2362  $multicurrency_total_ht = $tabprice[16];
2363  $multicurrency_total_tva = $tabprice[17];
2364  $multicurrency_total_ttc = $tabprice[18];
2365  $pu_ht_devise = $tabprice[19];
2366 
2367  if (empty($info_bits)) {
2368  $info_bits = 0;
2369  }
2370 
2371  //Fetch current line from the database and then clone the object and set it in $oldline property
2372  $line = new SupplierInvoiceLine($this->db);
2373  $line->fetch($id);
2374  $line->fetch_optionals();
2375 
2376  $staticline = clone $line;
2377 
2378  if ($idproduct) {
2379  $product = new Product($this->db);
2380  $result = $product->fetch($idproduct);
2381  $product_type = $product->type;
2382  } else {
2383  $idproduct = $staticline->fk_product;
2384  $product_type = $type;
2385  }
2386 
2387  $line->oldline = $staticline;
2388  $line->context = $this->context;
2389 
2390  $line->description = $desc;
2391 
2392  $line->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs($qty) : $qty); // For credit note, quantity is always positive and unit price negative
2393  $line->subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2394  $line->pu_ht = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2395  $line->pu_ttc = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ttc) : $pu_ttc); // For credit note, unit price always negative, always positive otherwise
2396 
2397  $line->remise_percent = $remise_percent;
2398  $line->ref_supplier = $ref_supplier;
2399 
2400  $line->date_start = $date_start;
2401  $line->date_end = $date_end;
2402 
2403  $line->vat_src_code = $vat_src_code;
2404  $line->tva_tx = $vatrate;
2405  $line->localtax1_tx = $txlocaltax1;
2406  $line->localtax2_tx = $txlocaltax2;
2407  $line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
2408  $line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
2409 
2410  $line->total_ht = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_ht) : $total_ht);
2411  $line->total_tva = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_tva) : $total_tva);
2412  $line->total_localtax1 = $total_localtax1;
2413  $line->total_localtax2 = $total_localtax2;
2414  $line->total_ttc = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_ttc) : $total_ttc);
2415 
2416  $line->fk_product = $idproduct;
2417  $line->product_type = $product_type;
2418  $line->info_bits = $info_bits;
2419  $line->fk_unit = $fk_unit;
2420  $line->rang = $rang;
2421 
2422  if (is_array($array_options) && count($array_options) > 0) {
2423  // We replace values in this->line->array_options only for entries defined into $array_options
2424  foreach ($array_options as $key => $value) {
2425  $line->array_options[$key] = $array_options[$key];
2426  }
2427  }
2428 
2429  // Multicurrency
2430  $line->multicurrency_subprice = $pu_ht_devise;
2431  $line->multicurrency_total_ht = $multicurrency_total_ht;
2432  $line->multicurrency_total_tva = $multicurrency_total_tva;
2433  $line->multicurrency_total_ttc = $multicurrency_total_ttc;
2434 
2435  $res = $line->update($notrigger);
2436 
2437  if ($res < 1) {
2438  $this->errors[] = $line->error;
2439  } else {
2440  // Update total price into invoice record
2441  $res = $this->update_price('1', 'auto', 0, $this->thirdparty);
2442  }
2443 
2444  return $res;
2445  }
2446 
2454  public function deleteline($rowid, $notrigger = 0)
2455  {
2456  if (!$rowid) {
2457  $rowid = $this->id;
2458  }
2459 
2460  $this->db->begin();
2461 
2462  // Free the discount linked to a line of invoice
2463  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
2464  $sql .= ' SET fk_invoice_supplier_line = NULL';
2465  $sql .= ' WHERE fk_invoice_supplier_line = '.((int) $rowid);
2466 
2467  dol_syslog(get_class($this)."::deleteline", LOG_DEBUG);
2468  $result = $this->db->query($sql);
2469  if (!$result) {
2470  $this->error = $this->db->error();
2471  $this->db->rollback();
2472  return -2;
2473  }
2474 
2475  $line = new SupplierInvoiceLine($this->db);
2476 
2477  if ($line->fetch($rowid) < 1) {
2478  return -1;
2479  }
2480 
2481  $res = $line->delete($notrigger);
2482 
2483  if ($res < 1) {
2484  $this->errors[] = $line->error;
2485  $this->db->rollback();
2486  return -3;
2487  } else {
2488  $res = $this->update_price(1);
2489 
2490  if ($res > 0) {
2491  $this->db->commit();
2492  return 1;
2493  } else {
2494  $this->db->rollback();
2495  $this->error = $this->db->lasterror();
2496  return -4;
2497  }
2498  }
2499  }
2500 
2501 
2508  public function info($id)
2509  {
2510  $sql = 'SELECT c.rowid, datec, tms as datem, ';
2511  $sql .= ' fk_user_author, fk_user_modif, fk_user_valid';
2512  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as c';
2513  $sql .= ' WHERE c.rowid = '.((int) $id);
2514 
2515  $result = $this->db->query($sql);
2516  if ($result) {
2517  if ($this->db->num_rows($result)) {
2518  $obj = $this->db->fetch_object($result);
2519 
2520  $this->id = $obj->rowid;
2521  if ($obj->fk_user_author) {
2522  $cuser = new User($this->db);
2523  $cuser->fetch($obj->fk_user_author);
2524  $this->user_creation = $cuser;
2525  }
2526  if ($obj->fk_user_valid) {
2527  $vuser = new User($this->db);
2528  $vuser->fetch($obj->fk_user_valid);
2529  $this->user_validation = $vuser;
2530  }
2531  if ($obj->fk_user_modif) {
2532  $muser = new User($this->db);
2533  $muser->fetch($obj->fk_user_modif);
2534  $this->user_modification = $muser;
2535  }
2536  $this->date_creation = $this->db->jdate($obj->datec);
2537  $this->date_modification = $this->db->jdate($obj->datem);
2538  //$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)
2539  }
2540  $this->db->free($result);
2541  } else {
2542  dol_print_error($this->db);
2543  }
2544  }
2545 
2546  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2555  public function list_replacable_supplier_invoices($socid = 0)
2556  {
2557  // phpcs:enable
2558  global $conf;
2559 
2560  $return = array();
2561 
2562  $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut,";
2563  $sql .= " ff.rowid as rowidnext";
2564  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2565  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2566  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture_fourn as ff ON f.rowid = ff.fk_facture_source";
2567  $sql .= " WHERE (f.fk_statut = ".self::STATUS_VALIDATED." OR (f.fk_statut = ".self::STATUS_ABANDONED." AND f.close_code = '".self::CLOSECODE_ABANDONED."'))";
2568  $sql .= " AND f.entity = ".$conf->entity;
2569  $sql .= " AND f.paye = 0"; // Pas classee payee completement
2570  $sql .= " AND pf.fk_paiementfourn IS NULL"; // Aucun paiement deja fait
2571  $sql .= " AND ff.fk_statut IS NULL"; // Renvoi vrai si pas facture de remplacement
2572  if ($socid > 0) {
2573  $sql .= " AND f.fk_soc = ".((int) $socid);
2574  }
2575  $sql .= " ORDER BY f.ref";
2576 
2577  dol_syslog(get_class($this)."::list_replacable_supplier_invoices", LOG_DEBUG);
2578  $resql = $this->db->query($sql);
2579  if ($resql) {
2580  while ($obj = $this->db->fetch_object($resql)) {
2581  $return[$obj->rowid] = array(
2582  'id' => $obj->rowid,
2583  'ref' => $obj->ref,
2584  'status' => $obj->fk_statut
2585  );
2586  }
2587  //print_r($return);
2588  return $return;
2589  } else {
2590  $this->error = $this->db->error();
2591  return -1;
2592  }
2593  }
2594 
2595  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2605  public function list_qualified_avoir_supplier_invoices($socid = 0)
2606  {
2607  // phpcs:enable
2608  global $conf;
2609 
2610  $return = array();
2611 
2612  $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.paye, pf.fk_paiementfourn";
2613  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2614  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2615  $sql .= " WHERE f.entity = ".$conf->entity;
2616  $sql .= " AND f.fk_statut in (".self::STATUS_VALIDATED.",".self::STATUS_CLOSED.")";
2617  $sql .= " AND NOT EXISTS (SELECT rowid from ".MAIN_DB_PREFIX."facture_fourn as ff WHERE f.rowid = ff.fk_facture_source";
2618  $sql .= " AND ff.type=".self::TYPE_REPLACEMENT.")";
2619  $sql .= " AND f.type != ".self::TYPE_CREDIT_NOTE; // Type non 2 si facture non avoir
2620  if ($socid > 0) {
2621  $sql .= " AND f.fk_soc = ".((int) $socid);
2622  }
2623  $sql .= " ORDER BY f.ref";
2624 
2625  dol_syslog(get_class($this)."::list_qualified_avoir_supplier_invoices", LOG_DEBUG);
2626  $resql = $this->db->query($sql);
2627  if ($resql) {
2628  while ($obj = $this->db->fetch_object($resql)) {
2629  $qualified = 0;
2630  if ($obj->fk_statut == self::STATUS_VALIDATED) {
2631  $qualified = 1;
2632  }
2633  if ($obj->fk_statut == self::STATUS_CLOSED) {
2634  $qualified = 1;
2635  }
2636  if ($qualified) {
2637  $paymentornot = ($obj->fk_paiementfourn ? 1 : 0);
2638  $return[$obj->rowid] = array('ref'=>$obj->ref, 'status'=>$obj->fk_statut, 'type'=>$obj->type, 'paye'=>$obj->paye, 'paymentornot'=>$paymentornot);
2639  }
2640  }
2641 
2642  return $return;
2643  } else {
2644  $this->error = $this->db->error();
2645  return -1;
2646  }
2647  }
2648 
2649  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2656  public function load_board($user)
2657  {
2658  // phpcs:enable
2659  global $conf, $langs;
2660 
2661  $sql = 'SELECT ff.rowid, ff.date_lim_reglement as datefin, ff.fk_statut as status, ff.total_ht, ff.total_ttc';
2662  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as ff';
2663  if (empty($user->rights->societe->client->voir) && !$user->socid) {
2664  $sql .= " JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ff.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
2665  }
2666  $sql .= ' WHERE ff.paye = 0';
2667  $sql .= ' AND ff.fk_statut > 0';
2668  $sql .= " AND ff.entity = ".$conf->entity;
2669  if ($user->socid) {
2670  $sql .= ' AND ff.fk_soc = '.((int) $user->socid);
2671  }
2672 
2673  $resql = $this->db->query($sql);
2674  if ($resql) {
2675  $langs->load("bills");
2676  $now = dol_now();
2677 
2678  $response = new WorkboardResponse();
2679  $response->warning_delay = $conf->facture->fournisseur->warning_delay / 60 / 60 / 24;
2680  $response->label = $langs->trans("SupplierBillsToPay");
2681  $response->labelShort = $langs->trans("StatusToPay");
2682 
2683  $response->url = DOL_URL_ROOT.'/fourn/facture/list.php?search_status=1&mainmenu=billing&leftmenu=suppliers_bills';
2684  $response->img = img_object($langs->trans("Bills"), "bill");
2685 
2686  $facturestatic = new FactureFournisseur($this->db);
2687 
2688  while ($obj = $this->db->fetch_object($resql)) {
2689  $facturestatic->date_echeance = $this->db->jdate($obj->datefin);
2690  $facturestatic->statut = $obj->status; // For backward compatibility
2691  $facturestatic->status = $obj->status;
2692 
2693  $response->nbtodo++;
2694  $response->total += $obj->total_ht;
2695 
2696  if ($facturestatic->hasDelay()) {
2697  $response->nbtodolate++;
2698  $response->url_late = DOL_URL_ROOT.'/fourn/facture/list.php?search_option=late&mainmenu=billing&leftmenu=suppliers_bills';
2699  }
2700  }
2701 
2702  $this->db->free($resql);
2703  return $response;
2704  } else {
2705  dol_print_error($this->db);
2706  $this->error = $this->db->error();
2707  return -1;
2708  }
2709  }
2710 
2718  public function getTooltipContentArray($params)
2719  {
2720  global $conf, $langs;
2721 
2722  $langs->load('bills');
2723 
2724  $datas = [];
2725  $moretitle = $params['moretitle'] ?? '';
2726  $picto = $this->picto;
2727  if ($this->type == self::TYPE_REPLACEMENT) {
2728  $picto .= 'r'; // Replacement invoice
2729  }
2730  if ($this->type == self::TYPE_CREDIT_NOTE) {
2731  $picto .= 'a'; // Credit note
2732  }
2733  if ($this->type == self::TYPE_DEPOSIT) {
2734  $picto .= 'd'; // Deposit invoice
2735  }
2736 
2737  $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("SupplierInvoice").'</u>';
2738  if ($this->type == self::TYPE_REPLACEMENT) {
2739  $datas['picto'] .= '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("InvoiceReplace").'</u>';
2740  } elseif ($this->type == self::TYPE_CREDIT_NOTE) {
2741  $datas['picto'] .= '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("CreditNote").'</u>';
2742  } elseif ($this->type == self::TYPE_DEPOSIT) {
2743  $datas['picto'] .= '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("Deposit").'</u>';
2744  }
2745  if (isset($this->status)) {
2746  $alreadypaid = -1;
2747  if (isset($this->alreadypaid)) {
2748  $alreadypaid = $this->alreadypaid;
2749  }
2750 
2751  $datas['picto'] .= ' '.$this->getLibStatut(5, $alreadypaid);
2752  }
2753  if ($moretitle) {
2754  $datas['picto'] .= ' - '.$moretitle;
2755  }
2756  if (!empty($this->ref)) {
2757  $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
2758  }
2759  if (!empty($this->ref_supplier)) {
2760  $datas['refsupplier'] = '<br><b>'.$langs->trans('RefSupplier').':</b> '.$this->ref_supplier;
2761  }
2762  if (!empty($this->label)) {
2763  $datas['label'] = '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
2764  }
2765  if (!empty($this->date)) {
2766  $datas['date'] = '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
2767  }
2768  if (!empty($this->date_echeance)) {
2769  $datas['date_echeance'] = '<br><b>'.$langs->trans('DateDue').':</b> '.dol_print_date($this->date_echeance, 'day');
2770  }
2771  if (!empty($this->total_ht)) {
2772  $datas['amountht'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
2773  }
2774  if (!empty($this->total_tva)) {
2775  $datas['totaltva'] = '<br><b>'.$langs->trans('AmountVAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
2776  }
2777  if (!empty($this->total_ttc)) {
2778  $datas['totalttc'] = '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
2779  }
2780  return $datas;
2781  }
2782 
2796  public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
2797  {
2798  global $langs, $conf, $user, $hookmanager;
2799 
2800  $result = '';
2801 
2802  if ($option == 'withdraw') {
2803  $url = DOL_URL_ROOT.'/compta/facture/prelevement.php?facid='.$this->id.'&type=bank-transfer';
2804  } elseif ($option == 'document') {
2805  $url = DOL_URL_ROOT.'/fourn/facture/document.php?facid='.$this->id;
2806  } else {
2807  $url = DOL_URL_ROOT.'/fourn/facture/card.php?facid='.$this->id;
2808  }
2809 
2810  if ($short) {
2811  return $url;
2812  }
2813 
2814  if ($option !== 'nolink') {
2815  // Add param to save lastsearch_values or not
2816  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
2817  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
2818  $add_save_lastsearch_values = 1;
2819  }
2820  if ($add_save_lastsearch_values) {
2821  $url .= '&save_lastsearch_values=1';
2822  }
2823  }
2824 
2825  $picto = $this->picto;
2826  if ($this->type == self::TYPE_REPLACEMENT) {
2827  $picto .= 'r'; // Replacement invoice
2828  }
2829  if ($this->type == self::TYPE_CREDIT_NOTE) {
2830  $picto .= 'a'; // Credit note
2831  }
2832  if ($this->type == self::TYPE_DEPOSIT) {
2833  $picto .= 'd'; // Deposit invoice
2834  }
2835  $params = [
2836  'id' => $this->id,
2837  'objecttype' => $this->element,
2838  'option' => $option,
2839  'moretitle' => $moretitle,
2840  ];
2841  $classfortooltip = 'classfortooltip';
2842  $dataparams = '';
2843  if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
2844  $classfortooltip = 'classforajaxtooltip';
2845  $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
2846  $label = '';
2847  } else {
2848  $label = implode($this->getTooltipContentArray($params));
2849  }
2850 
2851  $ref = $this->ref;
2852  if (empty($ref)) {
2853  $ref = $this->id;
2854  }
2855 
2856  $linkclose = '';
2857  if (empty($notooltip)) {
2858  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2859  $label = $langs->trans("ShowSupplierInvoice");
2860  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
2861  }
2862  $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
2863  $linkclose .= $dataparams.' class="'.$classfortooltip.'"';
2864  }
2865 
2866  $linkstart = '<a href="'.$url.'"';
2867  $linkstart .= $linkclose.'>';
2868  $linkend = '</a>';
2869 
2870  $result .= $linkstart;
2871  if ($withpicto) {
2872  $result .= img_object(($notooltip ? '' : $label), $picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : $dataparams.' class="'.(($withpicto != 2) ? 'paddingright ' : '').$classfortooltip.'"'), 0, 0, $notooltip ? 0 : 1);
2873  }
2874  if ($withpicto != 2) {
2875  $result .= ($max ?dol_trunc($ref, $max) : $ref);
2876  }
2877  $result .= $linkend;
2878 
2879  if ($addlinktonotes) {
2880  $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
2881  if ($txttoshow) {
2882  $notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
2883  $result .= ' <span class="note inline-block">';
2884  $result .= '<a href="'.DOL_URL_ROOT.'/fourn/facture/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
2885  $result .= img_picto('', 'note');
2886  $result .= '</a>';
2887  $result .= '</span>';
2888  }
2889  }
2890  global $action;
2891  $hookmanager->initHooks(array($this->element . 'dao'));
2892  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
2893  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2894  if ($reshook > 0) {
2895  $result = $hookmanager->resPrint;
2896  } else {
2897  $result .= $hookmanager->resPrint;
2898  }
2899  return $result;
2900  }
2901 
2910  public function getNextNumRef($soc, $mode = 'next')
2911  {
2912  global $db, $langs, $conf;
2913  $langs->load("orders");
2914 
2915  // Clean parameters (if not defined or using deprecated value)
2916  if (empty($conf->global->INVOICE_SUPPLIER_ADDON_NUMBER)) {
2917  $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER = 'mod_facture_fournisseur_cactus';
2918  }
2919 
2920  $mybool = false;
2921 
2922  $file = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER.".php";
2923  $classname = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER;
2924 
2925  // Include file with class
2926  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2927 
2928  foreach ($dirmodels as $reldir) {
2929  $dir = dol_buildpath($reldir."core/modules/supplier_invoice/");
2930 
2931  // Load file with numbering class (if found)
2932  $mybool |= @include_once $dir.$file;
2933  }
2934 
2935  if ($mybool === false) {
2936  dol_print_error('', "Failed to include file ".$file);
2937  return '';
2938  }
2939 
2940  $obj = new $classname();
2941  $numref = "";
2942  $numref = $obj->getNumRef($soc, $this, $mode);
2943 
2944  if ($numref != "") {
2945  return $numref;
2946  } else {
2947  $this->error = $obj->error;
2948  return -1;
2949  }
2950  }
2951 
2952 
2961  public function initAsSpecimen($option = '')
2962  {
2963  global $langs, $conf;
2964  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
2965 
2966  $now = dol_now();
2967 
2968  // Load array of products prodids
2969  $num_prods = 0;
2970  $prodids = array();
2971 
2972  $sql = "SELECT rowid";
2973  $sql .= " FROM ".MAIN_DB_PREFIX."product";
2974  $sql .= " WHERE entity IN (".getEntity('product').")";
2975  $sql .= $this->db->plimit(100);
2976 
2977  $resql = $this->db->query($sql);
2978  if ($resql) {
2979  $num_prods = $this->db->num_rows($resql);
2980  $i = 0;
2981  while ($i < $num_prods) {
2982  $i++;
2983  $row = $this->db->fetch_row($resql);
2984  $prodids[$i] = $row[0];
2985  }
2986  }
2987 
2988  // Initialise parametres
2989  $this->id = 0;
2990  $this->ref = 'SPECIMEN';
2991  $this->ref_supplier = 'SUPPLIER_REF_SPECIMEN';
2992  $this->specimen = 1;
2993  $this->socid = 1;
2994  $this->date = $now;
2995  $this->date_lim_reglement = $this->date + 3600 * 24 * 30;
2996  $this->cond_reglement_code = 'RECEP';
2997  $this->mode_reglement_code = 'CHQ';
2998 
2999  $this->note_public = 'This is a comment (public)';
3000  $this->note_private = 'This is a comment (private)';
3001 
3002  $this->multicurrency_tx = 1;
3003  $this->multicurrency_code = $conf->currency;
3004 
3005  $xnbp = 0;
3006  if (empty($option) || $option != 'nolines') {
3007  // Lines
3008  $nbp = 5;
3009  while ($xnbp < $nbp) {
3010  $line = new SupplierInvoiceLine($this->db);
3011  $line->desc = $langs->trans("Description")." ".$xnbp;
3012  $line->qty = 1;
3013  $line->subprice = 100;
3014  $line->pu_ht = 100; // the canelle template use pu_ht and not subprice
3015  $line->price = 100;
3016  $line->tva_tx = 19.6;
3017  $line->localtax1_tx = 0;
3018  $line->localtax2_tx = 0;
3019  if ($xnbp == 2) {
3020  $line->total_ht = 50;
3021  $line->total_ttc = 59.8;
3022  $line->total_tva = 9.8;
3023  $line->remise_percent = 50;
3024  } else {
3025  $line->total_ht = 100;
3026  $line->total_ttc = 119.6;
3027  $line->total_tva = 19.6;
3028  $line->remise_percent = 0;
3029  }
3030 
3031  if ($num_prods > 0) {
3032  $prodid = mt_rand(1, $num_prods);
3033  $line->fk_product = $prodids[$prodid];
3034  }
3035  $line->product_type = 0;
3036 
3037  $this->lines[$xnbp] = $line;
3038 
3039  $this->total_ht += $line->total_ht;
3040  $this->total_tva += $line->total_tva;
3041  $this->total_ttc += $line->total_ttc;
3042 
3043  $xnbp++;
3044  }
3045  }
3046 
3047  $this->amount_ht = $xnbp * 100;
3048  $this->total_ht = $xnbp * 100;
3049  $this->total_tva = $xnbp * 19.6;
3050  $this->total_ttc = $xnbp * 119.6;
3051  }
3052 
3053  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3059  public function load_state_board()
3060  {
3061  // phpcs:enable
3062  global $conf, $user;
3063 
3064  $this->nb = array();
3065 
3066  $clause = "WHERE";
3067 
3068  $sql = "SELECT count(f.rowid) as nb";
3069  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
3070  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
3071  if (empty($user->rights->societe->client->voir) && !$user->socid) {
3072  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
3073  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3074  $clause = "AND";
3075  }
3076  $sql .= " ".$clause." f.entity = ".$conf->entity;
3077 
3078  $resql = $this->db->query($sql);
3079  if ($resql) {
3080  while ($obj = $this->db->fetch_object($resql)) {
3081  $this->nb["supplier_invoices"] = $obj->nb;
3082  }
3083  $this->db->free($resql);
3084  return 1;
3085  } else {
3086  dol_print_error($this->db);
3087  $this->error = $this->db->error();
3088  return -1;
3089  }
3090  }
3091 
3100  public function createFromClone(User $user, $fromid, $invertdetail = 0)
3101  {
3102  global $conf, $langs;
3103 
3104  $error = 0;
3105 
3106  $object = new FactureFournisseur($this->db);
3107 
3108  $this->db->begin();
3109 
3110  // Load source object
3111  $object->fetch($fromid);
3112  $object->id = 0;
3113  $object->statut = self::STATUS_DRAFT; // For backward compatibility
3114  $object->status = self::STATUS_DRAFT;
3115 
3116  $object->fetch_thirdparty(); // We need it to recalculate VAT localtaxes according to main sale taxes and vendor
3117 
3118  // Clear fields
3119  $object->ref_supplier = (empty($this->ref_supplier) ? $langs->trans("CopyOf").' '.$object->ref_supplier : $this->ref_supplier);
3120  $object->author = $user->id;
3121  $object->user_valid = 0;
3122  $object->fk_facture_source = 0;
3123  $object->date_creation = '';
3124  $object->date_validation = '';
3125  $object->date = (empty($this->date) ? dol_now() : $this->date);
3126  $object->ref_client = '';
3127  $object->close_code = '';
3128  $object->close_note = '';
3129  if (getDolGlobalInt('MAIN_DONT_KEEP_NOTE_ON_CLONING') == 1) {
3130  $object->note_private = '';
3131  $object->note_public = '';
3132  }
3133 
3134  $object->date_echeance = $object->calculate_date_lim_reglement();
3135 
3136  // Loop on each line of new invoice
3137  foreach ($object->lines as $i => $line) {
3138  if (isset($object->lines[$i]->info_bits) && ($object->lines[$i]->info_bits & 0x02) == 0x02) { // We do not clone line of discounts
3139  unset($object->lines[$i]);
3140  }
3141  }
3142 
3143  // Create clone
3144  $object->context['createfromclone'] = 'createfromclone';
3145  $result = $object->create($user);
3146 
3147  // Other options
3148  if ($result < 0) {
3149  $this->error = $object->error;
3150  $this->errors = $object->errors;
3151  $error++;
3152  }
3153 
3154  if (!$error) {
3155  }
3156 
3157  unset($object->context['createfromclone']);
3158 
3159  // End
3160  if (!$error) {
3161  $this->db->commit();
3162  return $object->id;
3163  } else {
3164  $this->db->rollback();
3165  return -1;
3166  }
3167  }
3168 
3180  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
3181  {
3182  global $conf, $user, $langs;
3183 
3184  $langs->load("suppliers");
3185  $outputlangs->load("products");
3186 
3187  // Set the model on the model name to use
3188  if (empty($modele)) {
3189  if (!empty($conf->global->INVOICE_SUPPLIER_ADDON_PDF)) {
3190  $modele = $conf->global->INVOICE_SUPPLIER_ADDON_PDF;
3191  } else {
3192  $modele = ''; // No default value. For supplier invoice, we allow to disable all PDF generation
3193  }
3194  }
3195 
3196  if (empty($modele)) {
3197  return 0;
3198  } else {
3199  $modelpath = "core/modules/supplier_invoice/doc/";
3200 
3201  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
3202  }
3203  }
3204 
3209  public function getRights()
3210  {
3211  global $user;
3212 
3213  return $user->rights->fournisseur->facture;
3214  }
3215 
3224  public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
3225  {
3226  $tables = array(
3227  'facture_fourn'
3228  );
3229 
3230  return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
3231  }
3232 
3241  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
3242  {
3243  $tables = array(
3244  'facture_fourn_det'
3245  );
3246 
3247  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
3248  }
3249 
3255  public function hasDelay()
3256  {
3257  global $conf;
3258 
3259  $now = dol_now();
3260 
3261  if (!$this->date_echeance) {
3262  return false;
3263  }
3264 
3265  $status = isset($this->status) ? $this->status : $this->statut;
3266 
3267  return ($status == self::STATUS_VALIDATED) && ($this->date_echeance < ($now - $conf->facture->fournisseur->warning_delay));
3268  }
3269 
3275  public function isCreditNoteUsed()
3276  {
3277  $isUsed = false;
3278 
3279  $sql = "SELECT fk_invoice_supplier FROM ".MAIN_DB_PREFIX."societe_remise_except WHERE fk_invoice_supplier_source = ".((int) $this->id);
3280  $resql = $this->db->query($sql);
3281  if (!empty($resql)) {
3282  $obj = $this->db->fetch_object($resql);
3283  if (!empty($obj->fk_invoice_supplier)) {
3284  $isUsed = true;
3285  }
3286  }
3287 
3288  return $isUsed;
3289  }
3297  public function getKanbanView($option = '', $arraydata = null)
3298  {
3299  global $langs;
3300 
3301  $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
3302 
3303  $return = '<div class="box-flex-item box-flex-grow-zero">';
3304  $return .= '<div class="info-box info-box-sm">';
3305  $return .= '<span class="info-box-icon bg-infobox-action">';
3306  $return .= img_picto('', $this->picto);
3307  $return .= '</span>';
3308  $return .= '<div class="info-box-content">';
3309  $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
3310  $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
3311  if (!empty($arraydata['thirdparty'])) {
3312  $return .= '<br><span class="info-box-label">'.$arraydata['thirdparty'].'</span>';
3313  }
3314  if (property_exists($this, 'date')) {
3315  $return .= '<br><span class="info-box-label">'.dol_print_date($this->date, 'day').'</span>';
3316  }
3317  if (property_exists($this, 'total_ht')) {
3318  $return .= ' &nbsp; <span class="info-box-label amount" title="'.dol_escape_htmltag($langs->trans("AmountHT")).'">'.price($this->total_ht);
3319  $return .= ' '.$langs->trans("HT");
3320  $return .= '</span>';
3321  }
3322  if (method_exists($this, 'getLibStatut')) {
3323  $alreadypaid = (empty($arraydata['alreadypaid']) ? 0 : $arraydata['alreadypaid']);
3324  $return .= '<br><div class="info-box-status margintoponly">'.$this->getLibStatut(3, $alreadypaid).'</div>';
3325  }
3326  $return .= '</div>';
3327  $return .= '</div>';
3328  $return .= '</div>';
3329  return $return;
3330  }
3331 
3338  public function setVATReverseCharge($vatreversecharge)
3339  {
3340  if (!$this->table_element) {
3341  dol_syslog(get_class($this)."::setVATReverseCharge was called on objet with property table_element not defined", LOG_ERR);
3342  return -1;
3343  }
3344 
3345  dol_syslog(get_class($this).'::setVATReverseCharge('.$vatreversecharge.')');
3346 
3347  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3348  $sql .= " SET vat_reverse_charge = ".((int) $vatreversecharge);
3349  $sql .= " WHERE rowid=".((int) $this->id);
3350 
3351  if ($this->db->query($sql)) {
3352  $this->vat_reverse_charge = ($vatreversecharge == 0) ? 0 : 1;
3353  return 1;
3354  } else {
3355  dol_syslog(get_class($this).'::setVATReverseCharge Error ', LOG_DEBUG);
3356  $this->error = $this->db->error();
3357  return 0;
3358  }
3359  }
3360 }
3361 
3362 
3363 
3368 {
3372  public $element = 'facture_fourn_det';
3373 
3377  public $table_element = 'facture_fourn_det';
3378 
3379  public $oldline;
3380 
3385  public $ref;
3386 
3391  public $product_ref;
3392 
3398  public $ref_supplier;
3399 
3404  public $product_desc;
3405 
3412  public $pu_ht;
3413 
3418  public $subprice;
3419 
3424  public $pu_ttc;
3425 
3426 
3431  public $fk_facture_fourn;
3432 
3438  public $label;
3439 
3444  public $description;
3445 
3446  public $date_start;
3447  public $date_end;
3448 
3449  public $skip_update_total; // Skip update price total for special lines
3450 
3454  public $situation_percent;
3455 
3459  public $fk_prev_id;
3460 
3465  public $vat_src_code;
3466 
3471  public $tva_tx;
3472 
3477  public $localtax1_tx;
3478 
3483  public $localtax2_tx;
3484 
3489  public $qty;
3490 
3495  public $remise_percent;
3496 
3501  public $pa_ht;
3502 
3507  public $total_ht;
3508 
3513  public $total_ttc;
3514 
3519  public $total_tva;
3520 
3525  public $total_localtax1;
3526 
3531  public $total_localtax2;
3532 
3536  public $fk_product;
3537 
3542  public $product_type;
3543 
3548  public $product_label;
3549 
3556  public $info_bits;
3557 
3562  public $fk_remise_except;
3563 
3567  public $fk_parent_line;
3568 
3569  public $special_code;
3570 
3574  public $rang;
3575 
3580  public $localtax1_type;
3581 
3586  public $localtax2_type;
3587 
3588  // Multicurrency
3592  public $fk_multicurrency;
3593 
3594  public $multicurrency_code;
3595  public $multicurrency_subprice;
3596  public $multicurrency_total_ht;
3597  public $multicurrency_total_tva;
3598  public $multicurrency_total_ttc;
3599 
3600 
3606  public function __construct($db)
3607  {
3608  $this->db = $db;
3609  }
3610 
3617  public function fetch($rowid)
3618  {
3619  $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';
3620  $sql .= ', f.localtax1_type, f.localtax2_type, f.localtax1_tx, f.localtax2_tx, f.total_localtax1, f.total_localtax2, f.fk_remise_except';
3621  $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';
3622  $sql .= ', p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.description as product_desc';
3623  $sql .= ', f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, multicurrency_total_ttc';
3624  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
3625  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
3626  $sql .= ' WHERE f.rowid = '.((int) $rowid);
3627  $sql .= ' ORDER BY f.rang, f.rowid';
3628 
3629  $query = $this->db->query($sql);
3630 
3631  if (!$query) {
3632  $this->errors[] = $this->db->error();
3633  return -1;
3634  }
3635 
3636  if (!$this->db->num_rows($query)) {
3637  return 0;
3638  }
3639 
3640  $obj = $this->db->fetch_object($query);
3641 
3642  $this->id = $obj->rowid;
3643  $this->rowid = $obj->rowid;
3644  $this->fk_facture_fourn = $obj->fk_facture_fourn;
3645  $this->description = $obj->description;
3646  $this->date_start = $obj->date_start;
3647  $this->date_end = $obj->date_end;
3648  $this->product_ref = $obj->product_ref;
3649  $this->ref_supplier = $obj->ref_supplier;
3650  $this->product_desc = $obj->product_desc;
3651 
3652  $this->subprice = $obj->pu_ht;
3653  $this->pu_ht = $obj->pu_ht;
3654  $this->pu_ttc = $obj->pu_ttc;
3655  $this->tva_tx = $obj->tva_tx;
3656  $this->localtax1_tx = $obj->localtax1_tx;
3657  $this->localtax2_tx = $obj->localtax2_tx;
3658  $this->localtax1_type = $obj->localtax1_type;
3659  $this->localtax2_type = $obj->localtax2_type;
3660 
3661  $this->qty = $obj->qty;
3662  $this->remise_percent = $obj->remise_percent;
3663  $this->fk_remise_except = $obj->fk_remise_except;
3664  //$this->tva = $obj->total_tva; // deprecated
3665  $this->total_ht = $obj->total_ht;
3666  $this->total_tva = $obj->total_tva;
3667  $this->total_localtax1 = $obj->total_localtax1;
3668  $this->total_localtax2 = $obj->total_localtax2;
3669  $this->total_ttc = $obj->total_ttc;
3670  $this->fk_product = $obj->fk_product;
3671  $this->product_type = $obj->product_type;
3672  $this->product_label = $obj->product_label;
3673  $this->info_bits = $obj->info_bits;
3674  $this->tva_npr = ($obj->info_bits & 1 == 1) ? 1 : 0;
3675  $this->fk_parent_line = $obj->fk_parent_line;
3676  $this->special_code = $obj->special_code;
3677  $this->rang = $obj->rang;
3678  $this->fk_unit = $obj->fk_unit;
3679 
3680  $this->multicurrency_subprice = $obj->multicurrency_subprice;
3681  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
3682  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
3683  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
3684 
3685  $this->fetch_optionals();
3686 
3687  return 1;
3688  }
3689 
3696  public function delete($notrigger = 0)
3697  {
3698  global $user, $conf;
3699 
3700  dol_syslog(get_class($this)."::deleteline rowid=".((int) $this->id), LOG_DEBUG);
3701 
3702  $error = 0;
3703 
3704  $this->db->begin();
3705 
3706  if (!$notrigger) {
3707  if ($this->call_trigger('LINEBILL_SUPPLIER_DELETE', $user) < 0) {
3708  $error++;
3709  }
3710  }
3711 
3712  $this->deleteObjectLinked();
3713 
3714  // Remove extrafields
3715  if (!$error) {
3716  $result = $this->deleteExtraFields();
3717  if ($result < 0) {
3718  $error++;
3719  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
3720  }
3721  }
3722 
3723  if (!$error) {
3724  // Supprime ligne
3725  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det ';
3726  $sql .= " WHERE rowid = ".((int) $this->id);
3727  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
3728  $resql = $this->db->query($sql);
3729  if (!$resql) {
3730  $error++;
3731  $this->error = $this->db->lasterror();
3732  }
3733  }
3734 
3735  if (!$error) {
3736  $this->db->commit();
3737  return 1;
3738  } else {
3739  $this->db->rollback();
3740  return -1;
3741  }
3742  }
3743 
3750  public function update($notrigger = 0)
3751  {
3752  global $conf;
3753 
3754  $pu = price2num($this->pu_ht);
3755  $qty = price2num($this->qty);
3756 
3757  // Check parameters
3758  if (empty($this->qty)) {
3759  $this->qty = 0;
3760  }
3761 
3762  if ($this->product_type < 0) {
3763  return -1;
3764  }
3765 
3766  // Clean parameters
3767  if (empty($this->remise_percent)) {
3768  $this->remise_percent = 0;
3769  }
3770  if (empty($this->tva_tx)) {
3771  $this->tva_tx = 0;
3772  }
3773  if (empty($this->localtax1_tx)) {
3774  $this->localtax1_tx = 0;
3775  }
3776  if (empty($this->localtax2_tx)) {
3777  $this->localtax2_tx = 0;
3778  }
3779 
3780  if (empty($this->pa_ht)) {
3781  $this->pa_ht = 0;
3782  }
3783  if (empty($this->multicurrency_subprice)) {
3784  $this->multicurrency_subprice = 0;
3785  }
3786  if (empty($this->multicurrency_total_ht)) {
3787  $this->multicurrency_total_ht = 0;
3788  }
3789  if (empty($this->multicurrency_total_tva)) {
3790  $this->multicurrency_total_tva = 0;
3791  }
3792  if (empty($this->multicurrency_total_ttc)) {
3793  $this->multicurrency_total_ttc = 0;
3794  }
3795 
3796  $fk_product = (int) $this->fk_product;
3797  $fk_unit = (int) $this->fk_unit;
3798 
3799  $this->db->begin();
3800 
3801  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
3802  $sql .= " description = '".$this->db->escape($this->description)."'";
3803  $sql .= ", ref = '".$this->db->escape($this->ref_supplier ? $this->ref_supplier : $this->ref)."'";
3804  $sql .= ", date_start = ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : "null");
3805  $sql .= ", date_end = ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : "null");
3806  $sql .= ", pu_ht = ".price2num($this->pu_ht);
3807  $sql .= ", pu_ttc = ".price2num($this->pu_ttc);
3808  $sql .= ", qty = ".price2num($this->qty);
3809  $sql .= ", remise_percent = ".price2num($this->remise_percent);
3810  if ($this->fk_remise_except > 0) $sql .= ", fk_remise_except=".((int) $this->fk_remise_except);
3811  else $sql .= ", fk_remise_except=null";
3812  $sql .= ", vat_src_code = '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."'";
3813  $sql .= ", tva_tx = ".price2num($this->tva_tx);
3814  $sql .= ", localtax1_tx = ".price2num($this->localtax1_tx);
3815  $sql .= ", localtax2_tx = ".price2num($this->localtax2_tx);
3816  $sql .= ", localtax1_type = '".$this->db->escape($this->localtax1_type)."'";
3817  $sql .= ", localtax2_type = '".$this->db->escape($this->localtax2_type)."'";
3818  $sql .= ", total_ht = ".price2num($this->total_ht);
3819  $sql .= ", tva= ".price2num($this->total_tva);
3820  $sql .= ", total_localtax1= ".price2num($this->total_localtax1);
3821  $sql .= ", total_localtax2= ".price2num($this->total_localtax2);
3822  $sql .= ", total_ttc = ".price2num($this->total_ttc);
3823  $sql .= ", fk_product = ".($fk_product > 0 ? (int) $fk_product : 'null');
3824  $sql .= ", product_type = ".((int) $this->product_type);
3825  $sql .= ", info_bits = ".((int) $this->info_bits);
3826  $sql .= ", fk_unit = ".($fk_unit > 0 ? (int) $fk_unit : 'null');
3827 
3828  if (!empty($this->rang)) {
3829  $sql .= ", rang=".((int) $this->rang);
3830  }
3831 
3832  // Multicurrency
3833  $sql .= " , multicurrency_subprice=".price2num($this->multicurrency_subprice);
3834  $sql .= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht);
3835  $sql .= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva);
3836  $sql .= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc);
3837 
3838  $sql .= " WHERE rowid = ".((int) $this->id);
3839 
3840  dol_syslog(get_class($this)."::update", LOG_DEBUG);
3841  $resql = $this->db->query($sql);
3842 
3843  if (!$resql) {
3844  $this->db->rollback();
3845  $this->error = $this->db->lasterror();
3846  return -1;
3847  }
3848 
3849  $this->rowid = $this->id;
3850  $error = 0;
3851 
3852  if (!$error) {
3853  $result = $this->insertExtraFields();
3854  if ($result < 0) {
3855  $error++;
3856  }
3857  }
3858 
3859  if (!$error && !$notrigger) {
3860  global $langs, $user;
3861 
3862  // Call trigger
3863  if ($this->call_trigger('LINEBILL_SUPPLIER_MODIFY', $user) < 0) {
3864  $this->db->rollback();
3865  return -1;
3866  }
3867  // End call triggers
3868  }
3869 
3870  if ($error) {
3871  $this->db->rollback();
3872  return -1;
3873  }
3874 
3875  $this->db->commit();
3876  return 1;
3877  }
3878 
3885  public function insert($notrigger = 0)
3886  {
3887  global $user, $conf, $langs;
3888 
3889  $error = 0;
3890 
3891  dol_syslog(get_class($this)."::insert rang=".$this->rang, LOG_DEBUG);
3892 
3893  // Clean parameters
3894  $this->desc = trim($this->desc);
3895  if (empty($this->tva_tx)) {
3896  $this->tva_tx = 0;
3897  }
3898  if (empty($this->localtax1_tx)) {
3899  $this->localtax1_tx = 0;
3900  }
3901  if (empty($this->localtax2_tx)) {
3902  $this->localtax2_tx = 0;
3903  }
3904  if (empty($this->localtax1_type)) {
3905  $this->localtax1_type = '0';
3906  }
3907  if (empty($this->localtax2_type)) {
3908  $this->localtax2_type = '0';
3909  }
3910  if (empty($this->total_tva)) {
3911  $this->total_tva = 0;
3912  }
3913  if (empty($this->total_localtax1)) {
3914  $this->total_localtax1 = 0;
3915  }
3916  if (empty($this->total_localtax2)) {
3917  $this->total_localtax2 = 0;
3918  }
3919  if (empty($this->rang)) {
3920  $this->rang = 0;
3921  }
3922  if (empty($this->remise_percent)) {
3923  $this->remise_percent = 0;
3924  }
3925  if (empty($this->info_bits)) {
3926  $this->info_bits = 0;
3927  }
3928  if (empty($this->subprice)) {
3929  $this->subprice = 0;
3930  }
3931  if (empty($this->special_code)) {
3932  $this->special_code = 0;
3933  }
3934  if (empty($this->fk_parent_line)) {
3935  $this->fk_parent_line = 0;
3936  }
3937  if (!isset($this->situation_percent) || $this->situation_percent > 100 || (string) $this->situation_percent == '') {
3938  $this->situation_percent = 100;
3939  }
3940 
3941  if (empty($this->pa_ht)) {
3942  $this->pa_ht = 0;
3943  }
3944  if (empty($this->multicurrency_subprice)) {
3945  $this->multicurrency_subprice = 0;
3946  }
3947  if (empty($this->multicurrency_total_ht)) {
3948  $this->multicurrency_total_ht = 0;
3949  }
3950  if (empty($this->multicurrency_total_tva)) {
3951  $this->multicurrency_total_tva = 0;
3952  }
3953  if (empty($this->multicurrency_total_ttc)) {
3954  $this->multicurrency_total_ttc = 0;
3955  }
3956 
3957 
3958  // Check parameters
3959  if ($this->product_type < 0) {
3960  $this->error = 'ErrorProductTypeMustBe0orMore';
3961  return -1;
3962  }
3963  if (!empty($this->fk_product) && $this->fk_product > 0) {
3964  // Check product exists
3965  $result = Product::isExistingObject('product', $this->fk_product);
3966  if ($result <= 0) {
3967  $this->error = 'ErrorProductIdDoesNotExists';
3968  return -1;
3969  }
3970  }
3971 
3972  $this->db->begin();
3973 
3974  // Insertion dans base de la ligne
3975  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
3976  $sql .= ' (fk_facture_fourn, fk_parent_line, label, description, ref, qty,';
3977  $sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3978  $sql .= ' fk_product, product_type, remise_percent, fk_remise_except, pu_ht, pu_ttc,';
3979  $sql .= ' date_start, date_end, fk_code_ventilation, rang, special_code,';
3980  $sql .= ' info_bits, total_ht, tva, total_ttc, total_localtax1, total_localtax2, fk_unit';
3981  $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
3982  $sql .= ')';
3983  $sql .= " VALUES (".$this->fk_facture_fourn.",";
3984  $sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape($this->fk_parent_line)."'" : "null").",";
3985  $sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
3986  $sql .= " '".$this->db->escape($this->desc ? $this->desc : $this->description)."',";
3987  $sql .= " '".$this->db->escape($this->ref_supplier)."',";
3988  $sql .= " ".price2num($this->qty).",";
3989 
3990  $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape($this->vat_src_code)."'").",";
3991  $sql .= " ".price2num($this->tva_tx).",";
3992  $sql .= " ".price2num($this->localtax1_tx).",";
3993  $sql .= " ".price2num($this->localtax2_tx).",";
3994  $sql .= " '".$this->db->escape($this->localtax1_type)."',";
3995  $sql .= " '".$this->db->escape($this->localtax2_type)."',";
3996  $sql .= ' '.((!empty($this->fk_product) && $this->fk_product > 0) ? $this->fk_product : "null").',';
3997  $sql .= " ".((int) $this->product_type).",";
3998  $sql .= " ".price2num($this->remise_percent).",";
3999  $sql .= ' '.(!empty($this->fk_remise_except) ? ((int) $this->fk_remise_except) : "null").',';
4000  $sql .= " ".price2num($this->subprice).",";
4001  $sql .= " ".(!empty($this->qty) ?price2num($this->total_ttc / $this->qty) : price2num($this->total_ttc)).",";
4002  $sql .= " ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null").",";
4003  $sql .= " ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").",";
4004  $sql .= ' '.(!empty($this->fk_code_ventilation) ? $this->fk_code_ventilation : 0).',';
4005  $sql .= ' '.((int) $this->rang).',';
4006  $sql .= ' '.((int) $this->special_code).',';
4007  $sql .= " ".((int) $this->info_bits).",";
4008  $sql .= " ".price2num($this->total_ht).",";
4009  $sql .= " ".price2num($this->total_tva).",";
4010  $sql .= " ".price2num($this->total_ttc).",";
4011  $sql .= " ".price2num($this->total_localtax1).",";
4012  $sql .= " ".price2num($this->total_localtax2);
4013  $sql .= ", ".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
4014  $sql .= ", ".(int) $this->fk_multicurrency;
4015  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
4016  $sql .= ", ".price2num($this->multicurrency_subprice);
4017  $sql .= ", ".price2num($this->multicurrency_total_ht);
4018  $sql .= ", ".price2num($this->multicurrency_total_tva);
4019  $sql .= ", ".price2num($this->multicurrency_total_ttc);
4020  $sql .= ')';
4021 
4022  $resql = $this->db->query($sql);
4023  if ($resql) {
4024  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
4025  $this->rowid = $this->id; // backward compatibility
4026 
4027  if (!$error) {
4028  $result = $this->insertExtraFields();
4029  if ($result < 0) {
4030  $error++;
4031  }
4032  }
4033 
4034  // Si fk_remise_except defini, on lie la remise a la facture
4035  // ce qui la flague comme "consommee".
4036  if ($this->fk_remise_except) {
4037  $discount = new DiscountAbsolute($this->db);
4038  $result = $discount->fetch($this->fk_remise_except);
4039  if ($result >= 0) {
4040  // Check if discount was found
4041  if ($result > 0) {
4042  // Check if discount not already affected to another invoice
4043  if ($discount->fk_facture_line > 0) {
4044  if (empty($noerrorifdiscountalreadylinked)) {
4045  $this->error = $langs->trans("ErrorDiscountAlreadyUsed", $discount->id);
4046  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
4047  $this->db->rollback();
4048  return -3;
4049  }
4050  } else {
4051  $result = $discount->link_to_invoice($this->rowid, 0);
4052  if ($result < 0) {
4053  $this->error = $discount->error;
4054  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
4055  $this->db->rollback();
4056  return -3;
4057  }
4058  }
4059  } else {
4060  $this->error = $langs->trans("ErrorADiscountThatHasBeenRemovedIsIncluded");
4061  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
4062  $this->db->rollback();
4063  return -3;
4064  }
4065  } else {
4066  $this->error = $discount->error;
4067  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
4068  $this->db->rollback();
4069  return -3;
4070  }
4071  }
4072 
4073  if (!$error && !$notrigger) {
4074  // Call trigger
4075  $result = $this->call_trigger('LINEBILL_SUPPLIER_CREATE', $user);
4076  if ($result < 0) {
4077  $this->db->rollback();
4078  return -2;
4079  }
4080  // End call triggers
4081  }
4082 
4083  $this->db->commit();
4084  return $this->id;
4085  } else {
4086  $this->error = $this->db->error();
4087  $this->db->rollback();
4088  return -2;
4089  }
4090  }
4091 
4092  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4098  public function update_total()
4099  {
4100  // phpcs:enable
4101  $this->db->begin();
4102 
4103  // Mise a jour ligne en base
4104  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
4105  $sql .= " total_ht = ".price2num($this->total_ht);
4106  $sql .= ", tva= ".price2num($this->total_tva);
4107  $sql .= ", total_localtax1 = ".price2num($this->total_localtax1);
4108  $sql .= ", total_localtax2 = ".price2num($this->total_localtax2);
4109  $sql .= ", total_ttc = ".price2num($this->total_ttc);
4110  $sql .= " WHERE rowid = ".((int) $this->rowid);
4111 
4112  dol_syslog("FactureFournisseurLigne.class.php::update_total", LOG_DEBUG);
4113 
4114  $resql = $this->db->query($sql);
4115  if ($resql) {
4116  $this->db->commit();
4117  return 1;
4118  } else {
4119  $this->error = $this->db->error();
4120  $this->db->rollback();
4121  return -2;
4122  }
4123  }
4124 }
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:8337
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:6386
dol_escape_htmltag
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=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:1594
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:4049
SupplierInvoiceLine\fetch
fetch($rowid)
Retrieves a supplier invoice line.
Definition: fournisseur.facture.class.php:3617
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1322
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:1483
FactureFournisseur\info
info($id)
Loads the info order information into the invoice object.
Definition: fournisseur.facture.class.php:2508
DoliDB
Class to manage Dolibarr database access.
Definition: DoliDB.class.php:30
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:607
CommonObject\updateRangOfLine
updateRangOfLine($rowid, $rang)
Update position of line (rang)
Definition: commonobject.class.php:3138
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:5096
FactureFournisseur\hasDelay
hasDelay()
Is the payment of the supplier invoice having a delay?
Definition: fournisseur.facture.class.php:3255
FactureFournisseur\getKanbanView
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually picto)
Definition: fournisseur.facture.class.php:3297
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:1157
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:3750
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:2297
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:2454
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:4143
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:1779
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:2961
SupplierInvoiceLine\$ref
$ref
Definition: fournisseur.facture.class.php:3385
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:5943
SupplierInvoiceLine
Class to manage line invoices.
Definition: fournisseur.facture.class.php:3367
FactureFournisseur\load_board
load_board($user)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: fournisseur.facture.class.php:2656
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:2665
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:3224
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:1613
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:7705
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:4125
FactureFournisseur\isCreditNoteUsed
isCreditNoteUsed()
Is credit note used.
Definition: fournisseur.facture.class.php:3275
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:2910
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:5334
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:1332
SupplierInvoiceLine\__construct
__construct($db)
Constructor.
Definition: fournisseur.facture.class.php:3606
FactureFournisseur\setPaid
setPaid($user, $close_code='', $close_note='')
Tag invoice as a paid invoice.
Definition: fournisseur.facture.class.php:1598
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:3450
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:6870
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:3241
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:3885
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:6110
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:669
$sql
if(isModEnabled('facture') &&!empty($user->rights->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
FactureFournisseur\setDraft
setDraft($user, $idwarehouse=-1)
Set draft status.
Definition: fournisseur.facture.class.php:1932
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:7034
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:8498
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:10100
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1732
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:2035
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:2605
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:3296
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:5959
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:1661
FactureFournisseur\setVATReverseCharge
setVATReverseCharge($vatreversecharge)
Change the option VAT reverse charge.
Definition: fournisseur.facture.class.php:3338
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3987
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:2718
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:1583
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:6070
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:3733
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:1722
FactureFournisseur\getRights
getRights()
Returns the rights used for this class.
Definition: fournisseur.facture.class.php:3209
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:1676
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:4462
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:3046
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:5817
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5743
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:3100
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:2796
FactureFournisseur\load_state_board
load_state_board()
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: fournisseur.facture.class.php:3059
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:3180
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:2974
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:8469
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:4098
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:7733
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:8460
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:2555
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