dolibarr  16.0.5
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-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
14  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
15  * Copyright (C) 2018-2022 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.'/product/class/product.class.php';
42 
43 if (!empty($conf->accounting->enabled)) {
44  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
45 }
46 if (!empty($conf->accounting->enabled)) {
47  require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
48 }
49 
54 {
58  public $element = 'invoice_supplier';
59 
63  public $table_element = 'facture_fourn';
64 
68  public $table_element_line = 'facture_fourn_det';
69 
73  public $fk_element = 'fk_facture_fourn';
74 
78  public $picto = 'supplier_invoice';
79 
84  public $ismultientitymanaged = 1;
85 
90  public $restrictiononfksoc = 1;
91 
95  protected $table_ref_field = 'ref';
96 
100  public $rowid;
101 
105  public $ref;
106 
110  public $ref_supplier;
111 
115  public $label;
116 
117  public $socid;
118 
119  //Check constants for types
120  public $type = self::TYPE_STANDARD;
121 
127  public $statut;
128 
134  public $status;
135 
141  public $close_code;
142 
147  public $close_note;
148 
153  public $paye;
154 
155  public $author;
156 
162  public $datec;
163 
169  public $tms;
170 
176  public $date;
177 
183  public $date_echeance;
184 
189  public $amount = 0;
194  public $remise = 0;
195 
200  public $tva;
201 
202  // Warning: Do not set default value into property defintion. it must stay null.
203  // For example to avoid to have substition done when object is generic and not yet defined.
204  public $localtax1;
205  public $localtax2;
206  public $total_ht;
207  public $total_tva;
208  public $total_localtax1;
209  public $total_localtax2;
210  public $total_ttc;
211 
216  public $note;
217 
218  public $note_private;
219  public $note_public;
220  public $propalid;
221 
222  public $cond_reglement_id;
223  public $cond_reglement_code;
224  public $cond_reglement_label;
225  public $cond_reglement_doc;
226 
230  public $fk_account; // default bank account
231 
232  public $mode_reglement_id;
233  public $mode_reglement_code;
234 
238  public $transport_mode_id;
239 
240  public $extraparams = array();
241 
246  public $lines = array();
247 
251  public $fournisseur;
252 
253  // Multicurrency
257  public $fk_multicurrency;
258 
259  public $multicurrency_code;
260  public $multicurrency_tx;
261  public $multicurrency_total_ht;
262  public $multicurrency_total_tva;
263  public $multicurrency_total_ttc;
265 
268  public $fk_facture_source;
269 
270  public $fac_rec;
271 
272 
273  public $fields = array(
274  'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
275  'ref' =>array('type'=>'varchar(255)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>15),
276  'ref_supplier' =>array('type'=>'varchar(255)', 'label'=>'RefSupplier', 'enabled'=>1, 'visible'=>-1, 'position'=>20),
277  'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>25, 'index'=>1),
278  'ref_ext' =>array('type'=>'varchar(255)', 'label'=>'RefExt', 'enabled'=>1, 'visible'=>0, 'position'=>30),
279  'type' =>array('type'=>'smallint(6)', 'label'=>'Type', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35),
280  'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>'$conf->societe->enabled', 'visible'=>-1, 'notnull'=>1, 'position'=>40),
281  'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
282  'datef' =>array('type'=>'date', 'label'=>'Date', 'enabled'=>1, 'visible'=>-1, 'position'=>50),
283  'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>55),
284  'libelle' =>array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>1, 'visible'=>-1, 'position'=>60),
285  'paye' =>array('type'=>'smallint(6)', 'label'=>'Paye', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>65),
286  'amount' =>array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>70),
287  'remise' =>array('type'=>'double(24,8)', 'label'=>'Discount', 'enabled'=>1, 'visible'=>-1, 'position'=>75),
288  'close_code' =>array('type'=>'varchar(16)', 'label'=>'CloseCode', 'enabled'=>1, 'visible'=>-1, 'position'=>80),
289  'close_note' =>array('type'=>'varchar(128)', 'label'=>'CloseNote', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
290  'tva' =>array('type'=>'double(24,8)', 'label'=>'Tva', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
291  'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>-1, 'position'=>95),
292  'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>-1, 'position'=>100),
293  'total_ht' =>array('type'=>'double(24,8)', 'label'=>'TotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
294  'total_tva' =>array('type'=>'double(24,8)', 'label'=>'TotalVAT', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
295  'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'TotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
296  'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-1, 'position'=>125),
297  'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>130),
298  'fk_user_valid' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>135),
299  'fk_facture_source' =>array('type'=>'integer', 'label'=>'Fk facture source', 'enabled'=>1, 'visible'=>-1, 'position'=>140),
300  'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label'=>'Project', 'enabled'=>'$conf->project->enabled', 'visible'=>-1, 'position'=>145),
301  'fk_account' =>array('type'=>'integer', 'label'=>'Account', 'enabled'=>'$conf->banque->enabled', 'visible'=>-1, 'position'=>150),
302  'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'PaymentTerm', 'enabled'=>1, 'visible'=>-1, 'position'=>155),
303  'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'PaymentMode', 'enabled'=>1, 'visible'=>-1, 'position'=>160),
304  'date_lim_reglement' =>array('type'=>'date', 'label'=>'DateLimReglement', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
305  'note_private' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>170),
306  'note_public' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>175),
307  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'ModelPdf', 'enabled'=>1, 'visible'=>0, 'position'=>180),
308  'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>190),
309  'fk_incoterms' =>array('type'=>'integer', 'label'=>'IncotermCode', 'enabled'=>1, 'visible'=>-1, 'position'=>195),
310  'location_incoterms' =>array('type'=>'varchar(255)', 'label'=>'IncotermLocation', 'enabled'=>1, 'visible'=>-1, 'position'=>200),
311  'fk_multicurrency' =>array('type'=>'integer', 'label'=>'MulticurrencyId', 'enabled'=>1, 'visible'=>-1, 'position'=>205),
312  'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'MulticurrencyCode', 'enabled'=>1, 'visible'=>-1, 'position'=>210),
313  'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyRate', 'enabled'=>1, 'visible'=>-1, 'position'=>215),
314  'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyTotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>220),
315  'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyTotalVAT', 'enabled'=>1, 'visible'=>-1, 'position'=>225),
316  'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyTotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>230),
317  'date_pointoftax' =>array('type'=>'date', 'label'=>'Date pointoftax', 'enabled'=>1, 'visible'=>-1, 'position'=>235),
318  'date_valid' =>array('type'=>'date', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>240),
319  'last_main_doc' =>array('type'=>'varchar(255)', 'label'=>'Last main doc', 'enabled'=>1, 'visible'=>-1, 'position'=>245),
320  'fk_statut' =>array('type'=>'smallint(6)', 'label'=>'Status', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>500),
321  'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>900),
322  );
323 
324 
328  const TYPE_STANDARD = 0;
329 
333  const TYPE_REPLACEMENT = 1;
334 
338  const TYPE_CREDIT_NOTE = 2;
339 
343  const TYPE_DEPOSIT = 3;
344 
348  const STATUS_DRAFT = 0;
349 
353  const STATUS_VALIDATED = 1;
354 
362  const STATUS_CLOSED = 2;
363 
371  const STATUS_ABANDONED = 3;
372 
373  const CLOSECODE_DISCOUNTVAT = 'discount_vat';
374  const CLOSECODE_BADCREDIT = 'badsupplier';
375  const CLOSECODE_ABANDONED = 'abandon';
376  const CLOSECODE_REPLACED = 'replaced';
377 
383  public function __construct($db)
384  {
385  $this->db = $db;
386  }
387 
394  public function create($user)
395  {
396  global $langs, $conf, $hookmanager;
397 
398  $error = 0;
399  $now = dol_now();
400 
401  // Clean parameters
402  if (isset($this->ref_supplier)) {
403  $this->ref_supplier = trim($this->ref_supplier);
404  }
405  if (empty($this->type)) {
406  $this->type = self::TYPE_STANDARD;
407  }
408  if (empty($this->date)) {
409  $this->date = $now;
410  }
411 
412  // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
413  if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) {
414  list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $this->date);
415  } else {
416  $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
417  }
418  if (empty($this->fk_multicurrency)) {
419  $this->multicurrency_code = $conf->currency;
420  $this->fk_multicurrency = 0;
421  $this->multicurrency_tx = 1;
422  }
423 
424  $this->db->begin();
425 
426  // Create invoice from a template recurring invoice
427  if ($this->fac_rec > 0) {
428  $this->fk_fac_rec_source = $this->fac_rec;
429 
430  require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture-rec.class.php';
431  $_facrec = new FactureFournisseurRec($this->db);
432  $result = $_facrec->fetch($this->fac_rec);
433  $result = $_facrec->fetchObjectLinked(null, '', null, '', 'OR', 1, 'sourcetype', 0); // This load $_facrec->linkedObjectsIds
434 
435  // Define some dates
436  if (! empty($_facrec->frequency)) {
437  $originaldatewhen = $_facrec->date_when;
438  $nextdatewhen = dol_time_plus_duree($originaldatewhen, $_facrec->frequency, $_facrec->unit_frequency);
439  $previousdaynextdatewhen = dol_time_plus_duree($nextdatewhen, -1, 'd');
440  $this->socid = $_facrec->socid;
441  }
442 
443  $this->entity = $_facrec->entity; // Invoice created in same entity than template
444 
445  // 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
446  $this->fk_project = GETPOST('projectid', 'int') > 0 ? ((int) GETPOST('projectid', 'int')) : $_facrec->fk_projet;
447  $this->fk_projet = $this->fk_project;
448  $this->note_public = GETPOST('note_public', 'restricthtml') ? GETPOST('note_public', 'restricthtml') : $_facrec->note_public;
449  $this->note_private = GETPOST('note_private', 'restricthtml') ? GETPOST('note_private', 'restricthtml') : $_facrec->note_private;
450  $this->model_pdf = GETPOST('model', 'alpha') ? GETPOST('model', 'alpha') : $_facrec->model_pdf;
451  $this->cond_reglement_id = GETPOST('cond_reglement_id', 'int') > 0 ? ((int) GETPOST('cond_reglement_id', 'int')) : $_facrec->cond_reglement_id;
452  $this->mode_reglement_id = GETPOST('mode_reglement_id', 'int') > 0 ? ((int) GETPOST('mode_reglement_id', 'int')) : $_facrec->mode_reglement_id;
453  $this->fk_account = GETPOST('fk_account') > 0 ? ((int) GETPOST('fk_account')) : $_facrec->fk_account;
454 
455  // Set here to have this defined for substitution into notes, should be recalculated after adding lines to get same result
456  $this->total_ht = $_facrec->total_ht;
457  $this->total_ttc = $_facrec->total_ttc;
458 
459  // Fields always coming from template
460  $this->fk_incoterms = $_facrec->fk_incoterms;
461  $this->location_incoterms = $_facrec->location_incoterms;
462 
463  // Clean parameters
464  if (! $this->type) {
465  $this->type = self::TYPE_STANDARD;
466  }
467  if (! empty(GETPOST('ref_supplier'))) {
468  $this->ref_supplier = trim($this->ref_supplier);
469  } else {
470  $this->ref_supplier = trim($this->ref_supplier . '_' . ($_facrec->nb_gen_done + 1));
471  }
472  $this->note_public = trim($this->note_public);
473  $this->note_private = trim($this->note_private);
474  $this->note_private = dol_concatdesc($this->note_private, $langs->trans("GeneratedFromRecurringInvoice", $_facrec->titre));
475 
476  $this->array_options = $_facrec->array_options;
477 
478  if (! $this->mode_reglement_id) {
479  $this->mode_reglement_id = 0;
480  }
481  $this->brouillon = 1;
482  $this->status = self::STATUS_DRAFT;
483  $this->statut = self::STATUS_DRAFT;
484 
485  $this->linked_objects = $_facrec->linkedObjectsIds;
486  // We do not add link to template invoice or next invoice will be linked to all generated invoices
487  //$this->linked_objects['facturerec'][0] = $this->fac_rec;
488 
489  $forceduedate = $this->calculate_date_lim_reglement();
490 
491  // For recurring invoices, update date and number of last generation of recurring template invoice, before inserting new invoice
492  if ($_facrec->frequency > 0) {
493  dol_syslog("This is a recurring invoice so we set date_last_gen and next date_when");
494  if (empty($_facrec->date_when)) {
495  $_facrec->date_when = $now;
496  }
497  $next_date = $_facrec->getNextDate(); // Calculate next date
498  $result = $_facrec->setValueFrom('date_last_gen', $now, '', null, 'date', '', $user, '');
499  //$_facrec->setValueFrom('nb_gen_done', $_facrec->nb_gen_done + 1); // Not required, +1 already included into setNextDate when second param is 1.
500  $result = $_facrec->setNextDate($next_date, 1);
501  }
502 
503  // Define lang of customer
504  $outputlangs = $langs;
505  $newlang = '';
506 
507  if ($conf->global->MAIN_MULTILANGS && empty($newlang) && isset($this->thirdparty->default_lang)) {
508  $newlang = $this->thirdparty->default_lang; // for proposal, order, invoice, ...
509  }
510  if ($conf->global->MAIN_MULTILANGS && empty($newlang) && isset($this->default_lang)) {
511  $newlang = $this->default_lang; // for thirdparty
512  }
513  if (! empty($newlang)) {
514  $outputlangs = new Translate("", $conf);
515  $outputlangs->setDefaultLang($newlang);
516  }
517 
518  // Array of possible substitutions (See also file mailing-send.php that should manage same substitutions)
519  $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $this);
520  $substitutionarray['__INVOICE_PREVIOUS_MONTH__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'm'), '%m');
521  $substitutionarray['__INVOICE_MONTH__'] = dol_print_date($this->date, '%m');
522  $substitutionarray['__INVOICE_NEXT_MONTH__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'm'), '%m');
523  $substitutionarray['__INVOICE_PREVIOUS_MONTH_TEXT__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'm'), '%B');
524  $substitutionarray['__INVOICE_MONTH_TEXT__'] = dol_print_date($this->date, '%B');
525  $substitutionarray['__INVOICE_NEXT_MONTH_TEXT__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'm'), '%B');
526  $substitutionarray['__INVOICE_PREVIOUS_YEAR__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'y'), '%Y');
527  $substitutionarray['__INVOICE_YEAR__'] = dol_print_date($this->date, '%Y');
528  $substitutionarray['__INVOICE_NEXT_YEAR__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'y'), '%Y');
529  // Only for template invoice
530  $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_BEFORE_GEN__'] = dol_print_date($originaldatewhen, 'dayhour');
531  $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_AFTER_GEN__'] = dol_print_date($nextdatewhen, 'dayhour');
532  $substitutionarray['__INVOICE_PREVIOUS_DATE_NEXT_INVOICE_AFTER_GEN__'] = dol_print_date($previousdaynextdatewhen, 'dayhour');
533  $substitutionarray['__INVOICE_COUNTER_CURRENT__'] = $_facrec->nb_gen_done;
534  $substitutionarray['__INVOICE_COUNTER_MAX__'] = $_facrec->nb_gen_max;
535 
536  complete_substitutions_array($substitutionarray, $outputlangs);
537 
538  $this->note_public = make_substitutions($this->note_public, $substitutionarray);
539  $this->note_private = make_substitutions($this->note_private, $substitutionarray);
540  }
541 
542  // Define due date if not already defined
543  if (! empty($forceduedate)) {
544  $this->date_echeance = $forceduedate;
545  }
546 
547  $sql = "INSERT INTO ".MAIN_DB_PREFIX."facture_fourn (";
548  $sql .= "ref";
549  $sql .= ", ref_supplier";
550  $sql .= ", ref_ext";
551  $sql .= ", entity";
552  $sql .= ", type";
553  $sql .= ", libelle";
554  $sql .= ", fk_soc";
555  $sql .= ", datec";
556  $sql .= ", datef";
557  $sql .= ", fk_projet";
558  $sql .= ", fk_cond_reglement";
559  $sql .= ", fk_mode_reglement";
560  $sql .= ", fk_account";
561  $sql .= ", note_private";
562  $sql .= ", note_public";
563  $sql .= ", fk_user_author";
564  $sql .= ", date_lim_reglement";
565  $sql .= ", fk_incoterms, location_incoterms";
566  $sql .= ", fk_multicurrency";
567  $sql .= ", multicurrency_code";
568  $sql .= ", multicurrency_tx";
569  $sql .= ", fk_facture_source";
570  $sql .= ", fk_fac_rec_source";
571  $sql .= ")";
572  $sql .= " VALUES (";
573  $sql .= "'(PROV)'";
574  $sql .= ", '".$this->db->escape($this->ref_supplier)."'";
575  $sql .= ", '".$this->db->escape($this->ref_ext)."'";
576  $sql .= ", ".((int) $conf->entity);
577  $sql .= ", '".$this->db->escape($this->type)."'";
578  $sql .= ", '".$this->db->escape(isset($this->label) ? $this->label : (isset($this->libelle) ? $this->libelle : ''))."'";
579  $sql .= ", ".((int) $this->socid);
580  $sql .= ", '".$this->db->idate($now)."'";
581  $sql .= ", '".$this->db->idate($this->date)."'";
582  $sql .= ", ".($this->fk_project > 0 ? ((int) $this->fk_project) : "null");
583  $sql .= ", ".($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : "null");
584  $sql .= ", ".($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : "null");
585  $sql .= ", ".($this->fk_account > 0 ? ((int) $this->fk_account) : 'NULL');
586  $sql .= ", '".$this->db->escape($this->note_private)."'";
587  $sql .= ", '".$this->db->escape($this->note_public)."'";
588  $sql .= ", ".((int) $user->id).",";
589  $sql .= $this->date_echeance != '' ? "'".$this->db->idate($this->date_echeance)."'" : "null";
590  $sql .= ", ".(int) $this->fk_incoterms;
591  $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
592  $sql .= ", ".(int) $this->fk_multicurrency;
593  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
594  $sql .= ", ".(double) $this->multicurrency_tx;
595  $sql .= ", ".(isset($this->fk_facture_source) ? $this->fk_facture_source : "NULL");
596  $sql .= ", ".(isset($this->fk_fac_rec_source) ? $this->fk_fac_rec_source : "NULL");
597  $sql .= ")";
598 
599  dol_syslog(get_class($this)."::create", LOG_DEBUG);
600  $resql = $this->db->query($sql);
601  if ($resql) {
602  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn');
603 
604  // Update ref with new one
605  $this->ref = '(PROV'.$this->id.')';
606  $sql = 'UPDATE '.MAIN_DB_PREFIX."facture_fourn SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".((int) $this->id);
607 
608  dol_syslog(get_class($this)."::create", LOG_DEBUG);
609  $resql = $this->db->query($sql);
610  if (!$resql) {
611  $error++;
612  }
613 
614  if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) { // To use new linkedObjectsIds instead of old linked_objects
615  $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
616  }
617 
618  // Add object linked
619  if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) {
620  foreach ($this->linked_objects as $origin => $tmp_origin_id) {
621  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, ...))
622  foreach ($tmp_origin_id as $origin_id) {
623  $ret = $this->add_object_linked($origin, $origin_id);
624  if (!$ret) {
625  dol_print_error($this->db);
626  $error++;
627  }
628  }
629  } else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
630  {
631  $origin_id = $tmp_origin_id;
632  $ret = $this->add_object_linked($origin, $origin_id);
633  if (!$ret) {
634  dol_print_error($this->db);
635  $error++;
636  }
637  }
638  }
639  }
640 
641  if (!$error && empty($this->fac_rec) && count($this->lines) && is_object($this->lines[0])) { // If this->lines is array of InvoiceLines (preferred mode)
642  dol_syslog("There is ".count($this->lines)." lines that are invoice lines objects");
643  foreach ($this->lines as $i => $val) {
644  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn, special_code, fk_remise_except)';
645  $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').')';
646 
647  $resql_insert = $this->db->query($sql);
648  if ($resql_insert) {
649  $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det');
650 
651  $res = $this->updateline(
652  $idligne,
653  $this->lines[$i]->description,
654  $this->lines[$i]->pu_ht,
655  $this->lines[$i]->tva_tx.($this->lines[$i]->vat_src_code ? ' ('.$this->lines[$i]->vat_src_code.')' : ''),
656  $this->lines[$i]->localtax1_tx,
657  $this->lines[$i]->localtax2_tx,
658  $this->lines[$i]->qty,
659  $this->lines[$i]->fk_product,
660  'HT',
661  (!empty($this->lines[$i]->info_bits) ? $this->lines[$i]->info_bits : ''),
662  $this->lines[$i]->product_type,
663  $this->lines[$i]->remise_percent,
664  false,
665  $this->lines[$i]->date_start,
666  $this->lines[$i]->date_end,
667  $this->lines[$i]->array_options,
668  $this->lines[$i]->fk_unit,
669  $this->lines[$i]->multicurrency_subprice,
670  $this->lines[$i]->ref_supplier
671  );
672  } else {
673  $this->error = $this->db->lasterror();
674  $this->db->rollback();
675  return -5;
676  }
677  }
678  } elseif (!$error && empty($this->fac_rec)) { // If this->lines is an array of invoice line arrays
679  dol_syslog("There is ".count($this->lines)." lines that are array lines");
680  foreach ($this->lines as $i => $val) {
681  $line = $this->lines[$i];
682 
683  // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
684  //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
685  if (!is_object($line)) {
686  $line = (object) $line;
687  }
688 
689  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn, special_code, fk_remise_except)';
690  $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').')';
691 
692  $resql_insert = $this->db->query($sql);
693  if ($resql_insert) {
694  $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det');
695 
696  $this->updateline(
697  $idligne,
698  $line->description,
699  $line->pu_ht,
700  $line->tva_tx,
701  $line->localtax1_tx,
702  $line->localtax2_tx,
703  $line->qty,
704  $line->fk_product,
705  'HT',
706  (!empty($line->info_bits) ? $line->info_bits : ''),
707  $line->product_type,
708  $line->remise_percent,
709  0,
710  $line->date_start,
711  $line->date_end,
712  $line->array_options,
713  $line->fk_unit,
714  $line->multicurrency_subprice,
715  $line->ref_supplier
716  );
717  } else {
718  $this->error = $this->db->lasterror();
719  $this->db->rollback();
720  return -5;
721  }
722  }
723  }
724 
725  /*
726  * Insert lines of template invoices
727  */
728  if (! $error && $this->fac_rec > 0) {
729  foreach ($_facrec->lines as $i => $val) {
730  if ($_facrec->lines[$i]->fk_product) {
731  $prod = new Product($this->db);
732  $res = $prod->fetch($_facrec->lines[$i]->fk_product);
733  }
734 
735  // For line from template invoice, we use data from template invoice
736  /*
737  $tva_tx = get_default_tva($mysoc,$soc,$prod->id);
738  $tva_npr = get_default_npr($mysoc,$soc,$prod->id);
739  if (empty($tva_tx)) $tva_npr=0;
740  $localtax1_tx=get_localtax($tva_tx,1,$soc,$mysoc,$tva_npr);
741  $localtax2_tx=get_localtax($tva_tx,2,$soc,$mysoc,$tva_npr);
742  */
743  $tva_tx = $_facrec->lines[$i]->tva_tx . ($_facrec->lines[$i]->vat_src_code ? '(' . $_facrec->lines[$i]->vat_src_code . ')' : '');
744  $tva_npr = $_facrec->lines[$i]->info_bits;
745  if (empty($tva_tx)) {
746  $tva_npr = 0;
747  }
748  $localtax1_tx = $_facrec->lines[$i]->localtax1_tx;
749  $localtax2_tx = $_facrec->lines[$i]->localtax2_tx;
750 
751  $fk_product_fournisseur_price = empty($_facrec->lines[$i]->fk_product_fournisseur_price) ? null : $_facrec->lines[$i]->fk_product_fournisseur_price;
752  $buyprice = empty($_facrec->lines[$i]->buyprice) ? 0 : $_facrec->lines[$i]->buyprice;
753 
754  // If buyprice not defined from template invoice, we try to guess the best value
755  if (! $buyprice && $_facrec->lines[$i]->fk_product > 0) {
756  require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php';
757  $producttmp = new ProductFournisseur($this->db);
758  $producttmp->fetch($_facrec->lines[$i]->fk_product);
759 
760  // If margin module defined on costprice, we try the costprice
761  // If not defined or if module margin defined and pmp and stock module enabled, we try pmp price
762  // else we get the best supplier price
763  if ($conf->global->MARGIN_TYPE == 'costprice' && ! empty($producttmp->cost_price)) {
764  $buyprice = $producttmp->cost_price;
765  } elseif (! empty($conf->stock->enabled) && ($conf->global->MARGIN_TYPE == 'costprice' || $conf->global->MARGIN_TYPE == 'pmp') && ! empty($producttmp->pmp)) {
766  $buyprice = $producttmp->pmp;
767  } else {
768  if ($producttmp->find_min_price_product_fournisseur($_facrec->lines[$i]->fk_product) > 0) {
769  if ($producttmp->product_fourn_price_id > 0) {
770  $buyprice = price2num($producttmp->fourn_unitprice * (1 - $producttmp->fourn_remise_percent / 100) + $producttmp->fourn_remise, 'MU');
771  }
772  }
773  }
774  }
775 
776  $result_insert = $this->addline(
777  $_facrec->lines[$i]->description,
778  $_facrec->lines[$i]->pu_ht,
779  $tva_tx,
780  $localtax1_tx,
781  $localtax2_tx,
782  $_facrec->lines[$i]->qty,
783  $_facrec->lines[$i]->fk_product,
784  $_facrec->lines[$i]->remise_percent,
785  ($_facrec->lines[$i]->date_start == 1 && $this->date) ? $this->date : '',
786  ($_facrec->lines[$i]->date_end == 1 && $previousdaynextdatewhen) ? $previousdaynextdatewhen : '',
787  0,
788  $_facrec->lines[$i]->info_bits,
789  'HT',
790  0,
791  $_facrec->lines[$i]->rang,
792  false,
793  $_facrec->lines[$i]->array_options,
794  $_facrec->lines[$i]->fk_unit,
795  0,
796  0,
797  $_facrec->lines[$i]->ref_supplier,
798  $_facrec->lines[$i]->special_code,
799  0,
800  0
801  );
802  if ($result_insert < 0) {
803  $error++;
804  $this->error = $this->db->error();
805  break;
806  }
807  }
808  }
809 
810 
811  // Update total price
812  $result = $this->update_price();
813  if ($result > 0) {
814  // Actions on extra fields
815  if (!$error) {
816  $result = $this->insertExtraFields(); // This also set $this->error or $this->errors if errors are found
817  if ($result < 0) {
818  $error++;
819  }
820  }
821 
822  if (!$error) {
823  // Call trigger
824  $result = $this->call_trigger('BILL_SUPPLIER_CREATE', $user);
825  if ($result < 0) {
826  $error++;
827  }
828  // End call triggers
829  }
830 
831  if (!$error) {
832  $this->db->commit();
833  return $this->id;
834  } else {
835  $this->db->rollback();
836  return -4;
837  }
838  } else {
839  $this->error = $langs->trans('FailedToUpdatePrice');
840  $this->db->rollback();
841  return -3;
842  }
843  } else {
844  if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
845  $this->error = $langs->trans('ErrorRefAlreadyExists');
846  $this->db->rollback();
847  return -1;
848  } else {
849  $this->error = $this->db->lasterror();
850  $this->db->rollback();
851  return -2;
852  }
853  }
854  }
855 
863  public function fetch($id = '', $ref = '')
864  {
865  global $langs;
866 
867  $sql = "SELECT";
868  $sql .= " t.rowid,";
869  $sql .= " t.ref,";
870  $sql .= " t.ref_supplier,";
871  $sql .= " t.ref_ext,";
872  $sql .= " t.entity,";
873  $sql .= " t.type,";
874  $sql .= " t.fk_soc,";
875  $sql .= " t.datec,";
876  $sql .= " t.datef,";
877  $sql .= " t.tms,";
878  $sql .= " t.libelle as label,";
879  $sql .= " t.paye,";
880  $sql .= " t.close_code,";
881  $sql .= " t.close_note,";
882  $sql .= " t.tva,";
883  $sql .= " t.localtax1,";
884  $sql .= " t.localtax2,";
885  $sql .= " t.total_ht,";
886  $sql .= " t.total_tva,";
887  $sql .= " t.total_ttc,";
888  $sql .= " t.fk_statut as status,";
889  $sql .= " t.fk_user_author,";
890  $sql .= " t.fk_user_valid,";
891  $sql .= " t.fk_facture_source,";
892  $sql .= " t.fk_fac_rec_source,";
893  $sql .= " t.fk_projet as fk_project,";
894  $sql .= " t.fk_cond_reglement,";
895  $sql .= " t.fk_account,";
896  $sql .= " t.fk_mode_reglement,";
897  $sql .= " t.date_lim_reglement,";
898  $sql .= " t.note_private,";
899  $sql .= " t.note_public,";
900  $sql .= " t.model_pdf,";
901  $sql .= " t.import_key,";
902  $sql .= " t.extraparams,";
903  $sql .= " cr.code as cond_reglement_code, cr.libelle as cond_reglement_label, cr.libelle_facture as cond_reglement_doc,";
904  $sql .= " p.code as mode_reglement_code, p.libelle as mode_reglement_label,";
905  $sql .= ' s.nom as socnom, s.rowid as socid,';
906  $sql .= ' t.fk_incoterms, t.location_incoterms,';
907  $sql .= " i.libelle as label_incoterms,";
908  $sql .= ' t.fk_transport_mode,';
909  $sql .= ' t.fk_multicurrency, t.multicurrency_code, t.multicurrency_tx, t.multicurrency_total_ht, t.multicurrency_total_tva, t.multicurrency_total_ttc';
910  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as t';
911  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON (t.fk_soc = s.rowid)";
912  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_payment_term as cr ON t.fk_cond_reglement = cr.rowid";
913  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as p ON t.fk_mode_reglement = p.id";
914  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON t.fk_incoterms = i.rowid';
915  if ($id) {
916  $sql .= " WHERE t.rowid=".((int) $id);
917  }
918  if ($ref) {
919  $sql .= " WHERE t.ref='".$this->db->escape($ref)."' AND t.entity IN (".getEntity('supplier_invoice').")";
920  }
921 
922  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
923  $resql = $this->db->query($sql);
924  if ($resql) {
925  if ($this->db->num_rows($resql)) {
926  $obj = $this->db->fetch_object($resql);
927 
928  $this->id = $obj->rowid;
929  $this->ref = $obj->ref ? $obj->ref : $obj->rowid; // We take rowid if ref is empty for backward compatibility
930 
931  $this->ref_supplier = $obj->ref_supplier;
932  $this->ref_ext = $obj->ref_ext;
933  $this->entity = $obj->entity;
934  $this->type = empty($obj->type) ? self::TYPE_STANDARD : $obj->type;
935  $this->fk_soc = $obj->fk_soc;
936  $this->datec = $this->db->jdate($obj->datec);
937  $this->date = $this->db->jdate($obj->datef);
938  $this->datep = $this->db->jdate($obj->datef);
939  $this->tms = $this->db->jdate($obj->tms);
940  $this->libelle = $obj->label; // deprecated
941  $this->label = $obj->label;
942  $this->paye = $obj->paye;
943  $this->paid = $obj->paye;
944  $this->close_code = $obj->close_code;
945  $this->close_note = $obj->close_note;
946  $this->total_localtax1 = $obj->localtax1;
947  $this->total_localtax2 = $obj->localtax2;
948  $this->total_ht = $obj->total_ht;
949  $this->total_tva = $obj->total_tva;
950  $this->total_ttc = $obj->total_ttc;
951  $this->status = $obj->status;
952  $this->statut = $obj->status; // For backward compatibility
953  $this->fk_statut = $obj->status; // For backward compatibility
954  $this->fk_user_author = $obj->fk_user_author;
955  $this->author = $obj->fk_user_author;
956  $this->fk_user_valid = $obj->fk_user_valid;
957  $this->fk_facture_source = $obj->fk_facture_source;
958  $this->fk_fac_rec_source = $obj->fk_fac_rec_source;
959  $this->fk_project = $obj->fk_project;
960  $this->cond_reglement_id = $obj->fk_cond_reglement;
961  $this->cond_reglement_code = $obj->cond_reglement_code;
962  $this->cond_reglement = $obj->cond_reglement_label; // deprecated
963  $this->cond_reglement_label = $obj->cond_reglement_label;
964  $this->cond_reglement_doc = $obj->cond_reglement_doc;
965  $this->fk_account = $obj->fk_account;
966  $this->mode_reglement_id = $obj->fk_mode_reglement;
967  $this->mode_reglement_code = $obj->mode_reglement_code;
968  $this->mode_reglement = $obj->mode_reglement_label;
969  $this->date_echeance = $this->db->jdate($obj->date_lim_reglement);
970  $this->note = $obj->note_private; // deprecated
971  $this->note_private = $obj->note_private;
972  $this->note_public = $obj->note_public;
973  $this->model_pdf = $obj->model_pdf;
974  $this->modelpdf = $obj->model_pdf; // deprecated
975  $this->import_key = $obj->import_key;
976 
977  //Incoterms
978  $this->fk_incoterms = $obj->fk_incoterms;
979  $this->location_incoterms = $obj->location_incoterms;
980  $this->label_incoterms = $obj->label_incoterms;
981  $this->transport_mode_id = $obj->fk_transport_mode;
982 
983  // Multicurrency
984  $this->fk_multicurrency = $obj->fk_multicurrency;
985  $this->multicurrency_code = $obj->multicurrency_code;
986  $this->multicurrency_tx = $obj->multicurrency_tx;
987  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
988  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
989  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
990 
991  $this->extraparams = (array) json_decode($obj->extraparams, true);
992 
993  $this->socid = $obj->socid;
994  $this->socnom = $obj->socnom;
995 
996  // Retrieve all extrafield
997  // fetch optionals attributes and labels
998  $this->fetch_optionals();
999 
1000  if ($this->statut == self::STATUS_DRAFT) {
1001  $this->brouillon = 1;
1002  }
1003 
1004  $result = $this->fetch_lines();
1005  if ($result < 0) {
1006  $this->error = $this->db->lasterror();
1007  return -3;
1008  }
1009  } else {
1010  $this->error = 'Bill with id '.$id.' not found';
1011  dol_syslog(get_class($this).'::fetch '.$this->error);
1012  return 0;
1013  }
1014 
1015  $this->db->free($resql);
1016  return 1;
1017  } else {
1018  $this->error = "Error ".$this->db->lasterror();
1019  return -1;
1020  }
1021  }
1022 
1023 
1024  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1030  public function fetch_lines()
1031  {
1032  // phpcs:enable
1033  $this->lines = array();
1034 
1035  $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';
1036  $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';
1037  $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';
1038  $sql .= ', p.rowid as product_id, p.ref as product_ref, p.label as label, p.description as product_desc';
1039  $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';
1040  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
1041  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
1042  $sql .= ' WHERE fk_facture_fourn='.((int) $this->id);
1043  $sql .= ' ORDER BY f.rang, f.rowid';
1044 
1045  dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
1046 
1047  $resql_rows = $this->db->query($sql);
1048  if ($resql_rows) {
1049  $num_rows = $this->db->num_rows($resql_rows);
1050  if ($num_rows) {
1051  $i = 0;
1052  while ($i < $num_rows) {
1053  $obj = $this->db->fetch_object($resql_rows);
1054 
1055  $line = new SupplierInvoiceLine($this->db);
1056 
1057  $line->id = $obj->rowid;
1058  $line->rowid = $obj->rowid;
1059  $line->description = $obj->description;
1060  $line->date_start = $obj->date_start;
1061  $line->date_end = $obj->date_end;
1062 
1063  $line->product_ref = $obj->product_ref;
1064  $line->ref = $obj->product_ref;
1065  $line->ref_supplier = $obj->ref_supplier;
1066  $line->libelle = $obj->label;
1067  $line->label = $obj->label;
1068  $line->product_desc = $obj->product_desc;
1069  $line->subprice = $obj->pu_ht;
1070  $line->pu_ht = $obj->pu_ht;
1071  $line->pu_ttc = $obj->pu_ttc;
1072 
1073  $line->vat_src_code = $obj->vat_src_code;
1074  $line->tva_tx = $obj->tva_tx;
1075  $line->localtax1_tx = $obj->localtax1_tx;
1076  $line->localtax2_tx = $obj->localtax2_tx;
1077  $line->localtax1_type = $obj->localtax1_type;
1078  $line->localtax2_type = $obj->localtax2_type;
1079  $line->qty = $obj->qty;
1080  $line->remise_percent = $obj->remise_percent;
1081  $line->fk_remise_except = $obj->fk_remise_except;
1082  //$line->tva = $obj->total_tva; // deprecated
1083  $line->total_ht = $obj->total_ht;
1084  $line->total_ttc = $obj->total_ttc;
1085  $line->total_tva = $obj->total_tva;
1086  $line->total_localtax1 = $obj->total_localtax1;
1087  $line->total_localtax2 = $obj->total_localtax2;
1088  $line->fk_facture_fourn = $obj->fk_facture_fourn;
1089  $line->fk_product = $obj->fk_product;
1090  $line->product_type = $obj->product_type;
1091  $line->product_label = $obj->label;
1092  $line->info_bits = $obj->info_bits;
1093  $line->fk_parent_line = $obj->fk_parent_line;
1094  $line->special_code = $obj->special_code;
1095  $line->rang = $obj->rang;
1096  $line->fk_unit = $obj->fk_unit;
1097 
1098  // Accountancy
1099  $line->code_ventilation = $obj->fk_code_ventilation;
1100  $line->fk_accounting_account = $obj->fk_code_ventilation;
1101 
1102  // Multicurrency
1103  $line->fk_multicurrency = $obj->fk_multicurrency;
1104  $line->multicurrency_code = $obj->multicurrency_code;
1105  $line->multicurrency_subprice = $obj->multicurrency_subprice;
1106  $line->multicurrency_total_ht = $obj->multicurrency_total_ht;
1107  $line->multicurrency_total_tva = $obj->multicurrency_total_tva;
1108  $line->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
1109 
1110  // Extra fields
1111  $line->fetch_optionals();
1112 
1113  $this->lines[$i] = $line;
1114 
1115  $i++;
1116  }
1117  }
1118  $this->db->free($resql_rows);
1119  return 1;
1120  } else {
1121  $this->error = $this->db->error();
1122  dol_syslog(get_class($this)."::fetch_lines - No lines:{$this->error} Error:{$this->error}", LOG_DEBUG);
1123  return -3;
1124  }
1125  }
1126 
1127 
1135  public function update($user = null, $notrigger = 0)
1136  {
1137  global $conf, $langs;
1138  $error = 0;
1139 
1140  // Clean parameters
1141  if (empty($this->type)) {
1142  $this->type = self::TYPE_STANDARD;
1143  }
1144  if (isset($this->ref)) {
1145  $this->ref = trim($this->ref);
1146  }
1147  if (isset($this->ref_supplier)) {
1148  $this->ref_supplier = trim($this->ref_supplier);
1149  }
1150  if (isset($this->ref_ext)) {
1151  $this->ref_ext = trim($this->ref_ext);
1152  }
1153  if (isset($this->entity)) {
1154  $this->entity = trim($this->entity);
1155  }
1156  if (isset($this->type)) {
1157  $this->type = trim($this->type);
1158  }
1159  if (isset($this->fk_soc)) {
1160  $this->fk_soc = trim($this->fk_soc);
1161  }
1162  if (isset($this->label)) {
1163  $this->label = trim($this->label);
1164  }
1165  if (isset($this->libelle)) {
1166  $this->libelle = trim($this->libelle); // deprecated
1167  }
1168  if (isset($this->paye)) {
1169  $this->paye = trim($this->paye);
1170  }
1171  if (isset($this->close_code)) {
1172  $this->close_code = trim($this->close_code);
1173  }
1174  if (isset($this->close_note)) {
1175  $this->close_note = trim($this->close_note);
1176  }
1177  if (isset($this->localtax1)) {
1178  $this->localtax1 = trim($this->localtax1);
1179  }
1180  if (isset($this->localtax2)) {
1181  $this->localtax2 = trim($this->localtax2);
1182  }
1183  if (empty($this->total_ht)) {
1184  $this->total_ht = 0;
1185  }
1186  if (empty($this->total_tva)) {
1187  $this->total_tva = 0;
1188  }
1189  // if (isset($this->total_localtax1)) $this->total_localtax1=trim($this->total_localtax1);
1190  // if (isset($this->total_localtax2)) $this->total_localtax2=trim($this->total_localtax2);
1191  if (isset($this->total_ttc)) {
1192  $this->total_ttc = trim($this->total_ttc);
1193  }
1194  if (isset($this->statut)) {
1195  $this->statut = (int) $this->statut;
1196  }
1197  if (isset($this->status)) {
1198  $this->status = (int) $this->status;
1199  }
1200  if (isset($this->author)) {
1201  $this->author = trim($this->author);
1202  }
1203  if (isset($this->fk_user_valid)) {
1204  $this->fk_user_valid = trim($this->fk_user_valid);
1205  }
1206  if (isset($this->fk_facture_source)) {
1207  $this->fk_facture_source = trim($this->fk_facture_source);
1208  }
1209  if (isset($this->fk_project)) {
1210  if (empty($this->fk_project)) $this->fk_project = null;
1211  else $this->fk_project = intval($this->fk_project);
1212  }
1213  if (isset($this->cond_reglement_id)) {
1214  $this->cond_reglement_id = trim($this->cond_reglement_id);
1215  }
1216  if (isset($this->note_private)) {
1217  $this->note = trim($this->note_private);
1218  }
1219  if (isset($this->note_public)) {
1220  $this->note_public = trim($this->note_public);
1221  }
1222  if (isset($this->model_pdf)) {
1223  $this->model_pdf = trim($this->model_pdf);
1224  }
1225  if (isset($this->import_key)) {
1226  $this->import_key = trim($this->import_key);
1227  }
1228 
1229 
1230  // Check parameters
1231  // Put here code to add control on parameters values
1232 
1233  // Update request
1234  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn SET";
1235  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
1236  $sql .= " ref_supplier=".(isset($this->ref_supplier) ? "'".$this->db->escape($this->ref_supplier)."'" : "null").",";
1237  $sql .= " ref_ext=".(isset($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : "null").",";
1238  $sql .= " entity=".(isset($this->entity) ? $this->entity : "null").",";
1239  $sql .= " type=".(isset($this->type) ? $this->type : "null").",";
1240  $sql .= " fk_soc=".(isset($this->fk_soc) ? $this->fk_soc : "null").",";
1241  $sql .= " datec=".(dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
1242  $sql .= " datef=".(dol_strlen($this->date) != 0 ? "'".$this->db->idate($this->date)."'" : 'null').",";
1243  if (dol_strlen($this->tms) != 0) {
1244  $sql .= " tms=".(dol_strlen($this->tms) != 0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
1245  }
1246  $sql .= " libelle=".(isset($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
1247  $sql .= " paye=".(isset($this->paye) ? $this->paye : "null").",";
1248  $sql .= " close_code=".(isset($this->close_code) ? "'".$this->db->escape($this->close_code)."'" : "null").",";
1249  $sql .= " close_note=".(isset($this->close_note) ? "'".$this->db->escape($this->close_note)."'" : "null").",";
1250  //$sql .= " tva=".(isset($this->tva) ? $this->tva : "null").",";
1251  $sql .= " localtax1=".(isset($this->localtax1) ? $this->localtax1 : "null").",";
1252  $sql .= " localtax2=".(isset($this->localtax2) ? $this->localtax2 : "null").",";
1253  $sql .= " total_ht=".(isset($this->total_ht) ? $this->total_ht : "null").",";
1254  $sql .= " total_tva=".(isset($this->total_tva) ? $this->total_tva : "null").",";
1255  $sql .= " total_ttc=".(isset($this->total_ttc) ? $this->total_ttc : "null").",";
1256  $sql .= " fk_statut=".(isset($this->status) ? $this->status : (isset($this->statut) ? $this->statut : "null")).",";
1257  $sql .= " fk_user_author=".(isset($this->author) ? $this->author : "null").",";
1258  $sql .= " fk_user_valid=".(isset($this->fk_user_valid) ? $this->fk_user_valid : "null").",";
1259  $sql .= " fk_facture_source=".(isset($this->fk_facture_source) ? $this->fk_facture_source : "null").",";
1260  $sql .= " fk_projet=".(isset($this->fk_project) ? $this->fk_project : "null").",";
1261  $sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? $this->cond_reglement_id : "null").",";
1262  $sql .= " date_lim_reglement=".(dol_strlen($this->date_echeance) != 0 ? "'".$this->db->idate($this->date_echeance)."'" : 'null').",";
1263  $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
1264  $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
1265  $sql .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
1266  $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null")."";
1267  $sql .= " WHERE rowid=".((int) $this->id);
1268 
1269  $this->db->begin();
1270 
1271  dol_syslog(get_class($this)."::update", LOG_DEBUG);
1272  $resql = $this->db->query($sql);
1273 
1274  if (!$resql) {
1275  $error++;
1276 
1277  if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1278  $this->errors[] = $langs->trans('ErrorRefAlreadyExists');
1279  } else {
1280  $this->errors[] = "Error ".$this->db->lasterror();
1281  }
1282  }
1283 
1284  if (!$error) {
1285  $result = $this->insertExtraFields();
1286  if ($result < 0) {
1287  $error++;
1288  }
1289  }
1290 
1291  if (!$error) {
1292  if (!$notrigger) {
1293  // Call trigger
1294  $result = $this->call_trigger('BILL_SUPPLIER_MODIFY', $user);
1295  if ($result < 0) {
1296  $error++;
1297  }
1298  // End call triggers
1299  }
1300  }
1301 
1302  // Commit or rollback
1303  if ($error) {
1304  foreach ($this->errors as $errmsg) {
1305  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
1306  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1307  }
1308  $this->db->rollback();
1309  return -1 * $error;
1310  } else {
1311  $this->db->commit();
1312  return 1;
1313  }
1314  }
1315 
1316  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1323  public function insert_discount($idremise)
1324  {
1325  // phpcs:enable
1326  global $conf, $langs;
1327 
1328  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1329  include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
1330 
1331  $this->db->begin();
1332 
1333  $remise = new DiscountAbsolute($this->db);
1334  $result = $remise->fetch($idremise);
1335 
1336  if ($result > 0) {
1337  if ($remise->fk_invoice_supplier) { // Protection against multiple submission
1338  $this->error = $langs->trans("ErrorDiscountAlreadyUsed");
1339  $this->db->rollback();
1340  return -5;
1341  }
1342 
1343  $facligne = new SupplierInvoiceLine($this->db);
1344  $facligne->fk_facture_fourn = $this->id;
1345  $facligne->fk_remise_except = $remise->id;
1346  $facligne->desc = $remise->description; // Description ligne
1347  $facligne->vat_src_code = $remise->vat_src_code;
1348  $facligne->tva_tx = $remise->tva_tx;
1349  $facligne->subprice = -$remise->amount_ht;
1350  $facligne->fk_product = 0; // Id produit predefini
1351  $facligne->product_type = 0;
1352  $facligne->qty = 1;
1353  $facligne->remise_percent = 0;
1354  $facligne->rang = -1;
1355  $facligne->info_bits = 2;
1356 
1357  if (!empty($conf->global->MAIN_ADD_LINE_AT_POSITION)) {
1358  $facligne->rang = 1;
1359  $linecount = count($this->lines);
1360  for ($ii = 1; $ii <= $linecount; $ii++) {
1361  $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii+1);
1362  }
1363  }
1364 
1365  // Get buy/cost price of invoice that is source of discount
1366  if ($remise->fk_invoice_supplier_source > 0) {
1367  $srcinvoice = new FactureFournisseur($this->db);
1368  $srcinvoice->fetch($remise->fk_invoice_supplier_source);
1369  $totalcostpriceofinvoice = 0;
1370  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php'; // TODO Move this into commonobject
1371  $formmargin = new FormMargin($this->db);
1372  $arraytmp = $formmargin->getMarginInfosArray($srcinvoice, false);
1373  $facligne->pa_ht = $arraytmp['pa_total'];
1374  }
1375 
1376  $facligne->total_ht = -$remise->amount_ht;
1377  $facligne->total_tva = -$remise->amount_tva;
1378  $facligne->total_ttc = -$remise->amount_ttc;
1379 
1380  $facligne->multicurrency_subprice = -$remise->multicurrency_subprice;
1381  $facligne->multicurrency_total_ht = -$remise->multicurrency_total_ht;
1382  $facligne->multicurrency_total_tva = -$remise->multicurrency_total_tva;
1383  $facligne->multicurrency_total_ttc = -$remise->multicurrency_total_ttc;
1384 
1385  $lineid = $facligne->insert();
1386  if ($lineid > 0) {
1387  $result = $this->update_price(1);
1388  if ($result > 0) {
1389  // Create link between discount and invoice line
1390  $result = $remise->link_to_invoice($lineid, 0, 'supplier');
1391  if ($result < 0) {
1392  $this->error = $remise->error;
1393  $this->db->rollback();
1394  return -4;
1395  }
1396 
1397  $this->db->commit();
1398  return 1;
1399  } else {
1400  $this->error = $facligne->error;
1401  $this->db->rollback();
1402  return -1;
1403  }
1404  } else {
1405  $this->error = $facligne->error;
1406  $this->db->rollback();
1407  return -2;
1408  }
1409  } else {
1410  $this->db->rollback();
1411  return -3;
1412  }
1413  }
1414 
1415 
1423  public function delete(User $user, $notrigger = 0)
1424  {
1425  global $langs, $conf;
1426 
1427  $rowid = $this->id;
1428 
1429  dol_syslog("FactureFournisseur::delete rowid=".$rowid, LOG_DEBUG);
1430 
1431  // TODO Test if there is at least on payment. If yes, refuse to delete.
1432 
1433  $error = 0;
1434  $this->db->begin();
1435 
1436  if (!$error && !$notrigger) {
1437  // Call trigger
1438  $result = $this->call_trigger('BILL_SUPPLIER_DELETE', $user);
1439  if ($result < 0) {
1440  $this->db->rollback();
1441  return -1;
1442  }
1443  // Fin appel triggers
1444  }
1445 
1446  if (!$error) {
1447  // If invoice was converted into a discount not yet consumed, we remove discount
1448  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'societe_remise_except';
1449  $sql .= ' WHERE fk_invoice_supplier_source = '.((int) $rowid);
1450  $sql .= ' AND fk_invoice_supplier_line IS NULL';
1451  $resql = $this->db->query($sql);
1452 
1453  // If invoice has consumned discounts
1454  $this->fetch_lines();
1455  $list_rowid_det = array();
1456  foreach ($this->lines as $key => $invoiceline) {
1457  $list_rowid_det[] = $invoiceline->rowid;
1458  }
1459 
1460  // Consumned discounts are freed
1461  if (count($list_rowid_det)) {
1462  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
1463  $sql .= ' SET fk_invoice_supplier = NULL, fk_invoice_supplier_line = NULL';
1464  $sql .= ' WHERE fk_invoice_supplier_line IN ('.$this->db->sanitize(join(',', $list_rowid_det)).')';
1465 
1466  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1467  if (!$this->db->query($sql)) {
1468  $error++;
1469  }
1470  }
1471  }
1472 
1473  if (!$error) {
1474  $main = MAIN_DB_PREFIX.'facture_fourn_det';
1475  $ef = $main."_extrafields";
1476  $sqlef = "DELETE FROM $ef WHERE fk_object IN (SELECT rowid FROM ".$main." WHERE fk_facture_fourn = ".((int) $rowid).")";
1477  $resqlef = $this->db->query($sqlef);
1478  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det WHERE fk_facture_fourn = '.((int) $rowid);
1479  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1480  $resql = $this->db->query($sql);
1481  if ($resqlef && $resql) {
1482  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn WHERE rowid = '.((int) $rowid);
1483  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1484  $resql2 = $this->db->query($sql);
1485  if (!$resql2) {
1486  $error++;
1487  }
1488  } else {
1489  $error++;
1490  }
1491  }
1492 
1493  if (!$error) {
1494  // Delete linked object
1495  $res = $this->deleteObjectLinked();
1496  if ($res < 0) {
1497  $error++;
1498  }
1499  }
1500 
1501  if (!$error) {
1502  // Delete linked object
1503  $res = $this->deleteObjectLinked();
1504  if ($res < 0) {
1505  $error++;
1506  }
1507  }
1508 
1509  if (!$error) {
1510  // Delete record into ECM index (Note that delete is also done when deleting files with the dol_delete_dir_recursive
1511  $this->deleteEcmFiles();
1512 
1513  // We remove directory
1514  if ($conf->fournisseur->facture->dir_output) {
1515  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1516 
1517  $ref = dol_sanitizeFileName($this->ref);
1518  $dir = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$ref;
1519  $file = $dir."/".$ref.".pdf";
1520  if (file_exists($file)) {
1521  if (!dol_delete_file($file, 0, 0, 0, $this)) { // For triggers
1522  $this->error = 'ErrorFailToDeleteFile';
1523  $error++;
1524  }
1525  }
1526  if (file_exists($dir)) {
1527  $res = @dol_delete_dir_recursive($dir);
1528 
1529  if (!$res) {
1530  $this->error = 'ErrorFailToDeleteDir';
1531  $error++;
1532  }
1533  }
1534  }
1535  }
1536 
1537  // Remove extrafields
1538  if (!$error) {
1539  $result = $this->deleteExtraFields();
1540  if ($result < 0) {
1541  $error++;
1542  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1543  }
1544  }
1545 
1546  if (!$error) {
1547  dol_syslog(get_class($this)."::delete $this->id by $user->id", LOG_DEBUG);
1548  $this->db->commit();
1549  return 1;
1550  } else {
1551  $this->error = $this->db->lasterror();
1552  $this->db->rollback();
1553  return -$error;
1554  }
1555  }
1556 
1557 
1558  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1569  public function set_paid($user, $close_code = '', $close_note = '')
1570  {
1571  // phpcs:enable
1572  dol_syslog(get_class($this)."::set_paid is deprecated, use setPaid instead", LOG_NOTICE);
1573  return $this->setPaid($user, $close_code, $close_note);
1574  }
1575 
1584  public function setPaid($user, $close_code = '', $close_note = '')
1585  {
1586  $error = 0;
1587 
1588  if ($this->paye != 1) {
1589  $this->db->begin();
1590 
1591  $now = dol_now();
1592 
1593  dol_syslog("FactureFournisseur::set_paid", LOG_DEBUG);
1594 
1595  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn SET';
1596  $sql .= ' fk_statut = '.self::STATUS_CLOSED;
1597  if (!$close_code) {
1598  $sql .= ', paye=1';
1599  }
1600  if ($close_code) {
1601  $sql .= ", close_code='".$this->db->escape($close_code)."'";
1602  }
1603  if ($close_note) {
1604  $sql .= ", close_note='".$this->db->escape($close_note)."'";
1605  }
1606  $sql .= ', fk_user_closing = '.((int) $user->id);
1607  $sql .= ", date_closing = '".$this->db->idate($now)."'";
1608  $sql .= ' WHERE rowid = '.((int) $this->id);
1609 
1610  $resql = $this->db->query($sql);
1611  if ($resql) {
1612  // Call trigger
1613  $result = $this->call_trigger('BILL_SUPPLIER_PAYED', $user);
1614  if ($result < 0) {
1615  $error++;
1616  }
1617  // End call triggers
1618  } else {
1619  $error++;
1620  $this->error = $this->db->error();
1621  dol_print_error($this->db);
1622  }
1623 
1624  if (!$error) {
1625  $this->db->commit();
1626  return 1;
1627  } else {
1628  $this->db->rollback();
1629  return -1;
1630  }
1631  } else {
1632  return 0;
1633  }
1634  }
1635 
1636  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1647  public function set_unpaid($user)
1648  {
1649  // phpcs:enable
1650  dol_syslog(get_class($this)."::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE);
1651  return $this->setUnpaid($user);
1652  }
1653 
1662  public function setUnpaid($user)
1663  {
1664  $error = 0;
1665 
1666  $this->db->begin();
1667 
1668  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn';
1669  $sql .= ' SET paye=0, fk_statut='.self::STATUS_VALIDATED.', close_code=null, close_note=null,';
1670  $sql .= ' date_closing=null,';
1671  $sql .= ' fk_user_closing=null';
1672  $sql .= ' WHERE rowid = '.((int) $this->id);
1673 
1674  dol_syslog(get_class($this)."::set_unpaid", LOG_DEBUG);
1675  $resql = $this->db->query($sql);
1676  if ($resql) {
1677  // Call trigger
1678  $result = $this->call_trigger('BILL_SUPPLIER_UNPAYED', $user);
1679  if ($result < 0) {
1680  $error++;
1681  }
1682  // End call triggers
1683  } else {
1684  $error++;
1685  $this->error = $this->db->error();
1686  dol_print_error($this->db);
1687  }
1688 
1689  if (!$error) {
1690  $this->db->commit();
1691  return 1;
1692  } else {
1693  $this->db->rollback();
1694  return -1;
1695  }
1696  }
1697 
1708  public function setCanceled($user, $close_code = '', $close_note = '')
1709  {
1710  dol_syslog(get_class($this)."::setCanceled rowid=".((int) $this->id), LOG_DEBUG);
1711 
1712  $this->db->begin();
1713 
1714  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn SET';
1715  $sql .= ' fk_statut='.self::STATUS_ABANDONED;
1716  if ($close_code) {
1717  $sql .= ", close_code='".$this->db->escape($close_code)."'";
1718  }
1719  if ($close_note) {
1720  $sql .= ", close_note='".$this->db->escape($close_note)."'";
1721  }
1722  $sql .= " WHERE rowid = ".((int) $this->id);
1723 
1724  $resql = $this->db->query($sql);
1725  if ($resql) {
1726  // Bound discounts are deducted from the invoice
1727  // as they have not been used since the invoice is abandoned.
1728  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
1729  $sql .= ' SET fk_invoice_supplier = NULL';
1730  $sql .= ' WHERE fk_invoice_supplier = '.((int) $this->id);
1731 
1732  $resql = $this->db->query($sql);
1733  if ($resql) {
1734  // Call trigger
1735  $result = $this->call_trigger('BILL_SUPPLIER_CANCEL', $user);
1736  if ($result < 0) {
1737  $this->db->rollback();
1738  return -1;
1739  }
1740  // End call triggers
1741 
1742  $this->db->commit();
1743  return 1;
1744  } else {
1745  $this->error = $this->db->error()." sql=".$sql;
1746  $this->db->rollback();
1747  return -1;
1748  }
1749  } else {
1750  $this->error = $this->db->error()." sql=".$sql;
1751  $this->db->rollback();
1752  return -2;
1753  }
1754  }
1755 
1765  public function validate($user, $force_number = '', $idwarehouse = 0, $notrigger = 0)
1766  {
1767  global $conf, $langs;
1768 
1769  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1770 
1771  $now = dol_now();
1772 
1773  $error = 0;
1774  dol_syslog(get_class($this).'::validate user='.$user->id.', force_number='.$force_number.', idwarehouse='.$idwarehouse);
1775 
1776  // Force to have object complete for checks
1777  $this->fetch_thirdparty();
1778  $this->fetch_lines();
1779 
1780  // Check parameters
1781  if ($this->statut > self::STATUS_DRAFT) { // This is to avoid to validate twice (avoid errors on logs and stock management)
1782  dol_syslog(get_class($this)."::validate no draft status", LOG_WARNING);
1783  return 0;
1784  }
1785  if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ').'/', $this->ref_supplier)) {
1786  $langs->load("errors");
1787  $this->error = $langs->trans("ErrorFieldFormat", $langs->transnoentities("RefSupplier")).'. '.$langs->trans('RemoveString', $langs->transnoentitiesnoconv("CopyOf"));
1788  return -1;
1789  }
1790  if (count($this->lines) <= 0) {
1791  $langs->load("errors");
1792  $this->error = $langs->trans("ErrorObjectMustHaveLinesToBeValidated", $this->ref);
1793  return -1;
1794  }
1795 
1796  $this->db->begin();
1797 
1798  // Define new ref
1799  if ($force_number) {
1800  $num = $force_number;
1801  } elseif (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
1802  $num = $this->getNextNumRef($this->thirdparty);
1803  } else {
1804  $num = $this->ref;
1805  }
1806  $this->newref = dol_sanitizeFileName($num);
1807 
1808  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1809  $sql .= " SET ref='".$this->db->escape($num)."', fk_statut = 1, fk_user_valid = ".((int) $user->id).", date_valid = '".$this->db->idate($now)."'";
1810  $sql .= " WHERE rowid = ".((int) $this->id);
1811 
1812  dol_syslog(get_class($this)."::validate", LOG_DEBUG);
1813  $resql = $this->db->query($sql);
1814  if ($resql) {
1815  // Si on incrémente le produit principal et ses composants à la validation de facture fournisseur
1816  if (!$error && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) {
1817  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1818  $langs->load("agenda");
1819 
1820  $cpt = count($this->lines);
1821  for ($i = 0; $i < $cpt; $i++) {
1822  if ($this->lines[$i]->fk_product > 0) {
1823  $this->line = $this->lines[$i];
1824  $mouvP = new MouvementStock($this->db);
1825  $mouvP->origin = &$this;
1826  $mouvP->setOrigin($this->element, $this->id);
1827  // We increase stock for product
1828  $up_ht_disc = $this->lines[$i]->pu_ht;
1829  if (!empty($this->lines[$i]->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) {
1830  $up_ht_disc = price2num($up_ht_disc * (100 - $this->lines[$i]->remise_percent) / 100, 'MU');
1831  }
1833  $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1834  } else {
1835  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1836  }
1837  if ($result < 0) {
1838  $error++;
1839  }
1840  unset($this->line);
1841  }
1842  }
1843  }
1844 
1845  // Triggers call
1846  if (!$error && empty($notrigger)) {
1847  // Call trigger
1848  $result = $this->call_trigger('BILL_SUPPLIER_VALIDATE', $user);
1849  if ($result < 0) {
1850  $error++;
1851  }
1852  // End call triggers
1853  }
1854 
1855  if (!$error) {
1856  $this->oldref = $this->ref;
1857 
1858  // Rename directory if dir was a temporary ref
1859  if (preg_match('/^[\(]?PROV/i', $this->ref)) {
1860  // Now we rename also files into index
1861  $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)."'";
1862  $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;
1863  $resql = $this->db->query($sql);
1864  if (!$resql) {
1865  $error++; $this->error = $this->db->lasterror();
1866  }
1867 
1868  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1869  $oldref = dol_sanitizeFileName($this->ref);
1870  $newref = dol_sanitizeFileName($num);
1871  $dirsource = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$oldref;
1872  $dirdest = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$newref;
1873  if (!$error && file_exists($dirsource)) {
1874  dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest);
1875 
1876  if (@rename($dirsource, $dirdest)) {
1877  dol_syslog("Rename ok");
1878  // Rename docs starting with $oldref with $newref
1879  $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, '/'));
1880  foreach ($listoffiles as $fileentry) {
1881  $dirsource = $fileentry['name'];
1882  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1883  $dirsource = $fileentry['path'].'/'.$dirsource;
1884  $dirdest = $fileentry['path'].'/'.$dirdest;
1885  @rename($dirsource, $dirdest);
1886  }
1887  }
1888  }
1889  }
1890  }
1891 
1892  // Set new ref and define current statut
1893  if (!$error) {
1894  $this->ref = $num;
1895  $this->statut = self::STATUS_VALIDATED;
1896  //$this->date_validation=$now; this is stored into log table
1897  }
1898 
1899  if (!$error) {
1900  $this->db->commit();
1901  return 1;
1902  } else {
1903  $this->db->rollback();
1904  return -1;
1905  }
1906  } else {
1907  $this->error = $this->db->error();
1908  $this->db->rollback();
1909  return -1;
1910  }
1911  }
1912 
1920  public function setDraft($user, $idwarehouse = -1)
1921  {
1922  // phpcs:enable
1923  global $conf, $langs;
1924 
1925  $error = 0;
1926 
1927  if ($this->statut == self::STATUS_DRAFT) {
1928  dol_syslog(__METHOD__." already draft status", LOG_WARNING);
1929  return 0;
1930  }
1931 
1932  dol_syslog(__METHOD__, LOG_DEBUG);
1933 
1934  $this->db->begin();
1935 
1936  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1937  $sql .= " SET fk_statut = ".self::STATUS_DRAFT;
1938  $sql .= " WHERE rowid = ".((int) $this->id);
1939 
1940  $result = $this->db->query($sql);
1941  if ($result) {
1942  if (!$error) {
1943  $this->oldcopy = clone $this;
1944  }
1945 
1946  // Si on incremente le produit principal et ses composants a la validation de facture fournisseur, on decremente
1947  if ($result >= 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) {
1948  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1949  $langs->load("agenda");
1950 
1951  $cpt = count($this->lines);
1952  for ($i = 0; $i < $cpt; $i++) {
1953  if ($this->lines[$i]->fk_product > 0) {
1954  $mouvP = new MouvementStock($this->db);
1955  $mouvP->origin = &$this;
1956  $mouvP->setOrigin($this->element, $this->id);
1957  // We increase stock for product
1959  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
1960  } else {
1961  $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
1962  }
1963  }
1964  }
1965  }
1966  // Triggers call
1967  if (!$error && empty($notrigger)) {
1968  // Call trigger
1969  $result = $this->call_trigger('BILL_SUPPLIER_UNVALIDATE', $user);
1970  if ($result < 0) {
1971  $error++;
1972  }
1973  // End call triggers
1974  }
1975  if ($error == 0) {
1976  $this->db->commit();
1977  return 1;
1978  } else {
1979  $this->db->rollback();
1980  return -1;
1981  }
1982  } else {
1983  $this->error = $this->db->error();
1984  $this->db->rollback();
1985  return -1;
1986  }
1987  }
1988 
1989 
2023  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)
2024  {
2025  global $langs, $mysoc, $conf;
2026 
2027  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);
2028  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2029 
2030  if ($this->statut == self::STATUS_DRAFT) {
2031  // Clean parameters
2032  if (empty($remise_percent)) {
2033  $remise_percent = 0;
2034  }
2035  if (empty($qty)) {
2036  $qty = 0;
2037  }
2038  if (empty($info_bits)) {
2039  $info_bits = 0;
2040  }
2041  if (empty($rang)) {
2042  $rang = 0;
2043  }
2044  if (empty($ventil)) {
2045  $ventil = 0;
2046  }
2047  if (empty($txtva)) {
2048  $txtva = 0;
2049  }
2050  if (empty($txlocaltax1)) {
2051  $txlocaltax1 = 0;
2052  }
2053  if (empty($txlocaltax2)) {
2054  $txlocaltax2 = 0;
2055  }
2056 
2057  $remise_percent = price2num($remise_percent);
2058  $qty = price2num($qty);
2059  $pu = price2num($pu);
2060  if (!preg_match('/\((.*)\)/', $txtva)) {
2061  $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
2062  }
2063  $txlocaltax1 = price2num($txlocaltax1);
2064  $txlocaltax2 = price2num($txlocaltax2);
2065 
2066  if ($date_start && $date_end && $date_start > $date_end) {
2067  $langs->load("errors");
2068  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
2069  return -1;
2070  }
2071 
2072  $this->db->begin();
2073 
2074  if ($fk_product > 0) {
2075  if (!empty($conf->global->SUPPLIER_INVOICE_WITH_PREDEFINED_PRICES_ONLY)) {
2076  // Check quantity is enough
2077  dol_syslog(get_class($this)."::addline we check supplier prices fk_product=".$fk_product." qty=".$qty." ref_supplier=".$ref_supplier);
2078  $prod = new Product($this->db);
2079  if ($prod->fetch($fk_product) > 0) {
2080  $product_type = $prod->type;
2081  $label = $prod->label;
2082  $fk_prod_fourn_price = 0;
2083 
2084  // We use 'none' instead of $ref_supplier, because $ref_supplier may not exists anymore. So we will take the first supplier price ok.
2085  // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
2086  $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
2087  if ($result > 0) {
2088  if (empty($pu)) {
2089  $pu = $prod->fourn_pu; // Unit price supplier price set by get_buyprice
2090  }
2091  $ref_supplier = $prod->ref_supplier; // Ref supplier price set by get_buyprice
2092  // is remise percent not keyed but present for the product we add it
2093  if ($remise_percent == 0 && $prod->remise_percent != 0) {
2094  $remise_percent = $prod->remise_percent;
2095  }
2096  }
2097  if ($result == 0) { // If result == 0, we failed to found the supplier reference price
2098  $langs->load("errors");
2099  $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
2100  $this->db->rollback();
2101  dol_syslog(get_class($this)."::addline we did not found supplier price, so we can't guess unit price");
2102  //$pu = $prod->fourn_pu; // We do not overwrite unit price
2103  //$ref = $prod->ref_fourn; // We do not overwrite ref supplier price
2104  return -1;
2105  }
2106  if ($result == -1) {
2107  $langs->load("errors");
2108  $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
2109  $this->db->rollback();
2110  dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_DEBUG);
2111  return -1;
2112  }
2113  if ($result < -1) {
2114  $this->error = $prod->error;
2115  $this->db->rollback();
2116  dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_ERR);
2117  return -1;
2118  }
2119  } else {
2120  $this->error = $prod->error;
2121  $this->db->rollback();
2122  return -1;
2123  }
2124  }
2125  } else {
2126  $product_type = $type;
2127  }
2128 
2129  if (!empty($conf->multicurrency->enabled) && $pu_devise > 0) {
2130  $pu = 0;
2131  }
2132 
2133  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $mysoc, $this->thirdparty);
2134 
2135  // Clean vat code
2136  $reg = array();
2137  $vat_src_code = '';
2138  if (preg_match('/\((.*)\)/', $txtva, $reg)) {
2139  $vat_src_code = $reg[1];
2140  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
2141  }
2142 
2143  // Calcul du total TTC et de la TVA pour la ligne a partir de
2144  // qty, pu, remise_percent et txtva
2145  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2146  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2147 
2148  $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);
2149  $total_ht = $tabprice[0];
2150  $total_tva = $tabprice[1];
2151  $total_ttc = $tabprice[2];
2152  $total_localtax1 = $tabprice[9];
2153  $total_localtax2 = $tabprice[10];
2154  $pu_ht = $tabprice[3];
2155 
2156  // MultiCurrency
2157  $multicurrency_total_ht = $tabprice[16];
2158  $multicurrency_total_tva = $tabprice[17];
2159  $multicurrency_total_ttc = $tabprice[18];
2160  $pu_ht_devise = $tabprice[19];
2161 
2162  // Check parameters
2163  if ($type < 0) {
2164  return -1;
2165  }
2166 
2167  if ($rang < 0) {
2168  $rangmax = $this->line_max();
2169  $rang = $rangmax + 1;
2170  }
2171 
2172  // Insert line
2173  $this->line = new SupplierInvoiceLine($this->db);
2174 
2175  $this->line->context = $this->context;
2176 
2177  $this->line->fk_facture_fourn = $this->id;
2178  //$this->line->label=$label; // deprecated
2179  $this->line->desc = $desc;
2180  $this->line->ref_supplier = $ref_supplier;
2181 
2182  $this->line->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs($qty) : $qty); // For credit note, quantity is always positive and unit price negative
2183  $this->line->subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2184 
2185  $this->line->vat_src_code = $vat_src_code;
2186  $this->line->tva_tx = $txtva;
2187  $this->line->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
2188  $this->line->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
2189  $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
2190  $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
2191 
2192  $this->line->total_ht = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_ht) : $total_ht); // For credit note and if qty is negative, total is negative
2193  $this->line->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
2194  $this->line->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
2195  $this->line->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
2196  $this->line->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
2197 
2198  $this->line->fk_product = $fk_product;
2199  $this->line->product_type = $type;
2200  $this->line->remise_percent = $remise_percent;
2201  $this->line->date_start = $date_start;
2202  $this->line->date_end = $date_end;
2203  $this->line->fk_code_ventilation = $ventil;
2204  $this->line->rang = $rang;
2205  $this->line->info_bits = $info_bits;
2206  $this->line->fk_remise_except = $fk_remise_except;
2207 
2208  $this->line->special_code = ((string) $special_code != '' ? $special_code : $this->special_code);
2209  $this->line->fk_parent_line = $fk_parent_line;
2210  $this->line->origin = $this->origin;
2211  $this->line->origin_id = $origin_id;
2212  $this->line->fk_unit = $fk_unit;
2213 
2214  // Multicurrency
2215  $this->line->fk_multicurrency = $this->fk_multicurrency;
2216  $this->line->multicurrency_code = $this->multicurrency_code;
2217  $this->line->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
2218 
2219  $this->line->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
2220  $this->line->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
2221  $this->line->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
2222 
2223  if (is_array($array_options) && count($array_options) > 0) {
2224  $this->line->array_options = $array_options;
2225  }
2226 
2227  $result = $this->line->insert($notrigger);
2228  if ($result > 0) {
2229  // Reorder if child line
2230  if (!empty($fk_parent_line)) {
2231  $this->line_order(true, 'DESC');
2232  } elseif ($rang > 0 && $rang <= count($this->lines)) { // Update all rank of all other lines
2233  $linecount = count($this->lines);
2234  for ($ii = $rang; $ii <= $linecount; $ii++) {
2235  $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1);
2236  }
2237  }
2238 
2239  // Mise a jour informations denormalisees au niveau de la facture meme
2240  $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.
2241  if ($result > 0) {
2242  $this->db->commit();
2243  return $this->line->id;
2244  } else {
2245  $this->error = $this->db->error();
2246  $this->db->rollback();
2247  return -1;
2248  }
2249  } else {
2250  $this->error = $this->line->error;
2251  $this->errors = $this->line->errors;
2252  $this->db->rollback();
2253  return -2;
2254  }
2255  } else {
2256  return 0;
2257  }
2258  }
2259 
2285  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)
2286  {
2287  global $mysoc, $langs;
2288 
2289  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);
2290  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2291 
2292  $pu = price2num($pu);
2293  $qty = price2num($qty);
2294  $remise_percent = price2num($remise_percent);
2295  $pu_devise = price2num($pu_devise);
2296 
2297  // Check parameters
2298  //if (! is_numeric($pu) || ! is_numeric($qty)) return -1;
2299  if ($type < 0) {
2300  return -1;
2301  }
2302 
2303  if ($date_start && $date_end && $date_start > $date_end) {
2304  $langs->load("errors");
2305  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
2306  return -1;
2307  }
2308 
2309  // Clean parameters
2310  if (empty($vatrate)) {
2311  $vatrate = 0;
2312  }
2313  if (empty($txlocaltax1)) {
2314  $txlocaltax1 = 0;
2315  }
2316  if (empty($txlocaltax2)) {
2317  $txlocaltax2 = 0;
2318  }
2319 
2320  $txlocaltax1 = price2num($txlocaltax1);
2321  $txlocaltax2 = price2num($txlocaltax2);
2322 
2323  // Calcul du total TTC et de la TVA pour la ligne a partir de
2324  // qty, pu, remise_percent et txtva
2325  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2326  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2327 
2328  $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $mysoc, $this->thirdparty);
2329 
2330  $reg = array();
2331 
2332  // Clean vat code
2333  $vat_src_code = '';
2334  if (preg_match('/\((.*)\)/', $vatrate, $reg)) {
2335  $vat_src_code = $reg[1];
2336  $vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate.
2337  }
2338 
2339  $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);
2340  $total_ht = $tabprice[0];
2341  $total_tva = $tabprice[1];
2342  $total_ttc = $tabprice[2];
2343  $pu_ht = $tabprice[3];
2344  $pu_tva = $tabprice[4];
2345  $pu_ttc = $tabprice[5];
2346  $total_localtax1 = $tabprice[9];
2347  $total_localtax2 = $tabprice[10];
2348 
2349  // MultiCurrency
2350  $multicurrency_total_ht = $tabprice[16];
2351  $multicurrency_total_tva = $tabprice[17];
2352  $multicurrency_total_ttc = $tabprice[18];
2353  $pu_ht_devise = $tabprice[19];
2354 
2355  if (empty($info_bits)) {
2356  $info_bits = 0;
2357  }
2358 
2359  //Fetch current line from the database and then clone the object and set it in $oldline property
2360  $line = new SupplierInvoiceLine($this->db);
2361  $line->fetch($id);
2362  $line->fetch_optionals();
2363 
2364  $staticline = clone $line;
2365 
2366  if ($idproduct) {
2367  $product = new Product($this->db);
2368  $result = $product->fetch($idproduct);
2369  $product_type = $product->type;
2370  } else {
2371  $idproduct = $staticline->fk_product;
2372  $product_type = $type;
2373  }
2374 
2375  $line->oldline = $staticline;
2376  $line->context = $this->context;
2377 
2378  $line->description = $desc;
2379 
2380  $line->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs($qty) : $qty); // For credit note, quantity is always positive and unit price negative
2381  $line->subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2382  $line->pu_ht = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2383  $line->pu_ttc = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ttc) : $pu_ttc); // For credit note, unit price always negative, always positive otherwise
2384 
2385  $line->remise_percent = $remise_percent;
2386  $line->ref_supplier = $ref_supplier;
2387 
2388  $line->date_start = $date_start;
2389  $line->date_end = $date_end;
2390 
2391  $line->vat_src_code = $vat_src_code;
2392  $line->tva_tx = $vatrate;
2393  $line->localtax1_tx = $txlocaltax1;
2394  $line->localtax2_tx = $txlocaltax2;
2395  $line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
2396  $line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
2397 
2398  $line->total_ht = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_ht) : $total_ht);
2399  $line->total_tva = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_tva) : $total_tva);
2400  $line->total_localtax1 = $total_localtax1;
2401  $line->total_localtax2 = $total_localtax2;
2402  $line->total_ttc = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_ttc) : $total_ttc);
2403 
2404  $line->fk_product = $idproduct;
2405  $line->product_type = $product_type;
2406  $line->info_bits = $info_bits;
2407  $line->fk_unit = $fk_unit;
2408  $line->rang = $rang;
2409 
2410  if (is_array($array_options) && count($array_options) > 0) {
2411  // We replace values in this->line->array_options only for entries defined into $array_options
2412  foreach ($array_options as $key => $value) {
2413  $line->array_options[$key] = $array_options[$key];
2414  }
2415  }
2416 
2417  // Multicurrency
2418  $line->multicurrency_subprice = $pu_ht_devise;
2419  $line->multicurrency_total_ht = $multicurrency_total_ht;
2420  $line->multicurrency_total_tva = $multicurrency_total_tva;
2421  $line->multicurrency_total_ttc = $multicurrency_total_ttc;
2422 
2423  $res = $line->update($notrigger);
2424 
2425  if ($res < 1) {
2426  $this->errors[] = $line->error;
2427  } else {
2428  // Update total price into invoice record
2429  $res = $this->update_price('', 'auto', 0, $this->thirdparty);
2430  }
2431 
2432  return $res;
2433  }
2434 
2442  public function deleteline($rowid, $notrigger = 0)
2443  {
2444  if (!$rowid) {
2445  $rowid = $this->id;
2446  }
2447 
2448  $this->db->begin();
2449 
2450  // Free the discount linked to a line of invoice
2451  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
2452  $sql .= ' SET fk_invoice_supplier_line = NULL';
2453  $sql .= ' WHERE fk_invoice_supplier_line = '.((int) $rowid);
2454 
2455  dol_syslog(get_class($this)."::deleteline", LOG_DEBUG);
2456  $result = $this->db->query($sql);
2457  if (!$result) {
2458  $this->error = $this->db->error();
2459  $this->db->rollback();
2460  return -2;
2461  }
2462 
2463  $line = new SupplierInvoiceLine($this->db);
2464 
2465  if ($line->fetch($rowid) < 1) {
2466  return -1;
2467  }
2468 
2469  $res = $line->delete($notrigger);
2470 
2471  if ($res < 1) {
2472  $this->errors[] = $line->error;
2473  $this->db->rollback();
2474  return -3;
2475  } else {
2476  $res = $this->update_price();
2477 
2478  if ($res > 0) {
2479  $this->db->commit();
2480  return 1;
2481  } else {
2482  $this->db->rollback();
2483  $this->error = $this->db->lasterror();
2484  return -4;
2485  }
2486  }
2487  }
2488 
2489 
2496  public function info($id)
2497  {
2498  $sql = 'SELECT c.rowid, datec, tms as datem, ';
2499  $sql .= ' fk_user_author, fk_user_modif, fk_user_valid';
2500  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as c';
2501  $sql .= ' WHERE c.rowid = '.((int) $id);
2502 
2503  $result = $this->db->query($sql);
2504  if ($result) {
2505  if ($this->db->num_rows($result)) {
2506  $obj = $this->db->fetch_object($result);
2507 
2508  $this->id = $obj->rowid;
2509  if ($obj->fk_user_author) {
2510  $cuser = new User($this->db);
2511  $cuser->fetch($obj->fk_user_author);
2512  $this->user_creation = $cuser;
2513  }
2514  if ($obj->fk_user_valid) {
2515  $vuser = new User($this->db);
2516  $vuser->fetch($obj->fk_user_valid);
2517  $this->user_validation = $vuser;
2518  }
2519  if ($obj->fk_user_modif) {
2520  $muser = new User($this->db);
2521  $muser->fetch($obj->fk_user_modif);
2522  $this->user_modification = $muser;
2523  }
2524  $this->date_creation = $this->db->jdate($obj->datec);
2525  $this->date_modification = $this->db->jdate($obj->datem);
2526  //$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)
2527  }
2528  $this->db->free($result);
2529  } else {
2530  dol_print_error($this->db);
2531  }
2532  }
2533 
2534  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2543  public function list_replacable_supplier_invoices($socid = 0)
2544  {
2545  // phpcs:enable
2546  global $conf;
2547 
2548  $return = array();
2549 
2550  $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut,";
2551  $sql .= " ff.rowid as rowidnext";
2552  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2553  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2554  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture_fourn as ff ON f.rowid = ff.fk_facture_source";
2555  $sql .= " WHERE (f.fk_statut = ".self::STATUS_VALIDATED." OR (f.fk_statut = ".self::STATUS_ABANDONED." AND f.close_code = '".self::CLOSECODE_ABANDONED."'))";
2556  $sql .= " AND f.entity = ".$conf->entity;
2557  $sql .= " AND f.paye = 0"; // Pas classee payee completement
2558  $sql .= " AND pf.fk_paiementfourn IS NULL"; // Aucun paiement deja fait
2559  $sql .= " AND ff.fk_statut IS NULL"; // Renvoi vrai si pas facture de remplacement
2560  if ($socid > 0) {
2561  $sql .= " AND f.fk_soc = ".((int) $socid);
2562  }
2563  $sql .= " ORDER BY f.ref";
2564 
2565  dol_syslog(get_class($this)."::list_replacable_supplier_invoices", LOG_DEBUG);
2566  $resql = $this->db->query($sql);
2567  if ($resql) {
2568  while ($obj = $this->db->fetch_object($resql)) {
2569  $return[$obj->rowid] = array(
2570  'id' => $obj->rowid,
2571  'ref' => $obj->ref,
2572  'status' => $obj->fk_statut
2573  );
2574  }
2575  //print_r($return);
2576  return $return;
2577  } else {
2578  $this->error = $this->db->error();
2579  return -1;
2580  }
2581  }
2582 
2583  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2593  public function list_qualified_avoir_supplier_invoices($socid = 0)
2594  {
2595  // phpcs:enable
2596  global $conf;
2597 
2598  $return = array();
2599 
2600  $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.paye, pf.fk_paiementfourn";
2601  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2602  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2603  $sql .= " WHERE f.entity = ".$conf->entity;
2604  $sql .= " AND f.fk_statut in (".self::STATUS_VALIDATED.",".self::STATUS_CLOSED.")";
2605  $sql .= " AND NOT EXISTS (SELECT rowid from ".MAIN_DB_PREFIX."facture_fourn as ff WHERE f.rowid = ff.fk_facture_source";
2606  $sql .= " AND ff.type=".self::TYPE_REPLACEMENT.")";
2607  $sql .= " AND f.type != ".self::TYPE_CREDIT_NOTE; // Type non 2 si facture non avoir
2608  if ($socid > 0) {
2609  $sql .= " AND f.fk_soc = ".((int) $socid);
2610  }
2611  $sql .= " ORDER BY f.ref";
2612 
2613  dol_syslog(get_class($this)."::list_qualified_avoir_supplier_invoices", LOG_DEBUG);
2614  $resql = $this->db->query($sql);
2615  if ($resql) {
2616  while ($obj = $this->db->fetch_object($resql)) {
2617  $qualified = 0;
2618  if ($obj->fk_statut == self::STATUS_VALIDATED) {
2619  $qualified = 1;
2620  }
2621  if ($obj->fk_statut == self::STATUS_CLOSED) {
2622  $qualified = 1;
2623  }
2624  if ($qualified) {
2625  $paymentornot = ($obj->fk_paiementfourn ? 1 : 0);
2626  $return[$obj->rowid] = array('ref'=>$obj->ref, 'status'=>$obj->fk_statut, 'type'=>$obj->type, 'paye'=>$obj->paye, 'paymentornot'=>$paymentornot);
2627  }
2628  }
2629 
2630  return $return;
2631  } else {
2632  $this->error = $this->db->error();
2633  return -1;
2634  }
2635  }
2636 
2637  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2644  public function load_board($user)
2645  {
2646  // phpcs:enable
2647  global $conf, $langs;
2648 
2649  $sql = 'SELECT ff.rowid, ff.date_lim_reglement as datefin, ff.fk_statut as status, ff.total_ht, ff.total_ttc';
2650  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as ff';
2651  if (empty($user->rights->societe->client->voir) && !$user->socid) {
2652  $sql .= " JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ff.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
2653  }
2654  $sql .= ' WHERE ff.paye = 0';
2655  $sql .= ' AND ff.fk_statut > 0';
2656  $sql .= " AND ff.entity = ".$conf->entity;
2657  if ($user->socid) {
2658  $sql .= ' AND ff.fk_soc = '.((int) $user->socid);
2659  }
2660 
2661  $resql = $this->db->query($sql);
2662  if ($resql) {
2663  $langs->load("bills");
2664  $now = dol_now();
2665 
2666  $response = new WorkboardResponse();
2667  $response->warning_delay = $conf->facture->fournisseur->warning_delay / 60 / 60 / 24;
2668  $response->label = $langs->trans("SupplierBillsToPay");
2669  $response->labelShort = $langs->trans("StatusToPay");
2670 
2671  $response->url = DOL_URL_ROOT.'/fourn/facture/list.php?search_status=1&mainmenu=billing&leftmenu=suppliers_bills';
2672  $response->img = img_object($langs->trans("Bills"), "bill");
2673 
2674  $facturestatic = new FactureFournisseur($this->db);
2675 
2676  while ($obj = $this->db->fetch_object($resql)) {
2677  $facturestatic->date_echeance = $this->db->jdate($obj->datefin);
2678  $facturestatic->statut = $obj->status; // For backward compatibility
2679  $facturestatic->status = $obj->status;
2680 
2681  $response->nbtodo++;
2682  $response->total += $obj->total_ht;
2683 
2684  if ($facturestatic->hasDelay()) {
2685  $response->nbtodolate++;
2686  $response->url_late = DOL_URL_ROOT.'/fourn/facture/list.php?search_option=late&mainmenu=billing&leftmenu=suppliers_bills';
2687  }
2688  }
2689 
2690  $this->db->free($resql);
2691  return $response;
2692  } else {
2693  dol_print_error($this->db);
2694  $this->error = $this->db->error();
2695  return -1;
2696  }
2697  }
2698 
2699 
2713  public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
2714  {
2715  global $langs, $conf, $user, $hookmanager;
2716 
2717  $result = '';
2718 
2719  if ($option == 'withdraw') {
2720  $url = DOL_URL_ROOT.'/compta/facture/prelevement.php?facid='.$this->id.'&type=bank-transfer';
2721  } elseif ($option == 'document') {
2722  $url = DOL_URL_ROOT.'/fourn/facture/document.php?facid='.$this->id;
2723  } else {
2724  $url = DOL_URL_ROOT.'/fourn/facture/card.php?facid='.$this->id;
2725  }
2726 
2727  if ($short) {
2728  return $url;
2729  }
2730 
2731  if ($option !== 'nolink') {
2732  // Add param to save lastsearch_values or not
2733  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
2734  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
2735  $add_save_lastsearch_values = 1;
2736  }
2737  if ($add_save_lastsearch_values) {
2738  $url .= '&save_lastsearch_values=1';
2739  }
2740  }
2741 
2742  $picto = $this->picto;
2743  if ($this->type == self::TYPE_REPLACEMENT) {
2744  $picto .= 'r'; // Replacement invoice
2745  }
2746  if ($this->type == self::TYPE_CREDIT_NOTE) {
2747  $picto .= 'a'; // Credit note
2748  }
2749  if ($this->type == self::TYPE_DEPOSIT) {
2750  $picto .= 'd'; // Deposit invoice
2751  }
2752 
2753  $label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("SupplierInvoice").'</u>';
2754  if ($this->type == self::TYPE_REPLACEMENT) {
2755  $label = '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("InvoiceReplace").'</u>';
2756  } elseif ($this->type == self::TYPE_CREDIT_NOTE) {
2757  $label = '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("CreditNote").'</u>';
2758  } elseif ($this->type == self::TYPE_DEPOSIT) {
2759  $label = '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("Deposit").'</u>';
2760  }
2761  if (isset($this->status)) {
2762  $alreadypaid = -1;
2763  if (isset($this->alreadypaid)) {
2764  $alreadypaid = $this->alreadypaid;
2765  }
2766 
2767  $label .= ' '.$this->getLibStatut(5, $alreadypaid);
2768  }
2769  if (!empty($this->ref)) {
2770  $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
2771  }
2772  if (!empty($this->ref_supplier)) {
2773  $label .= '<br><b>'.$langs->trans('RefSupplier').':</b> '.$this->ref_supplier;
2774  }
2775  if (!empty($this->label)) {
2776  $label .= '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
2777  }
2778  if (!empty($this->date)) {
2779  $label .= '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
2780  }
2781  if (!empty($this->total_ht)) {
2782  $label .= '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
2783  }
2784  if (!empty($this->total_tva)) {
2785  $label .= '<br><b>'.$langs->trans('AmountVAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
2786  }
2787  if (!empty($this->total_ttc)) {
2788  $label .= '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
2789  }
2790  if ($moretitle) {
2791  $label .= ' - '.$moretitle;
2792  }
2793 
2794  $ref = $this->ref;
2795  if (empty($ref)) {
2796  $ref = $this->id;
2797  }
2798 
2799  $linkclose = '';
2800  if (empty($notooltip)) {
2801  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2802  $label = $langs->trans("ShowSupplierInvoice");
2803  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
2804  }
2805  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
2806  $linkclose .= ' class="classfortooltip"';
2807  }
2808 
2809  $linkstart = '<a href="'.$url.'"';
2810  $linkstart .= $linkclose.'>';
2811  $linkend = '</a>';
2812 
2813  $result .= $linkstart;
2814  if ($withpicto) {
2815  $result .= img_object(($notooltip ? '' : $label), $picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
2816  }
2817  if ($withpicto != 2) {
2818  $result .= ($max ?dol_trunc($ref, $max) : $ref);
2819  }
2820  $result .= $linkend;
2821 
2822  if ($addlinktonotes) {
2823  $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
2824  if ($txttoshow) {
2825  $notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
2826  $result .= ' <span class="note inline-block">';
2827  $result .= '<a href="'.DOL_URL_ROOT.'/fourn/facture/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
2828  $result .= img_picto('', 'note');
2829  $result .= '</a>';
2830  $result .= '</span>';
2831  }
2832  }
2833  global $action;
2834  $hookmanager->initHooks(array($this->element . 'dao'));
2835  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
2836  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2837  if ($reshook > 0) {
2838  $result = $hookmanager->resPrint;
2839  } else {
2840  $result .= $hookmanager->resPrint;
2841  }
2842  return $result;
2843  }
2844 
2853  public function getNextNumRef($soc, $mode = 'next')
2854  {
2855  global $db, $langs, $conf;
2856  $langs->load("orders");
2857 
2858  // Clean parameters (if not defined or using deprecated value)
2859  if (empty($conf->global->INVOICE_SUPPLIER_ADDON_NUMBER)) {
2860  $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER = 'mod_facture_fournisseur_cactus';
2861  }
2862 
2863  $mybool = false;
2864 
2865  $file = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER.".php";
2866  $classname = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER;
2867 
2868  // Include file with class
2869  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2870 
2871  foreach ($dirmodels as $reldir) {
2872  $dir = dol_buildpath($reldir."core/modules/supplier_invoice/");
2873 
2874  // Load file with numbering class (if found)
2875  $mybool |= @include_once $dir.$file;
2876  }
2877 
2878  if ($mybool === false) {
2879  dol_print_error('', "Failed to include file ".$file);
2880  return '';
2881  }
2882 
2883  $obj = new $classname();
2884  $numref = "";
2885  $numref = $obj->getNumRef($soc, $this, $mode);
2886 
2887  if ($numref != "") {
2888  return $numref;
2889  } else {
2890  $this->error = $obj->error;
2891  return -1;
2892  }
2893  }
2894 
2895 
2904  public function initAsSpecimen($option = '')
2905  {
2906  global $langs, $conf;
2907  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
2908 
2909  $now = dol_now();
2910 
2911  // Load array of products prodids
2912  $num_prods = 0;
2913  $prodids = array();
2914 
2915  $sql = "SELECT rowid";
2916  $sql .= " FROM ".MAIN_DB_PREFIX."product";
2917  $sql .= " WHERE entity IN (".getEntity('product').")";
2918  $sql .= $this->db->plimit(100);
2919 
2920  $resql = $this->db->query($sql);
2921  if ($resql) {
2922  $num_prods = $this->db->num_rows($resql);
2923  $i = 0;
2924  while ($i < $num_prods) {
2925  $i++;
2926  $row = $this->db->fetch_row($resql);
2927  $prodids[$i] = $row[0];
2928  }
2929  }
2930 
2931  // Initialise parametres
2932  $this->id = 0;
2933  $this->ref = 'SPECIMEN';
2934  $this->ref_supplier = 'SUPPLIER_REF_SPECIMEN';
2935  $this->specimen = 1;
2936  $this->socid = 1;
2937  $this->date = $now;
2938  $this->date_lim_reglement = $this->date + 3600 * 24 * 30;
2939  $this->cond_reglement_code = 'RECEP';
2940  $this->mode_reglement_code = 'CHQ';
2941 
2942  $this->note_public = 'This is a comment (public)';
2943  $this->note_private = 'This is a comment (private)';
2944 
2945  $this->multicurrency_tx = 1;
2946  $this->multicurrency_code = $conf->currency;
2947 
2948  $xnbp = 0;
2949  if (empty($option) || $option != 'nolines') {
2950  // Lines
2951  $nbp = 5;
2952  while ($xnbp < $nbp) {
2953  $line = new SupplierInvoiceLine($this->db);
2954  $line->desc = $langs->trans("Description")." ".$xnbp;
2955  $line->qty = 1;
2956  $line->subprice = 100;
2957  $line->pu_ht = 100; // the canelle template use pu_ht and not subprice
2958  $line->price = 100;
2959  $line->tva_tx = 19.6;
2960  $line->localtax1_tx = 0;
2961  $line->localtax2_tx = 0;
2962  if ($xnbp == 2) {
2963  $line->total_ht = 50;
2964  $line->total_ttc = 59.8;
2965  $line->total_tva = 9.8;
2966  $line->remise_percent = 50;
2967  } else {
2968  $line->total_ht = 100;
2969  $line->total_ttc = 119.6;
2970  $line->total_tva = 19.6;
2971  $line->remise_percent = 0;
2972  }
2973 
2974  if ($num_prods > 0) {
2975  $prodid = mt_rand(1, $num_prods);
2976  $line->fk_product = $prodids[$prodid];
2977  }
2978  $line->product_type = 0;
2979 
2980  $this->lines[$xnbp] = $line;
2981 
2982  $this->total_ht += $line->total_ht;
2983  $this->total_tva += $line->total_tva;
2984  $this->total_ttc += $line->total_ttc;
2985 
2986  $xnbp++;
2987  }
2988  }
2989 
2990  $this->amount_ht = $xnbp * 100;
2991  $this->total_ht = $xnbp * 100;
2992  $this->total_tva = $xnbp * 19.6;
2993  $this->total_ttc = $xnbp * 119.6;
2994  }
2995 
2996  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3002  public function load_state_board()
3003  {
3004  // phpcs:enable
3005  global $conf, $user;
3006 
3007  $this->nb = array();
3008 
3009  $clause = "WHERE";
3010 
3011  $sql = "SELECT count(f.rowid) as nb";
3012  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
3013  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
3014  if (empty($user->rights->societe->client->voir) && !$user->socid) {
3015  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
3016  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3017  $clause = "AND";
3018  }
3019  $sql .= " ".$clause." f.entity = ".$conf->entity;
3020 
3021  $resql = $this->db->query($sql);
3022  if ($resql) {
3023  while ($obj = $this->db->fetch_object($resql)) {
3024  $this->nb["supplier_invoices"] = $obj->nb;
3025  }
3026  $this->db->free($resql);
3027  return 1;
3028  } else {
3029  dol_print_error($this->db);
3030  $this->error = $this->db->error();
3031  return -1;
3032  }
3033  }
3034 
3043  public function createFromClone(User $user, $fromid, $invertdetail = 0)
3044  {
3045  global $conf, $langs;
3046 
3047  $error = 0;
3048 
3049  $object = new FactureFournisseur($this->db);
3050 
3051  $this->db->begin();
3052 
3053  // Load source object
3054  $object->fetch($fromid);
3055  $object->id = 0;
3056  $object->statut = self::STATUS_DRAFT; // For backward compatibility
3057  $object->status = self::STATUS_DRAFT;
3058 
3059  $object->fetch_thirdparty(); // We need it to recalculate VAT localtaxes according to main sale taxes and vendor
3060 
3061  // Clear fields
3062  $object->ref_supplier = (empty($this->ref_supplier) ? $langs->trans("CopyOf").' '.$object->ref_supplier : $this->ref_supplier);
3063  $object->author = $user->id;
3064  $object->user_valid = '';
3065  $object->fk_facture_source = 0;
3066  $object->date_creation = '';
3067  $object->date_validation = '';
3068  $object->date = (empty($this->date) ? '' : $this->date);
3069  $object->date_echeance = '';
3070  $object->ref_client = '';
3071  $object->close_code = '';
3072  $object->close_note = '';
3073  if ($conf->global->MAIN_DONT_KEEP_NOTE_ON_CLONING == 1) {
3074  $object->note_private = '';
3075  $object->note_public = '';
3076  }
3077 
3078  // Loop on each line of new invoice
3079  foreach ($object->lines as $i => $line) {
3080  if (isset($object->lines[$i]->info_bits) && ($object->lines[$i]->info_bits & 0x02) == 0x02) { // We do not clone line of discounts
3081  unset($object->lines[$i]);
3082  }
3083  }
3084 
3085  // Create clone
3086  $object->context['createfromclone'] = 'createfromclone';
3087  $result = $object->create($user);
3088 
3089  // Other options
3090  if ($result < 0) {
3091  $this->error = $object->error;
3092  $this->errors = $object->errors;
3093  $error++;
3094  }
3095 
3096  if (!$error) {
3097  }
3098 
3099  unset($object->context['createfromclone']);
3100 
3101  // End
3102  if (!$error) {
3103  $this->db->commit();
3104  return $object->id;
3105  } else {
3106  $this->db->rollback();
3107  return -1;
3108  }
3109  }
3110 
3122  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
3123  {
3124  global $conf, $user, $langs;
3125 
3126  $langs->load("suppliers");
3127  $outputlangs->load("products");
3128 
3129  // Set the model on the model name to use
3130  if (empty($modele)) {
3131  if (!empty($conf->global->INVOICE_SUPPLIER_ADDON_PDF)) {
3132  $modele = $conf->global->INVOICE_SUPPLIER_ADDON_PDF;
3133  } else {
3134  $modele = ''; // No default value. For supplier invoice, we allow to disable all PDF generation
3135  }
3136  }
3137 
3138  if (empty($modele)) {
3139  return 0;
3140  } else {
3141  $modelpath = "core/modules/supplier_invoice/doc/";
3142 
3143  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
3144  }
3145  }
3146 
3151  public function getRights()
3152  {
3153  global $user;
3154 
3155  return $user->rights->fournisseur->facture;
3156  }
3157 
3166  public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
3167  {
3168  $tables = array(
3169  'facture_fourn'
3170  );
3171 
3172  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
3173  }
3174 
3183  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
3184  {
3185  $tables = array(
3186  'facture_fourn_det'
3187  );
3188 
3189  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
3190  }
3191 
3197  public function hasDelay()
3198  {
3199  global $conf;
3200 
3201  $now = dol_now();
3202 
3203  if (!$this->date_echeance) {
3204  return false;
3205  }
3206 
3207  $status = isset($this->status) ? $this->status : $this->statut;
3208 
3209  return ($status == self::STATUS_VALIDATED) && ($this->date_echeance < ($now - $conf->facture->fournisseur->warning_delay));
3210  }
3211 
3217  public function isCreditNoteUsed()
3218  {
3219  $isUsed = false;
3220 
3221  $sql = "SELECT fk_invoice_supplier FROM ".MAIN_DB_PREFIX."societe_remise_except WHERE fk_invoice_supplier_source = ".((int) $this->id);
3222  $resql = $this->db->query($sql);
3223  if (!empty($resql)) {
3224  $obj = $this->db->fetch_object($resql);
3225  if (!empty($obj->fk_invoice_supplier)) {
3226  $isUsed = true;
3227  }
3228  }
3229 
3230  return $isUsed;
3231  }
3232 }
3233 
3234 
3235 
3240 {
3244  public $element = 'facture_fourn_det';
3245 
3249  public $table_element = 'facture_fourn_det';
3250 
3251  public $oldline;
3252 
3257  public $ref;
3258 
3263  public $product_ref;
3264 
3270  public $ref_supplier;
3271 
3276  public $product_desc;
3277 
3284  public $pu_ht;
3285 
3290  public $subprice;
3291 
3296  public $pu_ttc;
3297 
3298 
3303  public $fk_facture_fourn;
3304 
3310  public $label;
3311 
3316  public $description;
3317 
3318  public $date_start;
3319  public $date_end;
3320 
3321  public $skip_update_total; // Skip update price total for special lines
3322 
3326  public $situation_percent;
3327 
3331  public $fk_prev_id;
3332 
3337  public $vat_src_code;
3338 
3343  public $tva_tx;
3344 
3349  public $localtax1_tx;
3350 
3355  public $localtax2_tx;
3356 
3361  public $qty;
3362 
3367  public $remise_percent;
3368 
3373  public $total_ht;
3374 
3379  public $total_ttc;
3380 
3385  public $total_tva;
3386 
3391  public $total_localtax1;
3392 
3397  public $total_localtax2;
3398 
3402  public $fk_product;
3403 
3408  public $product_type;
3409 
3414  public $product_label;
3415 
3422  public $info_bits;
3423 
3428  public $fk_remise_except;
3429 
3433  public $fk_parent_line;
3434 
3435  public $special_code;
3436 
3440  public $rang;
3441 
3446  public $localtax1_type;
3447 
3452  public $localtax2_type;
3453 
3454  // Multicurrency
3458  public $fk_multicurrency;
3459 
3460  public $multicurrency_code;
3461  public $multicurrency_subprice;
3462  public $multicurrency_total_ht;
3463  public $multicurrency_total_tva;
3464  public $multicurrency_total_ttc;
3465 
3466 
3472  public function __construct($db)
3473  {
3474  $this->db = $db;
3475  }
3476 
3483  public function fetch($rowid)
3484  {
3485  $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';
3486  $sql .= ', f.localtax1_type, f.localtax2_type, f.localtax1_tx, f.localtax2_tx, f.total_localtax1, f.total_localtax2, f.fk_remise_except';
3487  $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';
3488  $sql .= ', p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.description as product_desc';
3489  $sql .= ', f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, multicurrency_total_ttc';
3490  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
3491  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
3492  $sql .= ' WHERE f.rowid = '.((int) $rowid);
3493  $sql .= ' ORDER BY f.rang, f.rowid';
3494 
3495  $query = $this->db->query($sql);
3496 
3497  if (!$query) {
3498  $this->errors[] = $this->db->error();
3499  return -1;
3500  }
3501 
3502  if (!$this->db->num_rows($query)) {
3503  return 0;
3504  }
3505 
3506  $obj = $this->db->fetch_object($query);
3507 
3508  $this->id = $obj->rowid;
3509  $this->rowid = $obj->rowid;
3510  $this->fk_facture_fourn = $obj->fk_facture_fourn;
3511  $this->description = $obj->description;
3512  $this->date_start = $obj->date_start;
3513  $this->date_end = $obj->date_end;
3514  $this->product_ref = $obj->product_ref;
3515  $this->ref_supplier = $obj->ref_supplier;
3516  $this->product_desc = $obj->product_desc;
3517 
3518  $this->subprice = $obj->pu_ht;
3519  $this->pu_ht = $obj->pu_ht;
3520  $this->pu_ttc = $obj->pu_ttc;
3521  $this->tva_tx = $obj->tva_tx;
3522  $this->localtax1_tx = $obj->localtax1_tx;
3523  $this->localtax2_tx = $obj->localtax2_tx;
3524  $this->localtax1_type = $obj->localtax1_type;
3525  $this->localtax2_type = $obj->localtax2_type;
3526 
3527  $this->qty = $obj->qty;
3528  $this->remise_percent = $obj->remise_percent;
3529  $this->fk_remise_except = $obj->fk_remise_except;
3530  //$this->tva = $obj->total_tva; // deprecated
3531  $this->total_ht = $obj->total_ht;
3532  $this->total_tva = $obj->total_tva;
3533  $this->total_localtax1 = $obj->total_localtax1;
3534  $this->total_localtax2 = $obj->total_localtax2;
3535  $this->total_ttc = $obj->total_ttc;
3536  $this->fk_product = $obj->fk_product;
3537  $this->product_type = $obj->product_type;
3538  $this->product_label = $obj->product_label;
3539  $this->info_bits = $obj->info_bits;
3540  $this->tva_npr = ($obj->info_bits & 1 == 1) ? 1 : 0;
3541  $this->fk_parent_line = $obj->fk_parent_line;
3542  $this->special_code = $obj->special_code;
3543  $this->rang = $obj->rang;
3544  $this->fk_unit = $obj->fk_unit;
3545 
3546  $this->multicurrency_subprice = $obj->multicurrency_subprice;
3547  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
3548  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
3549  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
3550 
3551  $this->fetch_optionals();
3552 
3553  return 1;
3554  }
3555 
3562  public function delete($notrigger = 0)
3563  {
3564  global $user, $conf;
3565 
3566  dol_syslog(get_class($this)."::deleteline rowid=".((int) $this->id), LOG_DEBUG);
3567 
3568  $error = 0;
3569 
3570  $this->db->begin();
3571 
3572  if (!$notrigger) {
3573  if ($this->call_trigger('LINEBILL_SUPPLIER_DELETE', $user) < 0) {
3574  $error++;
3575  }
3576  }
3577 
3578  $this->deleteObjectLinked();
3579 
3580  // Remove extrafields
3581  if (!$error) {
3582  $result = $this->deleteExtraFields();
3583  if ($result < 0) {
3584  $error++;
3585  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
3586  }
3587  }
3588 
3589  if (!$error) {
3590  // Supprime ligne
3591  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det ';
3592  $sql .= " WHERE rowid = ".((int) $this->id);
3593  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
3594  $resql = $this->db->query($sql);
3595  if (!$resql) {
3596  $error++;
3597  $this->error = $this->db->lasterror();
3598  }
3599  }
3600 
3601  if (!$error) {
3602  $this->db->commit();
3603  return 1;
3604  } else {
3605  $this->db->rollback();
3606  return -1;
3607  }
3608  }
3609 
3616  public function update($notrigger = 0)
3617  {
3618  global $conf;
3619 
3620  $pu = price2num($this->pu_ht);
3621  $qty = price2num($this->qty);
3622 
3623  // Check parameters
3624  if (empty($this->qty)) {
3625  $this->qty = 0;
3626  }
3627 
3628  if ($this->product_type < 0) {
3629  return -1;
3630  }
3631 
3632  // Clean parameters
3633  if (empty($this->remise_percent)) {
3634  $this->remise_percent = 0;
3635  }
3636  if (empty($this->tva_tx)) {
3637  $this->tva_tx = 0;
3638  }
3639  if (empty($this->localtax1_tx)) {
3640  $this->localtax1_tx = 0;
3641  }
3642  if (empty($this->localtax2_tx)) {
3643  $this->localtax2_tx = 0;
3644  }
3645 
3646  if (empty($this->pa_ht)) {
3647  $this->pa_ht = 0;
3648  }
3649  if (empty($this->multicurrency_subprice)) {
3650  $this->multicurrency_subprice = 0;
3651  }
3652  if (empty($this->multicurrency_total_ht)) {
3653  $this->multicurrency_total_ht = 0;
3654  }
3655  if (empty($this->multicurrency_total_tva)) {
3656  $this->multicurrency_total_tva = 0;
3657  }
3658  if (empty($this->multicurrency_total_ttc)) {
3659  $this->multicurrency_total_ttc = 0;
3660  }
3661 
3662  $fk_product = (int) $this->fk_product;
3663  $fk_unit = (int) $this->fk_unit;
3664 
3665  $this->db->begin();
3666 
3667  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
3668  $sql .= " description = '".$this->db->escape($this->description)."'";
3669  $sql .= ", ref = '".$this->db->escape($this->ref_supplier ? $this->ref_supplier : $this->ref)."'";
3670  $sql .= ", date_start = ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : "null");
3671  $sql .= ", date_end = ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : "null");
3672  $sql .= ", pu_ht = ".price2num($this->pu_ht);
3673  $sql .= ", pu_ttc = ".price2num($this->pu_ttc);
3674  $sql .= ", qty = ".price2num($this->qty);
3675  $sql .= ", remise_percent = ".price2num($this->remise_percent);
3676  if ($this->fk_remise_except > 0) $sql .= ", fk_remise_except=".((int) $this->fk_remise_except);
3677  else $sql .= ", fk_remise_except=null";
3678  $sql .= ", vat_src_code = '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."'";
3679  $sql .= ", tva_tx = ".price2num($this->tva_tx);
3680  $sql .= ", localtax1_tx = ".price2num($this->localtax1_tx);
3681  $sql .= ", localtax2_tx = ".price2num($this->localtax2_tx);
3682  $sql .= ", localtax1_type = '".$this->db->escape($this->localtax1_type)."'";
3683  $sql .= ", localtax2_type = '".$this->db->escape($this->localtax2_type)."'";
3684  $sql .= ", total_ht = ".price2num($this->total_ht);
3685  $sql .= ", tva= ".price2num($this->total_tva);
3686  $sql .= ", total_localtax1= ".price2num($this->total_localtax1);
3687  $sql .= ", total_localtax2= ".price2num($this->total_localtax2);
3688  $sql .= ", total_ttc = ".price2num($this->total_ttc);
3689  $sql .= ", fk_product = ".($fk_product > 0 ? (int) $fk_product : 'null');
3690  $sql .= ", product_type = ".((int) $this->product_type);
3691  $sql .= ", info_bits = ".((int) $this->info_bits);
3692  $sql .= ", fk_unit = ".($fk_unit > 0 ? (int) $fk_unit : 'null');
3693 
3694  if (!empty($this->rang)) {
3695  $sql .= ", rang=".((int) $this->rang);
3696  }
3697 
3698  // Multicurrency
3699  $sql .= " , multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
3700  $sql .= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
3701  $sql .= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
3702  $sql .= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
3703 
3704  $sql .= " WHERE rowid = ".((int) $this->id);
3705 
3706  dol_syslog(get_class($this)."::update", LOG_DEBUG);
3707  $resql = $this->db->query($sql);
3708 
3709  if (!$resql) {
3710  $this->db->rollback();
3711  $this->error = $this->db->lasterror();
3712  return -1;
3713  }
3714 
3715  $this->rowid = $this->id;
3716  $error = 0;
3717 
3718  if (!$error) {
3719  $result = $this->insertExtraFields();
3720  if ($result < 0) {
3721  $error++;
3722  }
3723  }
3724 
3725  if (!$error && !$notrigger) {
3726  global $langs, $user;
3727 
3728  // Call trigger
3729  if ($this->call_trigger('LINEBILL_SUPPLIER_MODIFY', $user) < 0) {
3730  $this->db->rollback();
3731  return -1;
3732  }
3733  // End call triggers
3734  }
3735 
3736  if ($error) {
3737  $this->db->rollback();
3738  return -1;
3739  }
3740 
3741  $this->db->commit();
3742  return 1;
3743  }
3744 
3751  public function insert($notrigger = 0)
3752  {
3753  global $user, $conf, $langs;
3754 
3755  $error = 0;
3756 
3757  dol_syslog(get_class($this)."::insert rang=".$this->rang, LOG_DEBUG);
3758 
3759  // Clean parameters
3760  $this->desc = trim($this->desc);
3761  if (empty($this->tva_tx)) {
3762  $this->tva_tx = 0;
3763  }
3764  if (empty($this->localtax1_tx)) {
3765  $this->localtax1_tx = 0;
3766  }
3767  if (empty($this->localtax2_tx)) {
3768  $this->localtax2_tx = 0;
3769  }
3770  if (empty($this->localtax1_type)) {
3771  $this->localtax1_type = '0';
3772  }
3773  if (empty($this->localtax2_type)) {
3774  $this->localtax2_type = '0';
3775  }
3776  if (empty($this->total_tva)) {
3777  $this->total_tva = 0;
3778  }
3779  if (empty($this->total_localtax1)) {
3780  $this->total_localtax1 = 0;
3781  }
3782  if (empty($this->total_localtax2)) {
3783  $this->total_localtax2 = 0;
3784  }
3785  if (empty($this->rang)) {
3786  $this->rang = 0;
3787  }
3788  if (empty($this->remise_percent)) {
3789  $this->remise_percent = 0;
3790  }
3791  if (empty($this->info_bits)) {
3792  $this->info_bits = 0;
3793  }
3794  if (empty($this->subprice)) {
3795  $this->subprice = 0;
3796  }
3797  if (empty($this->special_code)) {
3798  $this->special_code = 0;
3799  }
3800  if (empty($this->fk_parent_line)) {
3801  $this->fk_parent_line = 0;
3802  }
3803  if (!isset($this->situation_percent) || $this->situation_percent > 100 || (string) $this->situation_percent == '') {
3804  $this->situation_percent = 100;
3805  }
3806 
3807  if (empty($this->pa_ht)) {
3808  $this->pa_ht = 0;
3809  }
3810  if (empty($this->multicurrency_subprice)) {
3811  $this->multicurrency_subprice = 0;
3812  }
3813  if (empty($this->multicurrency_total_ht)) {
3814  $this->multicurrency_total_ht = 0;
3815  }
3816  if (empty($this->multicurrency_total_tva)) {
3817  $this->multicurrency_total_tva = 0;
3818  }
3819  if (empty($this->multicurrency_total_ttc)) {
3820  $this->multicurrency_total_ttc = 0;
3821  }
3822 
3823 
3824  // Check parameters
3825  if ($this->product_type < 0) {
3826  $this->error = 'ErrorProductTypeMustBe0orMore';
3827  return -1;
3828  }
3829  if (!empty($this->fk_product) && $this->fk_product > 0) {
3830  // Check product exists
3831  $result = Product::isExistingObject('product', $this->fk_product);
3832  if ($result <= 0) {
3833  $this->error = 'ErrorProductIdDoesNotExists';
3834  return -1;
3835  }
3836  }
3837 
3838  $this->db->begin();
3839 
3840  // Insertion dans base de la ligne
3841  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
3842  $sql .= ' (fk_facture_fourn, fk_parent_line, label, description, ref, qty,';
3843  $sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3844  $sql .= ' fk_product, product_type, remise_percent, fk_remise_except, pu_ht, pu_ttc,';
3845  $sql .= ' date_start, date_end, fk_code_ventilation, rang, special_code,';
3846  $sql .= ' info_bits, total_ht, tva, total_ttc, total_localtax1, total_localtax2, fk_unit';
3847  $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
3848  $sql .= ')';
3849  $sql .= " VALUES (".$this->fk_facture_fourn.",";
3850  $sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape($this->fk_parent_line)."'" : "null").",";
3851  $sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
3852  $sql .= " '".$this->db->escape($this->desc ? $this->desc : $this->description)."',";
3853  $sql .= " '".$this->db->escape($this->ref_supplier)."',";
3854  $sql .= " ".price2num($this->qty).",";
3855 
3856  $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape($this->vat_src_code)."'").",";
3857  $sql .= " ".price2num($this->tva_tx).",";
3858  $sql .= " ".price2num($this->localtax1_tx).",";
3859  $sql .= " ".price2num($this->localtax2_tx).",";
3860  $sql .= " '".$this->db->escape($this->localtax1_type)."',";
3861  $sql .= " '".$this->db->escape($this->localtax2_type)."',";
3862  $sql .= ' '.((!empty($this->fk_product) && $this->fk_product > 0) ? $this->fk_product : "null").',';
3863  $sql .= " ".((int) $this->product_type).",";
3864  $sql .= " ".price2num($this->remise_percent).",";
3865  $sql .= ' '.(! empty($this->fk_remise_except) ? ((int) $this->fk_remise_except) : "null").',';
3866  $sql .= " ".price2num($this->subprice).",";
3867  $sql .= " ".(!empty($this->qty) ?price2num($this->total_ttc / $this->qty) : price2num($this->total_ttc)).",";
3868  $sql .= " ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null").",";
3869  $sql .= " ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").",";
3870  $sql .= ' '.(!empty($this->fk_code_ventilation) ? $this->fk_code_ventilation : 0).',';
3871  $sql .= ' '.((int) $this->rang).',';
3872  $sql .= ' '.((int) $this->special_code).',';
3873  $sql .= " ".((int) $this->info_bits).",";
3874  $sql .= " ".price2num($this->total_ht).",";
3875  $sql .= " ".price2num($this->total_tva).",";
3876  $sql .= " ".price2num($this->total_ttc).",";
3877  $sql .= " ".price2num($this->total_localtax1).",";
3878  $sql .= " ".price2num($this->total_localtax2);
3879  $sql .= ", ".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
3880  $sql .= ", ".(int) $this->fk_multicurrency;
3881  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
3882  $sql .= ", ".price2num($this->multicurrency_subprice);
3883  $sql .= ", ".price2num($this->multicurrency_total_ht);
3884  $sql .= ", ".price2num($this->multicurrency_total_tva);
3885  $sql .= ", ".price2num($this->multicurrency_total_ttc);
3886  $sql .= ')';
3887 
3888  $resql = $this->db->query($sql);
3889  if ($resql) {
3890  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
3891  $this->rowid = $this->id; // backward compatibility
3892 
3893  if (!$error) {
3894  $result = $this->insertExtraFields();
3895  if ($result < 0) {
3896  $error++;
3897  }
3898  }
3899 
3900  // Si fk_remise_except defini, on lie la remise a la facture
3901  // ce qui la flague comme "consommee".
3902  if ($this->fk_remise_except) {
3903  $discount = new DiscountAbsolute($this->db);
3904  $result = $discount->fetch($this->fk_remise_except);
3905  if ($result >= 0) {
3906  // Check if discount was found
3907  if ($result > 0) {
3908  // Check if discount not already affected to another invoice
3909  if ($discount->fk_facture_line > 0) {
3910  if (empty($noerrorifdiscountalreadylinked)) {
3911  $this->error = $langs->trans("ErrorDiscountAlreadyUsed", $discount->id);
3912  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
3913  $this->db->rollback();
3914  return -3;
3915  }
3916  } else {
3917  $result = $discount->link_to_invoice($this->rowid, 0);
3918  if ($result < 0) {
3919  $this->error = $discount->error;
3920  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
3921  $this->db->rollback();
3922  return -3;
3923  }
3924  }
3925  } else {
3926  $this->error = $langs->trans("ErrorADiscountThatHasBeenRemovedIsIncluded");
3927  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
3928  $this->db->rollback();
3929  return -3;
3930  }
3931  } else {
3932  $this->error = $discount->error;
3933  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
3934  $this->db->rollback();
3935  return -3;
3936  }
3937  }
3938 
3939  if (!$error && !$notrigger) {
3940  // Call trigger
3941  $result = $this->call_trigger('LINEBILL_SUPPLIER_CREATE', $user);
3942  if ($result < 0) {
3943  $this->db->rollback();
3944  return -2;
3945  }
3946  // End call triggers
3947  }
3948 
3949  $this->db->commit();
3950  return $this->id;
3951  } else {
3952  $this->error = $this->db->error();
3953  $this->db->rollback();
3954  return -2;
3955  }
3956  }
3957 
3958  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3964  public function update_total()
3965  {
3966  // phpcs:enable
3967  $this->db->begin();
3968 
3969  // Mise a jour ligne en base
3970  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
3971  $sql .= " total_ht = ".price2num($this->total_ht);
3972  $sql .= ", tva= ".price2num($this->total_tva);
3973  $sql .= ", total_localtax1 = ".price2num($this->total_localtax1);
3974  $sql .= ", total_localtax2 = ".price2num($this->total_localtax2);
3975  $sql .= ", total_ttc = ".price2num($this->total_ttc);
3976  $sql .= " WHERE rowid = ".((int) $this->rowid);
3977 
3978  dol_syslog("FactureFournisseurLigne.class.php::update_total", LOG_DEBUG);
3979 
3980  $resql = $this->db->query($sql);
3981  if ($resql) {
3982  $this->db->commit();
3983  return 1;
3984  } else {
3985  $this->error = $this->db->error();
3986  $this->db->rollback();
3987  return -2;
3988  }
3989  }
3990 }
FactureFournisseur\update
update($user=null, $notrigger=0)
Update database.
Definition: fournisseur.facture.class.php:1135
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:7839
FactureFournisseur\fetch_lines
fetch_lines()
Load this->lines.
Definition: fournisseur.facture.class.php:1030
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:6097
db
$conf db
API class for accounts.
Definition: inc.php:41
dol_escape_htmltag
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
Definition: functions.lib.php:1468
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:3805
FactureFournisseur\fetch
fetch($id='', $ref='')
Load object in memory from database.
Definition: fournisseur.facture.class.php:863
SupplierInvoiceLine\fetch
fetch($rowid)
Retrieves a supplier invoice line.
Definition: fournisseur.facture.class.php:3483
FactureFournisseur\replaceThirdparty
static replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
Definition: fournisseur.facture.class.php:3166
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1226
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:338
FactureFournisseur\$note
$note
Definition: fournisseur.facture.class.php:216
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:1383
FactureFournisseur\info
info($id)
Loads the info order information into the invoice object.
Definition: fournisseur.facture.class.php:2496
DoliDB
Class to manage Dolibarr database access.
Definition: DoliDB.class.php:30
ProductFournisseur
Class to manage predefined suppliers products.
Definition: fournisseur.product.class.php:41
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:484
CommonObject\updateRangOfLine
updateRangOfLine($rowid, $rang)
Update position of line (rang)
Definition: commonobject.class.php:3219
FactureFournisseur
Class to manage suppliers invoices.
Definition: fournisseur.facture.class.php:53
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:4844
FactureFournisseur\hasDelay
hasDelay()
Is the payment of the supplier invoice having a delay?
Definition: fournisseur.facture.class.php:3197
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:1062
SupplierInvoiceLine\update
update($notrigger=0)
Update a supplier invoice line.
Definition: fournisseur.facture.class.php:3616
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:2285
MultiCurrency\getIdFromCode
static getIdFromCode($dbs, $code)
Get id of currency from code.
Definition: multicurrency.class.php:501
FactureFournisseur\deleteline
deleteline($rowid, $notrigger=0)
Delete a detail line from database.
Definition: fournisseur.facture.class.php:2442
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:4228
ref
$object ref
Definition: info.php:77
FactureFournisseur\create
create($user)
Create supplier invoice into database.
Definition: fournisseur.facture.class.php:394
FactureFournisseur\validate
validate($user, $force_number='', $idwarehouse=0, $notrigger=0)
Tag invoice as validated + call trigger BILL_VALIDATE.
Definition: fournisseur.facture.class.php:1765
FactureFournisseur\STATUS_VALIDATED
const STATUS_VALIDATED
Validated (need to be paid)
Definition: fournisseur.facture.class.php:353
CommonObject\commonReplaceProduct
static commonReplaceProduct(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a product id with another one.
Definition: commonobject.class.php:8376
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
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)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:60
FactureFournisseur\initAsSpecimen
initAsSpecimen($option='')
Initialise an instance with random values.
Definition: fournisseur.facture.class.php:2904
SupplierInvoiceLine\$ref
$ref
Definition: fournisseur.facture.class.php:3257
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:383
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:194
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5661
SupplierInvoiceLine
Class to manage line invoices.
Definition: fournisseur.facture.class.php:3239
FactureFournisseur\load_board
load_board($user)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: fournisseur.facture.class.php:2644
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:2514
WorkboardResponse
Definition: workboardresponse.class.php:25
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:1736
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:7248
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:3880
FactureFournisseur\isCreditNoteUsed
isCreditNoteUsed()
Is credit note used.
Definition: fournisseur.facture.class.php:3217
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:2853
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:5406
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:1231
SupplierInvoiceLine\__construct
__construct($db)
Constructor.
Definition: fournisseur.facture.class.php:3472
FactureFournisseur\setPaid
setPaid($user, $close_code='', $close_note='')
Tag invoice as a paid invoice.
Definition: fournisseur.facture.class.php:1584
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:3525
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:6549
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:3183
getEntity
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Definition: functions.lib.php:148
SupplierInvoiceLine\insert
insert($notrigger=0)
Insert line into database.
Definition: fournisseur.facture.class.php:3751
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:6156
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:617
getCommonSubstitutionArray
getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $object=null)
Return array of possible common substitutions.
Definition: functions.lib.php:7275
FactureFournisseur\setDraft
setDraft($user, $idwarehouse=-1)
Set draft status.
Definition: fournisseur.facture.class.php:1920
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:6694
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:1323
CommonObject\deleteEcmFiles
deleteEcmFiles($mode=0)
Delete related files of object in database.
Definition: commonobject.class.php:9966
CommonObject\commonReplaceThirdparty
static commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
Definition: commonobject.class.php:8347
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1603
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:2023
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:2593
MultiCurrency\getIdAndTxFromCode
static getIdAndTxFromCode($dbs, $code, $date_document='')
Get id and rate of currency from code.
Definition: multicurrency.class.php:526
CommonObject\line_max
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
Definition: commonobject.class.php:3373
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:6007
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:1647
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3747
FactureFournisseur\$fournisseur
$fournisseur
Definition: fournisseur.facture.class.php:251
FactureFournisseur\$table_ref_field
$table_ref_field
{}
Definition: fournisseur.facture.class.php:95
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:121
User
Class to manage Dolibarr users.
Definition: user.class.php:44
FactureFournisseur\set_paid
set_paid($user, $close_code='', $close_note='')
Tag invoice as a paid invoice.
Definition: fournisseur.facture.class.php:1569
FactureFournisseur\STATUS_DRAFT
const STATUS_DRAFT
Draft.
Definition: fournisseur.facture.class.php:348
FactureFournisseur\STATUS_CLOSED
const STATUS_CLOSED
Classified paid.
Definition: fournisseur.facture.class.php:362
CommonInvoice
Superclass for invoices classes.
Definition: commoninvoice.class.php:32
FactureFournisseur\TYPE_DEPOSIT
const TYPE_DEPOSIT
Deposit invoice.
Definition: fournisseur.facture.class.php:343
CommonObject\deleteExtraFields
deleteExtraFields()
Delete all extra fields values for the current object.
Definition: commonobject.class.php:6116
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:3818
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:1708
FactureFournisseur\getRights
getRights()
Returns the rights used for this class.
Definition: fournisseur.facture.class.php:3151
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:1662
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:4211
FactureFournisseur\TYPE_STANDARD
const TYPE_STANDARD
Standard invoice.
Definition: fournisseur.facture.class.php:328
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2845
$resql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice') && $user->rights->supplier_invoice->lire)) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
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:5541
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5791
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:3043
FactureFournisseur\STATUS_ABANDONED
const STATUS_ABANDONED
Classified abandoned and no payment done.
Definition: fournisseur.facture.class.php:371
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:2713
FactureFournisseur\load_state_board
load_state_board()
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: fournisseur.facture.class.php:3002
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:624
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:3122
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:3055
type
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:119
SupplierInvoiceLine\update_total
update_total()
Mise a jour de l'objet ligne de commande en base.
Definition: fournisseur.facture.class.php:3964
FactureFournisseur\$amount
$amount
Definition: fournisseur.facture.class.php:189
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:7961
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:2543
if
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Definition: journals_list.php:25
FactureFournisseur\TYPE_REPLACEMENT
const TYPE_REPLACEMENT
Replacement invoice.
Definition: fournisseur.facture.class.php:333