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  return -3;
1123  }
1124  }
1125 
1126 
1134  public function update($user = null, $notrigger = 0)
1135  {
1136  global $conf, $langs;
1137  $error = 0;
1138 
1139  // Clean parameters
1140  if (empty($this->type)) {
1141  $this->type = self::TYPE_STANDARD;
1142  }
1143  if (isset($this->ref)) {
1144  $this->ref = trim($this->ref);
1145  }
1146  if (isset($this->ref_supplier)) {
1147  $this->ref_supplier = trim($this->ref_supplier);
1148  }
1149  if (isset($this->ref_ext)) {
1150  $this->ref_ext = trim($this->ref_ext);
1151  }
1152  if (isset($this->entity)) {
1153  $this->entity = trim($this->entity);
1154  }
1155  if (isset($this->type)) {
1156  $this->type = trim($this->type);
1157  }
1158  if (isset($this->fk_soc)) {
1159  $this->fk_soc = trim($this->fk_soc);
1160  }
1161  if (isset($this->label)) {
1162  $this->label = trim($this->label);
1163  }
1164  if (isset($this->libelle)) {
1165  $this->libelle = trim($this->libelle); // deprecated
1166  }
1167  if (isset($this->paye)) {
1168  $this->paye = trim($this->paye);
1169  }
1170  if (isset($this->close_code)) {
1171  $this->close_code = trim($this->close_code);
1172  }
1173  if (isset($this->close_note)) {
1174  $this->close_note = trim($this->close_note);
1175  }
1176  if (isset($this->localtax1)) {
1177  $this->localtax1 = trim($this->localtax1);
1178  }
1179  if (isset($this->localtax2)) {
1180  $this->localtax2 = trim($this->localtax2);
1181  }
1182  if (empty($this->total_ht)) {
1183  $this->total_ht = 0;
1184  }
1185  if (empty($this->total_tva)) {
1186  $this->total_tva = 0;
1187  }
1188  // if (isset($this->total_localtax1)) $this->total_localtax1=trim($this->total_localtax1);
1189  // if (isset($this->total_localtax2)) $this->total_localtax2=trim($this->total_localtax2);
1190  if (isset($this->total_ttc)) {
1191  $this->total_ttc = trim($this->total_ttc);
1192  }
1193  if (isset($this->statut)) {
1194  $this->statut = (int) $this->statut;
1195  }
1196  if (isset($this->status)) {
1197  $this->status = (int) $this->status;
1198  }
1199  if (isset($this->author)) {
1200  $this->author = trim($this->author);
1201  }
1202  if (isset($this->fk_user_valid)) {
1203  $this->fk_user_valid = trim($this->fk_user_valid);
1204  }
1205  if (isset($this->fk_facture_source)) {
1206  $this->fk_facture_source = trim($this->fk_facture_source);
1207  }
1208  if (isset($this->fk_project)) {
1209  if (empty($this->fk_project)) $this->fk_project = null;
1210  else $this->fk_project = intval($this->fk_project);
1211  }
1212  if (isset($this->cond_reglement_id)) {
1213  $this->cond_reglement_id = trim($this->cond_reglement_id);
1214  }
1215  if (isset($this->note_private)) {
1216  $this->note = trim($this->note_private);
1217  }
1218  if (isset($this->note_public)) {
1219  $this->note_public = trim($this->note_public);
1220  }
1221  if (isset($this->model_pdf)) {
1222  $this->model_pdf = trim($this->model_pdf);
1223  }
1224  if (isset($this->import_key)) {
1225  $this->import_key = trim($this->import_key);
1226  }
1227 
1228 
1229  // Check parameters
1230  // Put here code to add control on parameters values
1231 
1232  // Update request
1233  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn SET";
1234  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
1235  $sql .= " ref_supplier=".(isset($this->ref_supplier) ? "'".$this->db->escape($this->ref_supplier)."'" : "null").",";
1236  $sql .= " ref_ext=".(isset($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : "null").",";
1237  $sql .= " entity=".(isset($this->entity) ? $this->entity : "null").",";
1238  $sql .= " type=".(isset($this->type) ? $this->type : "null").",";
1239  $sql .= " fk_soc=".(isset($this->fk_soc) ? $this->fk_soc : "null").",";
1240  $sql .= " datec=".(dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
1241  $sql .= " datef=".(dol_strlen($this->date) != 0 ? "'".$this->db->idate($this->date)."'" : 'null').",";
1242  if (dol_strlen($this->tms) != 0) {
1243  $sql .= " tms=".(dol_strlen($this->tms) != 0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
1244  }
1245  $sql .= " libelle=".(isset($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
1246  $sql .= " paye=".(isset($this->paye) ? $this->paye : "null").",";
1247  $sql .= " close_code=".(isset($this->close_code) ? "'".$this->db->escape($this->close_code)."'" : "null").",";
1248  $sql .= " close_note=".(isset($this->close_note) ? "'".$this->db->escape($this->close_note)."'" : "null").",";
1249  //$sql .= " tva=".(isset($this->tva) ? $this->tva : "null").",";
1250  $sql .= " localtax1=".(isset($this->localtax1) ? $this->localtax1 : "null").",";
1251  $sql .= " localtax2=".(isset($this->localtax2) ? $this->localtax2 : "null").",";
1252  $sql .= " total_ht=".(isset($this->total_ht) ? $this->total_ht : "null").",";
1253  $sql .= " total_tva=".(isset($this->total_tva) ? $this->total_tva : "null").",";
1254  $sql .= " total_ttc=".(isset($this->total_ttc) ? $this->total_ttc : "null").",";
1255  $sql .= " fk_statut=".(isset($this->status) ? $this->status : (isset($this->statut) ? $this->statut : "null")).",";
1256  $sql .= " fk_user_author=".(isset($this->author) ? $this->author : "null").",";
1257  $sql .= " fk_user_valid=".(isset($this->fk_user_valid) ? $this->fk_user_valid : "null").",";
1258  $sql .= " fk_facture_source=".(isset($this->fk_facture_source) ? $this->fk_facture_source : "null").",";
1259  $sql .= " fk_projet=".(isset($this->fk_project) ? $this->fk_project : "null").",";
1260  $sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? $this->cond_reglement_id : "null").",";
1261  $sql .= " date_lim_reglement=".(dol_strlen($this->date_echeance) != 0 ? "'".$this->db->idate($this->date_echeance)."'" : 'null').",";
1262  $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
1263  $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
1264  $sql .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
1265  $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null")."";
1266  $sql .= " WHERE rowid=".((int) $this->id);
1267 
1268  $this->db->begin();
1269 
1270  dol_syslog(get_class($this)."::update", LOG_DEBUG);
1271  $resql = $this->db->query($sql);
1272 
1273  if (!$resql) {
1274  $error++;
1275 
1276  if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1277  $this->errors[] = $langs->trans('ErrorRefAlreadyExists');
1278  } else {
1279  $this->errors[] = "Error ".$this->db->lasterror();
1280  }
1281  }
1282 
1283  if (!$error) {
1284  $result = $this->insertExtraFields();
1285  if ($result < 0) {
1286  $error++;
1287  }
1288  }
1289 
1290  if (!$error) {
1291  if (!$notrigger) {
1292  // Call trigger
1293  $result = $this->call_trigger('BILL_SUPPLIER_MODIFY', $user);
1294  if ($result < 0) {
1295  $error++;
1296  }
1297  // End call triggers
1298  }
1299  }
1300 
1301  // Commit or rollback
1302  if ($error) {
1303  foreach ($this->errors as $errmsg) {
1304  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
1305  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1306  }
1307  $this->db->rollback();
1308  return -1 * $error;
1309  } else {
1310  $this->db->commit();
1311  return 1;
1312  }
1313  }
1314 
1315  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1322  public function insert_discount($idremise)
1323  {
1324  // phpcs:enable
1325  global $conf, $langs;
1326 
1327  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1328  include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
1329 
1330  $this->db->begin();
1331 
1332  $remise = new DiscountAbsolute($this->db);
1333  $result = $remise->fetch($idremise);
1334 
1335  if ($result > 0) {
1336  if ($remise->fk_invoice_supplier) { // Protection against multiple submission
1337  $this->error = $langs->trans("ErrorDiscountAlreadyUsed");
1338  $this->db->rollback();
1339  return -5;
1340  }
1341 
1342  $facligne = new SupplierInvoiceLine($this->db);
1343  $facligne->fk_facture_fourn = $this->id;
1344  $facligne->fk_remise_except = $remise->id;
1345  $facligne->desc = $remise->description; // Description ligne
1346  $facligne->vat_src_code = $remise->vat_src_code;
1347  $facligne->tva_tx = $remise->tva_tx;
1348  $facligne->subprice = -$remise->amount_ht;
1349  $facligne->fk_product = 0; // Id produit predefini
1350  $facligne->product_type = 0;
1351  $facligne->qty = 1;
1352  $facligne->remise_percent = 0;
1353  $facligne->rang = -1;
1354  $facligne->info_bits = 2;
1355 
1356  if (!empty($conf->global->MAIN_ADD_LINE_AT_POSITION)) {
1357  $facligne->rang = 1;
1358  $linecount = count($this->lines);
1359  for ($ii = 1; $ii <= $linecount; $ii++) {
1360  $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii+1);
1361  }
1362  }
1363 
1364  // Get buy/cost price of invoice that is source of discount
1365  if ($remise->fk_invoice_supplier_source > 0) {
1366  $srcinvoice = new FactureFournisseur($this->db);
1367  $srcinvoice->fetch($remise->fk_invoice_supplier_source);
1368  $totalcostpriceofinvoice = 0;
1369  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php'; // TODO Move this into commonobject
1370  $formmargin = new FormMargin($this->db);
1371  $arraytmp = $formmargin->getMarginInfosArray($srcinvoice, false);
1372  $facligne->pa_ht = $arraytmp['pa_total'];
1373  }
1374 
1375  $facligne->total_ht = -$remise->amount_ht;
1376  $facligne->total_tva = -$remise->amount_tva;
1377  $facligne->total_ttc = -$remise->amount_ttc;
1378 
1379  $facligne->multicurrency_subprice = -$remise->multicurrency_subprice;
1380  $facligne->multicurrency_total_ht = -$remise->multicurrency_total_ht;
1381  $facligne->multicurrency_total_tva = -$remise->multicurrency_total_tva;
1382  $facligne->multicurrency_total_ttc = -$remise->multicurrency_total_ttc;
1383 
1384  $lineid = $facligne->insert();
1385  if ($lineid > 0) {
1386  $result = $this->update_price(1);
1387  if ($result > 0) {
1388  // Create link between discount and invoice line
1389  $result = $remise->link_to_invoice($lineid, 0, 'supplier');
1390  if ($result < 0) {
1391  $this->error = $remise->error;
1392  $this->db->rollback();
1393  return -4;
1394  }
1395 
1396  $this->db->commit();
1397  return 1;
1398  } else {
1399  $this->error = $facligne->error;
1400  $this->db->rollback();
1401  return -1;
1402  }
1403  } else {
1404  $this->error = $facligne->error;
1405  $this->db->rollback();
1406  return -2;
1407  }
1408  } else {
1409  $this->db->rollback();
1410  return -3;
1411  }
1412  }
1413 
1414 
1422  public function delete(User $user, $notrigger = 0)
1423  {
1424  global $langs, $conf;
1425 
1426  $rowid = $this->id;
1427 
1428  dol_syslog("FactureFournisseur::delete rowid=".$rowid, LOG_DEBUG);
1429 
1430  // TODO Test if there is at least on payment. If yes, refuse to delete.
1431 
1432  $error = 0;
1433  $this->db->begin();
1434 
1435  if (!$error && !$notrigger) {
1436  // Call trigger
1437  $result = $this->call_trigger('BILL_SUPPLIER_DELETE', $user);
1438  if ($result < 0) {
1439  $this->db->rollback();
1440  return -1;
1441  }
1442  // Fin appel triggers
1443  }
1444 
1445  if (!$error) {
1446  // If invoice was converted into a discount not yet consumed, we remove discount
1447  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'societe_remise_except';
1448  $sql .= ' WHERE fk_invoice_supplier_source = '.((int) $rowid);
1449  $sql .= ' AND fk_invoice_supplier_line IS NULL';
1450  $resql = $this->db->query($sql);
1451 
1452  // If invoice has consumned discounts
1453  $this->fetch_lines();
1454  $list_rowid_det = array();
1455  foreach ($this->lines as $key => $invoiceline) {
1456  $list_rowid_det[] = $invoiceline->rowid;
1457  }
1458 
1459  // Consumned discounts are freed
1460  if (count($list_rowid_det)) {
1461  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
1462  $sql .= ' SET fk_invoice_supplier = NULL, fk_invoice_supplier_line = NULL';
1463  $sql .= ' WHERE fk_invoice_supplier_line IN ('.$this->db->sanitize(join(',', $list_rowid_det)).')';
1464 
1465  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1466  if (!$this->db->query($sql)) {
1467  $error++;
1468  }
1469  }
1470  }
1471 
1472  if (!$error) {
1473  $main = MAIN_DB_PREFIX.'facture_fourn_det';
1474  $ef = $main."_extrafields";
1475  $sqlef = "DELETE FROM $ef WHERE fk_object IN (SELECT rowid FROM ".$main." WHERE fk_facture_fourn = ".((int) $rowid).")";
1476  $resqlef = $this->db->query($sqlef);
1477  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det WHERE fk_facture_fourn = '.((int) $rowid);
1478  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1479  $resql = $this->db->query($sql);
1480  if ($resqlef && $resql) {
1481  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn WHERE rowid = '.((int) $rowid);
1482  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1483  $resql2 = $this->db->query($sql);
1484  if (!$resql2) {
1485  $error++;
1486  }
1487  } else {
1488  $error++;
1489  }
1490  }
1491 
1492  if (!$error) {
1493  // Delete linked object
1494  $res = $this->deleteObjectLinked();
1495  if ($res < 0) {
1496  $error++;
1497  }
1498  }
1499 
1500  if (!$error) {
1501  // Delete linked object
1502  $res = $this->deleteObjectLinked();
1503  if ($res < 0) {
1504  $error++;
1505  }
1506  }
1507 
1508  if (!$error) {
1509  // Delete record into ECM index (Note that delete is also done when deleting files with the dol_delete_dir_recursive
1510  $this->deleteEcmFiles();
1511 
1512  // We remove directory
1513  if ($conf->fournisseur->facture->dir_output) {
1514  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1515 
1516  $ref = dol_sanitizeFileName($this->ref);
1517  $dir = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$ref;
1518  $file = $dir."/".$ref.".pdf";
1519  if (file_exists($file)) {
1520  if (!dol_delete_file($file, 0, 0, 0, $this)) { // For triggers
1521  $this->error = 'ErrorFailToDeleteFile';
1522  $error++;
1523  }
1524  }
1525  if (file_exists($dir)) {
1526  $res = @dol_delete_dir_recursive($dir);
1527 
1528  if (!$res) {
1529  $this->error = 'ErrorFailToDeleteDir';
1530  $error++;
1531  }
1532  }
1533  }
1534  }
1535 
1536  // Remove extrafields
1537  if (!$error) {
1538  $result = $this->deleteExtraFields();
1539  if ($result < 0) {
1540  $error++;
1541  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1542  }
1543  }
1544 
1545  if (!$error) {
1546  dol_syslog(get_class($this)."::delete $this->id by $user->id", LOG_DEBUG);
1547  $this->db->commit();
1548  return 1;
1549  } else {
1550  $this->error = $this->db->lasterror();
1551  $this->db->rollback();
1552  return -$error;
1553  }
1554  }
1555 
1556 
1557  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1568  public function set_paid($user, $close_code = '', $close_note = '')
1569  {
1570  // phpcs:enable
1571  dol_syslog(get_class($this)."::set_paid is deprecated, use setPaid instead", LOG_NOTICE);
1572  return $this->setPaid($user, $close_code, $close_note);
1573  }
1574 
1583  public function setPaid($user, $close_code = '', $close_note = '')
1584  {
1585  $error = 0;
1586 
1587  if ($this->paye != 1) {
1588  $this->db->begin();
1589 
1590  $now = dol_now();
1591 
1592  dol_syslog("FactureFournisseur::set_paid", LOG_DEBUG);
1593 
1594  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn SET';
1595  $sql .= ' fk_statut = '.self::STATUS_CLOSED;
1596  if (!$close_code) {
1597  $sql .= ', paye=1';
1598  }
1599  if ($close_code) {
1600  $sql .= ", close_code='".$this->db->escape($close_code)."'";
1601  }
1602  if ($close_note) {
1603  $sql .= ", close_note='".$this->db->escape($close_note)."'";
1604  }
1605  $sql .= ', fk_user_closing = '.((int) $user->id);
1606  $sql .= ", date_closing = '".$this->db->idate($now)."'";
1607  $sql .= ' WHERE rowid = '.((int) $this->id);
1608 
1609  $resql = $this->db->query($sql);
1610  if ($resql) {
1611  // Call trigger
1612  $result = $this->call_trigger('BILL_SUPPLIER_PAYED', $user);
1613  if ($result < 0) {
1614  $error++;
1615  }
1616  // End call triggers
1617  } else {
1618  $error++;
1619  $this->error = $this->db->error();
1620  dol_print_error($this->db);
1621  }
1622 
1623  if (!$error) {
1624  $this->db->commit();
1625  return 1;
1626  } else {
1627  $this->db->rollback();
1628  return -1;
1629  }
1630  } else {
1631  return 0;
1632  }
1633  }
1634 
1635  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1646  public function set_unpaid($user)
1647  {
1648  // phpcs:enable
1649  dol_syslog(get_class($this)."::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE);
1650  return $this->setUnpaid($user);
1651  }
1652 
1661  public function setUnpaid($user)
1662  {
1663  $error = 0;
1664 
1665  $this->db->begin();
1666 
1667  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn';
1668  $sql .= ' SET paye=0, fk_statut='.self::STATUS_VALIDATED.', close_code=null, close_note=null,';
1669  $sql .= ' date_closing=null,';
1670  $sql .= ' fk_user_closing=null';
1671  $sql .= ' WHERE rowid = '.((int) $this->id);
1672 
1673  dol_syslog(get_class($this)."::set_unpaid", LOG_DEBUG);
1674  $resql = $this->db->query($sql);
1675  if ($resql) {
1676  // Call trigger
1677  $result = $this->call_trigger('BILL_SUPPLIER_UNPAYED', $user);
1678  if ($result < 0) {
1679  $error++;
1680  }
1681  // End call triggers
1682  } else {
1683  $error++;
1684  $this->error = $this->db->error();
1685  dol_print_error($this->db);
1686  }
1687 
1688  if (!$error) {
1689  $this->db->commit();
1690  return 1;
1691  } else {
1692  $this->db->rollback();
1693  return -1;
1694  }
1695  }
1696 
1707  public function setCanceled($user, $close_code = '', $close_note = '')
1708  {
1709  dol_syslog(get_class($this)."::setCanceled rowid=".((int) $this->id), LOG_DEBUG);
1710 
1711  $this->db->begin();
1712 
1713  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn SET';
1714  $sql .= ' fk_statut='.self::STATUS_ABANDONED;
1715  if ($close_code) {
1716  $sql .= ", close_code='".$this->db->escape($close_code)."'";
1717  }
1718  if ($close_note) {
1719  $sql .= ", close_note='".$this->db->escape($close_note)."'";
1720  }
1721  $sql .= " WHERE rowid = ".((int) $this->id);
1722 
1723  $resql = $this->db->query($sql);
1724  if ($resql) {
1725  // Bound discounts are deducted from the invoice
1726  // as they have not been used since the invoice is abandoned.
1727  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
1728  $sql .= ' SET fk_invoice_supplier = NULL';
1729  $sql .= ' WHERE fk_invoice_supplier = '.((int) $this->id);
1730 
1731  $resql = $this->db->query($sql);
1732  if ($resql) {
1733  // Call trigger
1734  $result = $this->call_trigger('BILL_SUPPLIER_CANCEL', $user);
1735  if ($result < 0) {
1736  $this->db->rollback();
1737  return -1;
1738  }
1739  // End call triggers
1740 
1741  $this->db->commit();
1742  return 1;
1743  } else {
1744  $this->error = $this->db->error()." sql=".$sql;
1745  $this->db->rollback();
1746  return -1;
1747  }
1748  } else {
1749  $this->error = $this->db->error()." sql=".$sql;
1750  $this->db->rollback();
1751  return -2;
1752  }
1753  }
1754 
1764  public function validate($user, $force_number = '', $idwarehouse = 0, $notrigger = 0)
1765  {
1766  global $conf, $langs;
1767 
1768  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1769 
1770  $now = dol_now();
1771 
1772  $error = 0;
1773  dol_syslog(get_class($this).'::validate user='.$user->id.', force_number='.$force_number.', idwarehouse='.$idwarehouse);
1774 
1775  // Force to have object complete for checks
1776  $this->fetch_thirdparty();
1777  $this->fetch_lines();
1778 
1779  // Check parameters
1780  if ($this->statut > self::STATUS_DRAFT) { // This is to avoid to validate twice (avoid errors on logs and stock management)
1781  dol_syslog(get_class($this)."::validate no draft status", LOG_WARNING);
1782  return 0;
1783  }
1784  if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ').'/', $this->ref_supplier)) {
1785  $langs->load("errors");
1786  $this->error = $langs->trans("ErrorFieldFormat", $langs->transnoentities("RefSupplier")).'. '.$langs->trans('RemoveString', $langs->transnoentitiesnoconv("CopyOf"));
1787  return -1;
1788  }
1789  if (count($this->lines) <= 0) {
1790  $langs->load("errors");
1791  $this->error = $langs->trans("ErrorObjectMustHaveLinesToBeValidated", $this->ref);
1792  return -1;
1793  }
1794 
1795  $this->db->begin();
1796 
1797  // Define new ref
1798  if ($force_number) {
1799  $num = $force_number;
1800  } elseif (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
1801  $num = $this->getNextNumRef($this->thirdparty);
1802  } else {
1803  $num = $this->ref;
1804  }
1805  $this->newref = dol_sanitizeFileName($num);
1806 
1807  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1808  $sql .= " SET ref='".$this->db->escape($num)."', fk_statut = 1, fk_user_valid = ".((int) $user->id).", date_valid = '".$this->db->idate($now)."'";
1809  $sql .= " WHERE rowid = ".((int) $this->id);
1810 
1811  dol_syslog(get_class($this)."::validate", LOG_DEBUG);
1812  $resql = $this->db->query($sql);
1813  if ($resql) {
1814  // Si on incrémente le produit principal et ses composants à la validation de facture fournisseur
1815  if (!$error && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) {
1816  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1817  $langs->load("agenda");
1818 
1819  $cpt = count($this->lines);
1820  for ($i = 0; $i < $cpt; $i++) {
1821  if ($this->lines[$i]->fk_product > 0) {
1822  $this->line = $this->lines[$i];
1823  $mouvP = new MouvementStock($this->db);
1824  $mouvP->origin = &$this;
1825  $mouvP->setOrigin($this->element, $this->id);
1826  // We increase stock for product
1827  $up_ht_disc = $this->lines[$i]->pu_ht;
1828  if (!empty($this->lines[$i]->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) {
1829  $up_ht_disc = price2num($up_ht_disc * (100 - $this->lines[$i]->remise_percent) / 100, 'MU');
1830  }
1832  $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1833  } else {
1834  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1835  }
1836  if ($result < 0) {
1837  $error++;
1838  }
1839  unset($this->line);
1840  }
1841  }
1842  }
1843 
1844  // Triggers call
1845  if (!$error && empty($notrigger)) {
1846  // Call trigger
1847  $result = $this->call_trigger('BILL_SUPPLIER_VALIDATE', $user);
1848  if ($result < 0) {
1849  $error++;
1850  }
1851  // End call triggers
1852  }
1853 
1854  if (!$error) {
1855  $this->oldref = $this->ref;
1856 
1857  // Rename directory if dir was a temporary ref
1858  if (preg_match('/^[\(]?PROV/i', $this->ref)) {
1859  // Now we rename also files into index
1860  $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)."'";
1861  $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;
1862  $resql = $this->db->query($sql);
1863  if (!$resql) {
1864  $error++; $this->error = $this->db->lasterror();
1865  }
1866 
1867  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1868  $oldref = dol_sanitizeFileName($this->ref);
1869  $newref = dol_sanitizeFileName($num);
1870  $dirsource = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$oldref;
1871  $dirdest = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$newref;
1872  if (!$error && file_exists($dirsource)) {
1873  dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest);
1874 
1875  if (@rename($dirsource, $dirdest)) {
1876  dol_syslog("Rename ok");
1877  // Rename docs starting with $oldref with $newref
1878  $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, '/'));
1879  foreach ($listoffiles as $fileentry) {
1880  $dirsource = $fileentry['name'];
1881  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1882  $dirsource = $fileentry['path'].'/'.$dirsource;
1883  $dirdest = $fileentry['path'].'/'.$dirdest;
1884  @rename($dirsource, $dirdest);
1885  }
1886  }
1887  }
1888  }
1889  }
1890 
1891  // Set new ref and define current statut
1892  if (!$error) {
1893  $this->ref = $num;
1894  $this->statut = self::STATUS_VALIDATED;
1895  //$this->date_validation=$now; this is stored into log table
1896  }
1897 
1898  if (!$error) {
1899  $this->db->commit();
1900  return 1;
1901  } else {
1902  $this->db->rollback();
1903  return -1;
1904  }
1905  } else {
1906  $this->error = $this->db->error();
1907  $this->db->rollback();
1908  return -1;
1909  }
1910  }
1911 
1919  public function setDraft($user, $idwarehouse = -1)
1920  {
1921  // phpcs:enable
1922  global $conf, $langs;
1923 
1924  $error = 0;
1925 
1926  if ($this->statut == self::STATUS_DRAFT) {
1927  dol_syslog(__METHOD__." already draft status", LOG_WARNING);
1928  return 0;
1929  }
1930 
1931  dol_syslog(__METHOD__, LOG_DEBUG);
1932 
1933  $this->db->begin();
1934 
1935  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1936  $sql .= " SET fk_statut = ".self::STATUS_DRAFT;
1937  $sql .= " WHERE rowid = ".((int) $this->id);
1938 
1939  $result = $this->db->query($sql);
1940  if ($result) {
1941  if (!$error) {
1942  $this->oldcopy = clone $this;
1943  }
1944 
1945  // Si on incremente le produit principal et ses composants a la validation de facture fournisseur, on decremente
1946  if ($result >= 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) {
1947  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1948  $langs->load("agenda");
1949 
1950  $cpt = count($this->lines);
1951  for ($i = 0; $i < $cpt; $i++) {
1952  if ($this->lines[$i]->fk_product > 0) {
1953  $mouvP = new MouvementStock($this->db);
1954  $mouvP->origin = &$this;
1955  $mouvP->setOrigin($this->element, $this->id);
1956  // We increase stock for product
1958  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
1959  } else {
1960  $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
1961  }
1962  }
1963  }
1964  }
1965  // Triggers call
1966  if (!$error && empty($notrigger)) {
1967  // Call trigger
1968  $result = $this->call_trigger('BILL_SUPPLIER_UNVALIDATE', $user);
1969  if ($result < 0) {
1970  $error++;
1971  }
1972  // End call triggers
1973  }
1974  if ($error == 0) {
1975  $this->db->commit();
1976  return 1;
1977  } else {
1978  $this->db->rollback();
1979  return -1;
1980  }
1981  } else {
1982  $this->error = $this->db->error();
1983  $this->db->rollback();
1984  return -1;
1985  }
1986  }
1987 
1988 
2022  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)
2023  {
2024  global $langs, $mysoc, $conf;
2025 
2026  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);
2027  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2028 
2029  if ($this->statut == self::STATUS_DRAFT) {
2030  // Clean parameters
2031  if (empty($remise_percent)) {
2032  $remise_percent = 0;
2033  }
2034  if (empty($qty)) {
2035  $qty = 0;
2036  }
2037  if (empty($info_bits)) {
2038  $info_bits = 0;
2039  }
2040  if (empty($rang)) {
2041  $rang = 0;
2042  }
2043  if (empty($ventil)) {
2044  $ventil = 0;
2045  }
2046  if (empty($txtva)) {
2047  $txtva = 0;
2048  }
2049  if (empty($txlocaltax1)) {
2050  $txlocaltax1 = 0;
2051  }
2052  if (empty($txlocaltax2)) {
2053  $txlocaltax2 = 0;
2054  }
2055 
2056  $remise_percent = price2num($remise_percent);
2057  $qty = price2num($qty);
2058  $pu = price2num($pu);
2059  if (!preg_match('/\((.*)\)/', $txtva)) {
2060  $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
2061  }
2062  $txlocaltax1 = price2num($txlocaltax1);
2063  $txlocaltax2 = price2num($txlocaltax2);
2064 
2065  if ($date_start && $date_end && $date_start > $date_end) {
2066  $langs->load("errors");
2067  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
2068  return -1;
2069  }
2070 
2071  $this->db->begin();
2072 
2073  if ($fk_product > 0) {
2074  if (!empty($conf->global->SUPPLIER_INVOICE_WITH_PREDEFINED_PRICES_ONLY)) {
2075  // Check quantity is enough
2076  dol_syslog(get_class($this)."::addline we check supplier prices fk_product=".$fk_product." qty=".$qty." ref_supplier=".$ref_supplier);
2077  $prod = new Product($this->db);
2078  if ($prod->fetch($fk_product) > 0) {
2079  $product_type = $prod->type;
2080  $label = $prod->label;
2081  $fk_prod_fourn_price = 0;
2082 
2083  // We use 'none' instead of $ref_supplier, because $ref_supplier may not exists anymore. So we will take the first supplier price ok.
2084  // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
2085  $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
2086  if ($result > 0) {
2087  if (empty($pu)) {
2088  $pu = $prod->fourn_pu; // Unit price supplier price set by get_buyprice
2089  }
2090  $ref_supplier = $prod->ref_supplier; // Ref supplier price set by get_buyprice
2091  // is remise percent not keyed but present for the product we add it
2092  if ($remise_percent == 0 && $prod->remise_percent != 0) {
2093  $remise_percent = $prod->remise_percent;
2094  }
2095  }
2096  if ($result == 0) { // If result == 0, we failed to found the supplier reference price
2097  $langs->load("errors");
2098  $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
2099  $this->db->rollback();
2100  dol_syslog(get_class($this)."::addline we did not found supplier price, so we can't guess unit price");
2101  //$pu = $prod->fourn_pu; // We do not overwrite unit price
2102  //$ref = $prod->ref_fourn; // We do not overwrite ref supplier price
2103  return -1;
2104  }
2105  if ($result == -1) {
2106  $langs->load("errors");
2107  $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
2108  $this->db->rollback();
2109  dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_DEBUG);
2110  return -1;
2111  }
2112  if ($result < -1) {
2113  $this->error = $prod->error;
2114  $this->db->rollback();
2115  dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_ERR);
2116  return -1;
2117  }
2118  } else {
2119  $this->error = $prod->error;
2120  $this->db->rollback();
2121  return -1;
2122  }
2123  }
2124  } else {
2125  $product_type = $type;
2126  }
2127 
2128  if (!empty($conf->multicurrency->enabled) && $pu_devise > 0) {
2129  $pu = 0;
2130  }
2131 
2132  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $mysoc, $this->thirdparty);
2133 
2134  // Clean vat code
2135  $reg = array();
2136  $vat_src_code = '';
2137  if (preg_match('/\((.*)\)/', $txtva, $reg)) {
2138  $vat_src_code = $reg[1];
2139  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
2140  }
2141 
2142  // Calcul du total TTC et de la TVA pour la ligne a partir de
2143  // qty, pu, remise_percent et txtva
2144  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2145  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2146 
2147  $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);
2148  $total_ht = $tabprice[0];
2149  $total_tva = $tabprice[1];
2150  $total_ttc = $tabprice[2];
2151  $total_localtax1 = $tabprice[9];
2152  $total_localtax2 = $tabprice[10];
2153  $pu_ht = $tabprice[3];
2154 
2155  // MultiCurrency
2156  $multicurrency_total_ht = $tabprice[16];
2157  $multicurrency_total_tva = $tabprice[17];
2158  $multicurrency_total_ttc = $tabprice[18];
2159  $pu_ht_devise = $tabprice[19];
2160 
2161  // Check parameters
2162  if ($type < 0) {
2163  return -1;
2164  }
2165 
2166  if ($rang < 0) {
2167  $rangmax = $this->line_max();
2168  $rang = $rangmax + 1;
2169  }
2170 
2171  // Insert line
2172  $this->line = new SupplierInvoiceLine($this->db);
2173 
2174  $this->line->context = $this->context;
2175 
2176  $this->line->fk_facture_fourn = $this->id;
2177  //$this->line->label=$label; // deprecated
2178  $this->line->desc = $desc;
2179  $this->line->ref_supplier = $ref_supplier;
2180 
2181  $this->line->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs($qty) : $qty); // For credit note, quantity is always positive and unit price negative
2182  $this->line->subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2183 
2184  $this->line->vat_src_code = $vat_src_code;
2185  $this->line->tva_tx = $txtva;
2186  $this->line->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
2187  $this->line->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
2188  $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
2189  $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
2190 
2191  $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
2192  $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
2193  $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
2194  $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
2195  $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
2196 
2197  $this->line->fk_product = $fk_product;
2198  $this->line->product_type = $type;
2199  $this->line->remise_percent = $remise_percent;
2200  $this->line->date_start = $date_start;
2201  $this->line->date_end = $date_end;
2202  $this->line->fk_code_ventilation = $ventil;
2203  $this->line->rang = $rang;
2204  $this->line->info_bits = $info_bits;
2205  $this->line->fk_remise_except = $fk_remise_except;
2206 
2207  $this->line->special_code = ((string) $special_code != '' ? $special_code : $this->special_code);
2208  $this->line->fk_parent_line = $fk_parent_line;
2209  $this->line->origin = $this->origin;
2210  $this->line->origin_id = $origin_id;
2211  $this->line->fk_unit = $fk_unit;
2212 
2213  // Multicurrency
2214  $this->line->fk_multicurrency = $this->fk_multicurrency;
2215  $this->line->multicurrency_code = $this->multicurrency_code;
2216  $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
2217 
2218  $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
2219  $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
2220  $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
2221 
2222  if (is_array($array_options) && count($array_options) > 0) {
2223  $this->line->array_options = $array_options;
2224  }
2225 
2226  $result = $this->line->insert($notrigger);
2227  if ($result > 0) {
2228  // Reorder if child line
2229  if (!empty($fk_parent_line)) {
2230  $this->line_order(true, 'DESC');
2231  } elseif ($rang > 0 && $rang <= count($this->lines)) { // Update all rank of all other lines
2232  $linecount = count($this->lines);
2233  for ($ii = $rang; $ii <= $linecount; $ii++) {
2234  $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1);
2235  }
2236  }
2237 
2238  // Mise a jour informations denormalisees au niveau de la facture meme
2239  $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.
2240  if ($result > 0) {
2241  $this->db->commit();
2242  return $this->line->id;
2243  } else {
2244  $this->error = $this->db->error();
2245  $this->db->rollback();
2246  return -1;
2247  }
2248  } else {
2249  $this->error = $this->line->error;
2250  $this->errors = $this->line->errors;
2251  $this->db->rollback();
2252  return -2;
2253  }
2254  } else {
2255  return 0;
2256  }
2257  }
2258 
2284  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)
2285  {
2286  global $mysoc, $langs;
2287 
2288  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);
2289  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2290 
2291  $pu = price2num($pu);
2292  $qty = price2num($qty);
2293  $remise_percent = price2num($remise_percent);
2294  $pu_devise = price2num($pu_devise);
2295 
2296  // Check parameters
2297  //if (! is_numeric($pu) || ! is_numeric($qty)) return -1;
2298  if ($type < 0) {
2299  return -1;
2300  }
2301 
2302  if ($date_start && $date_end && $date_start > $date_end) {
2303  $langs->load("errors");
2304  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
2305  return -1;
2306  }
2307 
2308  // Clean parameters
2309  if (empty($vatrate)) {
2310  $vatrate = 0;
2311  }
2312  if (empty($txlocaltax1)) {
2313  $txlocaltax1 = 0;
2314  }
2315  if (empty($txlocaltax2)) {
2316  $txlocaltax2 = 0;
2317  }
2318 
2319  $txlocaltax1 = price2num($txlocaltax1);
2320  $txlocaltax2 = price2num($txlocaltax2);
2321 
2322  // Calcul du total TTC et de la TVA pour la ligne a partir de
2323  // qty, pu, remise_percent et txtva
2324  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2325  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2326 
2327  $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $mysoc, $this->thirdparty);
2328 
2329  $reg = array();
2330 
2331  // Clean vat code
2332  $vat_src_code = '';
2333  if (preg_match('/\((.*)\)/', $vatrate, $reg)) {
2334  $vat_src_code = $reg[1];
2335  $vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate.
2336  }
2337 
2338  $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);
2339  $total_ht = $tabprice[0];
2340  $total_tva = $tabprice[1];
2341  $total_ttc = $tabprice[2];
2342  $pu_ht = $tabprice[3];
2343  $pu_tva = $tabprice[4];
2344  $pu_ttc = $tabprice[5];
2345  $total_localtax1 = $tabprice[9];
2346  $total_localtax2 = $tabprice[10];
2347 
2348  // MultiCurrency
2349  $multicurrency_total_ht = $tabprice[16];
2350  $multicurrency_total_tva = $tabprice[17];
2351  $multicurrency_total_ttc = $tabprice[18];
2352  $pu_ht_devise = $tabprice[19];
2353 
2354  if (empty($info_bits)) {
2355  $info_bits = 0;
2356  }
2357 
2358  //Fetch current line from the database and then clone the object and set it in $oldline property
2359  $line = new SupplierInvoiceLine($this->db);
2360  $line->fetch($id);
2361  $line->fetch_optionals();
2362 
2363  $staticline = clone $line;
2364 
2365  if ($idproduct) {
2366  $product = new Product($this->db);
2367  $result = $product->fetch($idproduct);
2368  $product_type = $product->type;
2369  } else {
2370  $idproduct = $staticline->fk_product;
2371  $product_type = $type;
2372  }
2373 
2374  $line->oldline = $staticline;
2375  $line->context = $this->context;
2376 
2377  $line->description = $desc;
2378 
2379  $line->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs($qty) : $qty); // For credit note, quantity is always positive and unit price negative
2380  $line->subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2381  $line->pu_ht = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2382  $line->pu_ttc = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ttc) : $pu_ttc); // For credit note, unit price always negative, always positive otherwise
2383 
2384  $line->remise_percent = $remise_percent;
2385  $line->ref_supplier = $ref_supplier;
2386 
2387  $line->date_start = $date_start;
2388  $line->date_end = $date_end;
2389 
2390  $line->vat_src_code = $vat_src_code;
2391  $line->tva_tx = $vatrate;
2392  $line->localtax1_tx = $txlocaltax1;
2393  $line->localtax2_tx = $txlocaltax2;
2394  $line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
2395  $line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
2396 
2397  $line->total_ht = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_ht) : $total_ht);
2398  $line->total_tva = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_tva) : $total_tva);
2399  $line->total_localtax1 = $total_localtax1;
2400  $line->total_localtax2 = $total_localtax2;
2401  $line->total_ttc = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ?-abs($total_ttc) : $total_ttc);
2402 
2403  $line->fk_product = $idproduct;
2404  $line->product_type = $product_type;
2405  $line->info_bits = $info_bits;
2406  $line->fk_unit = $fk_unit;
2407  $line->rang = $rang;
2408 
2409  if (is_array($array_options) && count($array_options) > 0) {
2410  // We replace values in this->line->array_options only for entries defined into $array_options
2411  foreach ($array_options as $key => $value) {
2412  $line->array_options[$key] = $array_options[$key];
2413  }
2414  }
2415 
2416  // Multicurrency
2417  $line->multicurrency_subprice = $pu_ht_devise;
2418  $line->multicurrency_total_ht = $multicurrency_total_ht;
2419  $line->multicurrency_total_tva = $multicurrency_total_tva;
2420  $line->multicurrency_total_ttc = $multicurrency_total_ttc;
2421 
2422  $res = $line->update($notrigger);
2423 
2424  if ($res < 1) {
2425  $this->errors[] = $line->error;
2426  } else {
2427  // Update total price into invoice record
2428  $res = $this->update_price('', 'auto', 0, $this->thirdparty);
2429  }
2430 
2431  return $res;
2432  }
2433 
2441  public function deleteline($rowid, $notrigger = 0)
2442  {
2443  if (!$rowid) {
2444  $rowid = $this->id;
2445  }
2446 
2447  $this->db->begin();
2448 
2449  // Free the discount linked to a line of invoice
2450  $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
2451  $sql .= ' SET fk_invoice_supplier_line = NULL';
2452  $sql .= ' WHERE fk_invoice_supplier_line = '.((int) $rowid);
2453 
2454  dol_syslog(get_class($this)."::deleteline", LOG_DEBUG);
2455  $result = $this->db->query($sql);
2456  if (!$result) {
2457  $this->error = $this->db->error();
2458  $this->db->rollback();
2459  return -2;
2460  }
2461 
2462  $line = new SupplierInvoiceLine($this->db);
2463 
2464  if ($line->fetch($rowid) < 1) {
2465  return -1;
2466  }
2467 
2468  $res = $line->delete($notrigger);
2469 
2470  if ($res < 1) {
2471  $this->errors[] = $line->error;
2472  $this->db->rollback();
2473  return -3;
2474  } else {
2475  $res = $this->update_price();
2476 
2477  if ($res > 0) {
2478  $this->db->commit();
2479  return 1;
2480  } else {
2481  $this->db->rollback();
2482  $this->error = $this->db->lasterror();
2483  return -4;
2484  }
2485  }
2486  }
2487 
2488 
2495  public function info($id)
2496  {
2497  $sql = 'SELECT c.rowid, datec, tms as datem, ';
2498  $sql .= ' fk_user_author, fk_user_modif, fk_user_valid';
2499  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as c';
2500  $sql .= ' WHERE c.rowid = '.((int) $id);
2501 
2502  $result = $this->db->query($sql);
2503  if ($result) {
2504  if ($this->db->num_rows($result)) {
2505  $obj = $this->db->fetch_object($result);
2506 
2507  $this->id = $obj->rowid;
2508  if ($obj->fk_user_author) {
2509  $cuser = new User($this->db);
2510  $cuser->fetch($obj->fk_user_author);
2511  $this->user_creation = $cuser;
2512  }
2513  if ($obj->fk_user_valid) {
2514  $vuser = new User($this->db);
2515  $vuser->fetch($obj->fk_user_valid);
2516  $this->user_validation = $vuser;
2517  }
2518  if ($obj->fk_user_modif) {
2519  $muser = new User($this->db);
2520  $muser->fetch($obj->fk_user_modif);
2521  $this->user_modification = $muser;
2522  }
2523  $this->date_creation = $this->db->jdate($obj->datec);
2524  $this->date_modification = $this->db->jdate($obj->datem);
2525  //$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)
2526  }
2527  $this->db->free($result);
2528  } else {
2529  dol_print_error($this->db);
2530  }
2531  }
2532 
2533  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2542  public function list_replacable_supplier_invoices($socid = 0)
2543  {
2544  // phpcs:enable
2545  global $conf;
2546 
2547  $return = array();
2548 
2549  $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut,";
2550  $sql .= " ff.rowid as rowidnext";
2551  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2552  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2553  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture_fourn as ff ON f.rowid = ff.fk_facture_source";
2554  $sql .= " WHERE (f.fk_statut = ".self::STATUS_VALIDATED." OR (f.fk_statut = ".self::STATUS_ABANDONED." AND f.close_code = '".self::CLOSECODE_ABANDONED."'))";
2555  $sql .= " AND f.entity = ".$conf->entity;
2556  $sql .= " AND f.paye = 0"; // Pas classee payee completement
2557  $sql .= " AND pf.fk_paiementfourn IS NULL"; // Aucun paiement deja fait
2558  $sql .= " AND ff.fk_statut IS NULL"; // Renvoi vrai si pas facture de remplacement
2559  if ($socid > 0) {
2560  $sql .= " AND f.fk_soc = ".((int) $socid);
2561  }
2562  $sql .= " ORDER BY f.ref";
2563 
2564  dol_syslog(get_class($this)."::list_replacable_supplier_invoices", LOG_DEBUG);
2565  $resql = $this->db->query($sql);
2566  if ($resql) {
2567  while ($obj = $this->db->fetch_object($resql)) {
2568  $return[$obj->rowid] = array(
2569  'id' => $obj->rowid,
2570  'ref' => $obj->ref,
2571  'status' => $obj->fk_statut
2572  );
2573  }
2574  //print_r($return);
2575  return $return;
2576  } else {
2577  $this->error = $this->db->error();
2578  return -1;
2579  }
2580  }
2581 
2582  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2592  public function list_qualified_avoir_supplier_invoices($socid = 0)
2593  {
2594  // phpcs:enable
2595  global $conf;
2596 
2597  $return = array();
2598 
2599  $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.paye, pf.fk_paiementfourn";
2600  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2601  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2602  $sql .= " WHERE f.entity = ".$conf->entity;
2603  $sql .= " AND f.fk_statut in (".self::STATUS_VALIDATED.",".self::STATUS_CLOSED.")";
2604  $sql .= " AND NOT EXISTS (SELECT rowid from ".MAIN_DB_PREFIX."facture_fourn as ff WHERE f.rowid = ff.fk_facture_source";
2605  $sql .= " AND ff.type=".self::TYPE_REPLACEMENT.")";
2606  $sql .= " AND f.type != ".self::TYPE_CREDIT_NOTE; // Type non 2 si facture non avoir
2607  if ($socid > 0) {
2608  $sql .= " AND f.fk_soc = ".((int) $socid);
2609  }
2610  $sql .= " ORDER BY f.ref";
2611 
2612  dol_syslog(get_class($this)."::list_qualified_avoir_supplier_invoices", LOG_DEBUG);
2613  $resql = $this->db->query($sql);
2614  if ($resql) {
2615  while ($obj = $this->db->fetch_object($resql)) {
2616  $qualified = 0;
2617  if ($obj->fk_statut == self::STATUS_VALIDATED) {
2618  $qualified = 1;
2619  }
2620  if ($obj->fk_statut == self::STATUS_CLOSED) {
2621  $qualified = 1;
2622  }
2623  if ($qualified) {
2624  $paymentornot = ($obj->fk_paiementfourn ? 1 : 0);
2625  $return[$obj->rowid] = array('ref'=>$obj->ref, 'status'=>$obj->fk_statut, 'type'=>$obj->type, 'paye'=>$obj->paye, 'paymentornot'=>$paymentornot);
2626  }
2627  }
2628 
2629  return $return;
2630  } else {
2631  $this->error = $this->db->error();
2632  return -1;
2633  }
2634  }
2635 
2636  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2643  public function load_board($user)
2644  {
2645  // phpcs:enable
2646  global $conf, $langs;
2647 
2648  $sql = 'SELECT ff.rowid, ff.date_lim_reglement as datefin, ff.fk_statut as status, ff.total_ht, ff.total_ttc';
2649  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as ff';
2650  if (empty($user->rights->societe->client->voir) && !$user->socid) {
2651  $sql .= " JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ff.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
2652  }
2653  $sql .= ' WHERE ff.paye = 0';
2654  $sql .= ' AND ff.fk_statut > 0';
2655  $sql .= " AND ff.entity = ".$conf->entity;
2656  if ($user->socid) {
2657  $sql .= ' AND ff.fk_soc = '.((int) $user->socid);
2658  }
2659 
2660  $resql = $this->db->query($sql);
2661  if ($resql) {
2662  $langs->load("bills");
2663  $now = dol_now();
2664 
2665  $response = new WorkboardResponse();
2666  $response->warning_delay = $conf->facture->fournisseur->warning_delay / 60 / 60 / 24;
2667  $response->label = $langs->trans("SupplierBillsToPay");
2668  $response->labelShort = $langs->trans("StatusToPay");
2669 
2670  $response->url = DOL_URL_ROOT.'/fourn/facture/list.php?search_status=1&mainmenu=billing&leftmenu=suppliers_bills';
2671  $response->img = img_object($langs->trans("Bills"), "bill");
2672 
2673  $facturestatic = new FactureFournisseur($this->db);
2674 
2675  while ($obj = $this->db->fetch_object($resql)) {
2676  $facturestatic->date_echeance = $this->db->jdate($obj->datefin);
2677  $facturestatic->statut = $obj->status; // For backward compatibility
2678  $facturestatic->status = $obj->status;
2679 
2680  $response->nbtodo++;
2681  $response->total += $obj->total_ht;
2682 
2683  if ($facturestatic->hasDelay()) {
2684  $response->nbtodolate++;
2685  $response->url_late = DOL_URL_ROOT.'/fourn/facture/list.php?search_option=late&mainmenu=billing&leftmenu=suppliers_bills';
2686  }
2687  }
2688 
2689  $this->db->free($resql);
2690  return $response;
2691  } else {
2692  dol_print_error($this->db);
2693  $this->error = $this->db->error();
2694  return -1;
2695  }
2696  }
2697 
2698 
2712  public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
2713  {
2714  global $langs, $conf, $user, $hookmanager;
2715 
2716  $result = '';
2717 
2718  if ($option == 'withdraw') {
2719  $url = DOL_URL_ROOT.'/compta/facture/prelevement.php?facid='.$this->id.'&type=bank-transfer';
2720  } elseif ($option == 'document') {
2721  $url = DOL_URL_ROOT.'/fourn/facture/document.php?facid='.$this->id;
2722  } else {
2723  $url = DOL_URL_ROOT.'/fourn/facture/card.php?facid='.$this->id;
2724  }
2725 
2726  if ($short) {
2727  return $url;
2728  }
2729 
2730  if ($option !== 'nolink') {
2731  // Add param to save lastsearch_values or not
2732  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
2733  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
2734  $add_save_lastsearch_values = 1;
2735  }
2736  if ($add_save_lastsearch_values) {
2737  $url .= '&save_lastsearch_values=1';
2738  }
2739  }
2740 
2741  $picto = $this->picto;
2742  if ($this->type == self::TYPE_REPLACEMENT) {
2743  $picto .= 'r'; // Replacement invoice
2744  }
2745  if ($this->type == self::TYPE_CREDIT_NOTE) {
2746  $picto .= 'a'; // Credit note
2747  }
2748  if ($this->type == self::TYPE_DEPOSIT) {
2749  $picto .= 'd'; // Deposit invoice
2750  }
2751 
2752  $label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("SupplierInvoice").'</u>';
2753  if ($this->type == self::TYPE_REPLACEMENT) {
2754  $label = '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("InvoiceReplace").'</u>';
2755  } elseif ($this->type == self::TYPE_CREDIT_NOTE) {
2756  $label = '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("CreditNote").'</u>';
2757  } elseif ($this->type == self::TYPE_DEPOSIT) {
2758  $label = '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("Deposit").'</u>';
2759  }
2760  if (isset($this->status)) {
2761  $alreadypaid = -1;
2762  if (isset($this->alreadypaid)) {
2763  $alreadypaid = $this->alreadypaid;
2764  }
2765 
2766  $label .= ' '.$this->getLibStatut(5, $alreadypaid);
2767  }
2768  if (!empty($this->ref)) {
2769  $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
2770  }
2771  if (!empty($this->ref_supplier)) {
2772  $label .= '<br><b>'.$langs->trans('RefSupplier').':</b> '.$this->ref_supplier;
2773  }
2774  if (!empty($this->label)) {
2775  $label .= '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
2776  }
2777  if (!empty($this->date)) {
2778  $label .= '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
2779  }
2780  if (!empty($this->total_ht)) {
2781  $label .= '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
2782  }
2783  if (!empty($this->total_tva)) {
2784  $label .= '<br><b>'.$langs->trans('AmountVAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
2785  }
2786  if (!empty($this->total_ttc)) {
2787  $label .= '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
2788  }
2789  if ($moretitle) {
2790  $label .= ' - '.$moretitle;
2791  }
2792 
2793  $ref = $this->ref;
2794  if (empty($ref)) {
2795  $ref = $this->id;
2796  }
2797 
2798  $linkclose = '';
2799  if (empty($notooltip)) {
2800  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2801  $label = $langs->trans("ShowSupplierInvoice");
2802  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
2803  }
2804  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
2805  $linkclose .= ' class="classfortooltip"';
2806  }
2807 
2808  $linkstart = '<a href="'.$url.'"';
2809  $linkstart .= $linkclose.'>';
2810  $linkend = '</a>';
2811 
2812  $result .= $linkstart;
2813  if ($withpicto) {
2814  $result .= img_object(($notooltip ? '' : $label), $picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
2815  }
2816  if ($withpicto != 2) {
2817  $result .= ($max ?dol_trunc($ref, $max) : $ref);
2818  }
2819  $result .= $linkend;
2820 
2821  if ($addlinktonotes) {
2822  $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
2823  if ($txttoshow) {
2824  $notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
2825  $result .= ' <span class="note inline-block">';
2826  $result .= '<a href="'.DOL_URL_ROOT.'/fourn/facture/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
2827  $result .= img_picto('', 'note');
2828  $result .= '</a>';
2829  $result .= '</span>';
2830  }
2831  }
2832  global $action;
2833  $hookmanager->initHooks(array($this->element . 'dao'));
2834  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
2835  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2836  if ($reshook > 0) {
2837  $result = $hookmanager->resPrint;
2838  } else {
2839  $result .= $hookmanager->resPrint;
2840  }
2841  return $result;
2842  }
2843 
2852  public function getNextNumRef($soc, $mode = 'next')
2853  {
2854  global $db, $langs, $conf;
2855  $langs->load("orders");
2856 
2857  // Clean parameters (if not defined or using deprecated value)
2858  if (empty($conf->global->INVOICE_SUPPLIER_ADDON_NUMBER)) {
2859  $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER = 'mod_facture_fournisseur_cactus';
2860  }
2861 
2862  $mybool = false;
2863 
2864  $file = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER.".php";
2865  $classname = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER;
2866 
2867  // Include file with class
2868  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2869 
2870  foreach ($dirmodels as $reldir) {
2871  $dir = dol_buildpath($reldir."core/modules/supplier_invoice/");
2872 
2873  // Load file with numbering class (if found)
2874  $mybool |= @include_once $dir.$file;
2875  }
2876 
2877  if ($mybool === false) {
2878  dol_print_error('', "Failed to include file ".$file);
2879  return '';
2880  }
2881 
2882  $obj = new $classname();
2883  $numref = "";
2884  $numref = $obj->getNumRef($soc, $this, $mode);
2885 
2886  if ($numref != "") {
2887  return $numref;
2888  } else {
2889  $this->error = $obj->error;
2890  return -1;
2891  }
2892  }
2893 
2894 
2903  public function initAsSpecimen($option = '')
2904  {
2905  global $langs, $conf;
2906  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
2907 
2908  $now = dol_now();
2909 
2910  // Load array of products prodids
2911  $num_prods = 0;
2912  $prodids = array();
2913 
2914  $sql = "SELECT rowid";
2915  $sql .= " FROM ".MAIN_DB_PREFIX."product";
2916  $sql .= " WHERE entity IN (".getEntity('product').")";
2917  $sql .= $this->db->plimit(100);
2918 
2919  $resql = $this->db->query($sql);
2920  if ($resql) {
2921  $num_prods = $this->db->num_rows($resql);
2922  $i = 0;
2923  while ($i < $num_prods) {
2924  $i++;
2925  $row = $this->db->fetch_row($resql);
2926  $prodids[$i] = $row[0];
2927  }
2928  }
2929 
2930  // Initialise parametres
2931  $this->id = 0;
2932  $this->ref = 'SPECIMEN';
2933  $this->ref_supplier = 'SUPPLIER_REF_SPECIMEN';
2934  $this->specimen = 1;
2935  $this->socid = 1;
2936  $this->date = $now;
2937  $this->date_lim_reglement = $this->date + 3600 * 24 * 30;
2938  $this->cond_reglement_code = 'RECEP';
2939  $this->mode_reglement_code = 'CHQ';
2940 
2941  $this->note_public = 'This is a comment (public)';
2942  $this->note_private = 'This is a comment (private)';
2943 
2944  $this->multicurrency_tx = 1;
2945  $this->multicurrency_code = $conf->currency;
2946 
2947  $xnbp = 0;
2948  if (empty($option) || $option != 'nolines') {
2949  // Lines
2950  $nbp = 5;
2951  while ($xnbp < $nbp) {
2952  $line = new SupplierInvoiceLine($this->db);
2953  $line->desc = $langs->trans("Description")." ".$xnbp;
2954  $line->qty = 1;
2955  $line->subprice = 100;
2956  $line->pu_ht = 100; // the canelle template use pu_ht and not subprice
2957  $line->price = 100;
2958  $line->tva_tx = 19.6;
2959  $line->localtax1_tx = 0;
2960  $line->localtax2_tx = 0;
2961  if ($xnbp == 2) {
2962  $line->total_ht = 50;
2963  $line->total_ttc = 59.8;
2964  $line->total_tva = 9.8;
2965  $line->remise_percent = 50;
2966  } else {
2967  $line->total_ht = 100;
2968  $line->total_ttc = 119.6;
2969  $line->total_tva = 19.6;
2970  $line->remise_percent = 0;
2971  }
2972 
2973  if ($num_prods > 0) {
2974  $prodid = mt_rand(1, $num_prods);
2975  $line->fk_product = $prodids[$prodid];
2976  }
2977  $line->product_type = 0;
2978 
2979  $this->lines[$xnbp] = $line;
2980 
2981  $this->total_ht += $line->total_ht;
2982  $this->total_tva += $line->total_tva;
2983  $this->total_ttc += $line->total_ttc;
2984 
2985  $xnbp++;
2986  }
2987  }
2988 
2989  $this->amount_ht = $xnbp * 100;
2990  $this->total_ht = $xnbp * 100;
2991  $this->total_tva = $xnbp * 19.6;
2992  $this->total_ttc = $xnbp * 119.6;
2993  }
2994 
2995  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3001  public function load_state_board()
3002  {
3003  // phpcs:enable
3004  global $conf, $user;
3005 
3006  $this->nb = array();
3007 
3008  $clause = "WHERE";
3009 
3010  $sql = "SELECT count(f.rowid) as nb";
3011  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
3012  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
3013  if (empty($user->rights->societe->client->voir) && !$user->socid) {
3014  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
3015  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3016  $clause = "AND";
3017  }
3018  $sql .= " ".$clause." f.entity = ".$conf->entity;
3019 
3020  $resql = $this->db->query($sql);
3021  if ($resql) {
3022  while ($obj = $this->db->fetch_object($resql)) {
3023  $this->nb["supplier_invoices"] = $obj->nb;
3024  }
3025  $this->db->free($resql);
3026  return 1;
3027  } else {
3028  dol_print_error($this->db);
3029  $this->error = $this->db->error();
3030  return -1;
3031  }
3032  }
3033 
3042  public function createFromClone(User $user, $fromid, $invertdetail = 0)
3043  {
3044  global $conf, $langs;
3045 
3046  $error = 0;
3047 
3048  $object = new FactureFournisseur($this->db);
3049 
3050  $this->db->begin();
3051 
3052  // Load source object
3053  $object->fetch($fromid);
3054  $object->id = 0;
3055  $object->statut = self::STATUS_DRAFT; // For backward compatibility
3056  $object->status = self::STATUS_DRAFT;
3057 
3058  $object->fetch_thirdparty(); // We need it to recalculate VAT localtaxes according to main sale taxes and vendor
3059 
3060  // Clear fields
3061  $object->ref_supplier = (empty($this->ref_supplier) ? $langs->trans("CopyOf").' '.$object->ref_supplier : $this->ref_supplier);
3062  $object->author = $user->id;
3063  $object->user_valid = '';
3064  $object->fk_facture_source = 0;
3065  $object->date_creation = '';
3066  $object->date_validation = '';
3067  $object->date = (empty($this->date) ? '' : $this->date);
3068  $object->date_echeance = '';
3069  $object->ref_client = '';
3070  $object->close_code = '';
3071  $object->close_note = '';
3072  if ($conf->global->MAIN_DONT_KEEP_NOTE_ON_CLONING == 1) {
3073  $object->note_private = '';
3074  $object->note_public = '';
3075  }
3076 
3077  // Loop on each line of new invoice
3078  foreach ($object->lines as $i => $line) {
3079  if (isset($object->lines[$i]->info_bits) && ($object->lines[$i]->info_bits & 0x02) == 0x02) { // We do not clone line of discounts
3080  unset($object->lines[$i]);
3081  }
3082  }
3083 
3084  // Create clone
3085  $object->context['createfromclone'] = 'createfromclone';
3086  $result = $object->create($user);
3087 
3088  // Other options
3089  if ($result < 0) {
3090  $this->error = $object->error;
3091  $this->errors = $object->errors;
3092  $error++;
3093  }
3094 
3095  if (!$error) {
3096  }
3097 
3098  unset($object->context['createfromclone']);
3099 
3100  // End
3101  if (!$error) {
3102  $this->db->commit();
3103  return $object->id;
3104  } else {
3105  $this->db->rollback();
3106  return -1;
3107  }
3108  }
3109 
3121  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
3122  {
3123  global $conf, $user, $langs;
3124 
3125  $langs->load("suppliers");
3126  $outputlangs->load("products");
3127 
3128  // Set the model on the model name to use
3129  if (empty($modele)) {
3130  if (!empty($conf->global->INVOICE_SUPPLIER_ADDON_PDF)) {
3131  $modele = $conf->global->INVOICE_SUPPLIER_ADDON_PDF;
3132  } else {
3133  $modele = ''; // No default value. For supplier invoice, we allow to disable all PDF generation
3134  }
3135  }
3136 
3137  if (empty($modele)) {
3138  return 0;
3139  } else {
3140  $modelpath = "core/modules/supplier_invoice/doc/";
3141 
3142  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
3143  }
3144  }
3145 
3150  public function getRights()
3151  {
3152  global $user;
3153 
3154  return $user->rights->fournisseur->facture;
3155  }
3156 
3165  public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
3166  {
3167  $tables = array(
3168  'facture_fourn'
3169  );
3170 
3171  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
3172  }
3173 
3182  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
3183  {
3184  $tables = array(
3185  'facture_fourn_det'
3186  );
3187 
3188  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
3189  }
3190 
3196  public function hasDelay()
3197  {
3198  global $conf;
3199 
3200  $now = dol_now();
3201 
3202  if (!$this->date_echeance) {
3203  return false;
3204  }
3205 
3206  $status = isset($this->status) ? $this->status : $this->statut;
3207 
3208  return ($status == self::STATUS_VALIDATED) && ($this->date_echeance < ($now - $conf->facture->fournisseur->warning_delay));
3209  }
3210 
3216  public function isCreditNoteUsed()
3217  {
3218  $isUsed = false;
3219 
3220  $sql = "SELECT fk_invoice_supplier FROM ".MAIN_DB_PREFIX."societe_remise_except WHERE fk_invoice_supplier_source = ".((int) $this->id);
3221  $resql = $this->db->query($sql);
3222  if (!empty($resql)) {
3223  $obj = $this->db->fetch_object($resql);
3224  if (!empty($obj->fk_invoice_supplier)) {
3225  $isUsed = true;
3226  }
3227  }
3228 
3229  return $isUsed;
3230  }
3231 }
3232 
3233 
3234 
3239 {
3243  public $element = 'facture_fourn_det';
3244 
3248  public $table_element = 'facture_fourn_det';
3249 
3250  public $oldline;
3251 
3256  public $ref;
3257 
3262  public $product_ref;
3263 
3269  public $ref_supplier;
3270 
3275  public $product_desc;
3276 
3283  public $pu_ht;
3284 
3289  public $subprice;
3290 
3295  public $pu_ttc;
3296 
3297 
3302  public $fk_facture_fourn;
3303 
3309  public $label;
3310 
3315  public $description;
3316 
3317  public $date_start;
3318  public $date_end;
3319 
3320  public $skip_update_total; // Skip update price total for special lines
3321 
3325  public $situation_percent;
3326 
3330  public $fk_prev_id;
3331 
3336  public $vat_src_code;
3337 
3342  public $tva_tx;
3343 
3348  public $localtax1_tx;
3349 
3354  public $localtax2_tx;
3355 
3360  public $qty;
3361 
3366  public $remise_percent;
3367 
3372  public $total_ht;
3373 
3378  public $total_ttc;
3379 
3384  public $total_tva;
3385 
3390  public $total_localtax1;
3391 
3396  public $total_localtax2;
3397 
3401  public $fk_product;
3402 
3407  public $product_type;
3408 
3413  public $product_label;
3414 
3421  public $info_bits;
3422 
3427  public $fk_remise_except;
3428 
3432  public $fk_parent_line;
3433 
3434  public $special_code;
3435 
3439  public $rang;
3440 
3445  public $localtax1_type;
3446 
3451  public $localtax2_type;
3452 
3453  // Multicurrency
3457  public $fk_multicurrency;
3458 
3459  public $multicurrency_code;
3460  public $multicurrency_subprice;
3461  public $multicurrency_total_ht;
3462  public $multicurrency_total_tva;
3463  public $multicurrency_total_ttc;
3464 
3465 
3471  public function __construct($db)
3472  {
3473  $this->db = $db;
3474  }
3475 
3482  public function fetch($rowid)
3483  {
3484  $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';
3485  $sql .= ', f.localtax1_type, f.localtax2_type, f.localtax1_tx, f.localtax2_tx, f.total_localtax1, f.total_localtax2, f.fk_remise_except';
3486  $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';
3487  $sql .= ', p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.description as product_desc';
3488  $sql .= ', f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, multicurrency_total_ttc';
3489  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
3490  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
3491  $sql .= ' WHERE f.rowid = '.((int) $rowid);
3492  $sql .= ' ORDER BY f.rang, f.rowid';
3493 
3494  $query = $this->db->query($sql);
3495 
3496  if (!$query) {
3497  $this->errors[] = $this->db->error();
3498  return -1;
3499  }
3500 
3501  if (!$this->db->num_rows($query)) {
3502  return 0;
3503  }
3504 
3505  $obj = $this->db->fetch_object($query);
3506 
3507  $this->id = $obj->rowid;
3508  $this->rowid = $obj->rowid;
3509  $this->fk_facture_fourn = $obj->fk_facture_fourn;
3510  $this->description = $obj->description;
3511  $this->date_start = $obj->date_start;
3512  $this->date_end = $obj->date_end;
3513  $this->product_ref = $obj->product_ref;
3514  $this->ref_supplier = $obj->ref_supplier;
3515  $this->product_desc = $obj->product_desc;
3516 
3517  $this->subprice = $obj->pu_ht;
3518  $this->pu_ht = $obj->pu_ht;
3519  $this->pu_ttc = $obj->pu_ttc;
3520  $this->tva_tx = $obj->tva_tx;
3521  $this->localtax1_tx = $obj->localtax1_tx;
3522  $this->localtax2_tx = $obj->localtax2_tx;
3523  $this->localtax1_type = $obj->localtax1_type;
3524  $this->localtax2_type = $obj->localtax2_type;
3525 
3526  $this->qty = $obj->qty;
3527  $this->remise_percent = $obj->remise_percent;
3528  $this->fk_remise_except = $obj->fk_remise_except;
3529  //$this->tva = $obj->total_tva; // deprecated
3530  $this->total_ht = $obj->total_ht;
3531  $this->total_tva = $obj->total_tva;
3532  $this->total_localtax1 = $obj->total_localtax1;
3533  $this->total_localtax2 = $obj->total_localtax2;
3534  $this->total_ttc = $obj->total_ttc;
3535  $this->fk_product = $obj->fk_product;
3536  $this->product_type = $obj->product_type;
3537  $this->product_label = $obj->product_label;
3538  $this->info_bits = $obj->info_bits;
3539  $this->tva_npr = ($obj->info_bits & 1 == 1) ? 1 : 0;
3540  $this->fk_parent_line = $obj->fk_parent_line;
3541  $this->special_code = $obj->special_code;
3542  $this->rang = $obj->rang;
3543  $this->fk_unit = $obj->fk_unit;
3544 
3545  $this->multicurrency_subprice = $obj->multicurrency_subprice;
3546  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
3547  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
3548  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
3549 
3550  $this->fetch_optionals();
3551 
3552  return 1;
3553  }
3554 
3561  public function delete($notrigger = 0)
3562  {
3563  global $user, $conf;
3564 
3565  dol_syslog(get_class($this)."::deleteline rowid=".((int) $this->id), LOG_DEBUG);
3566 
3567  $error = 0;
3568 
3569  $this->db->begin();
3570 
3571  if (!$notrigger) {
3572  if ($this->call_trigger('LINEBILL_SUPPLIER_DELETE', $user) < 0) {
3573  $error++;
3574  }
3575  }
3576 
3577  $this->deleteObjectLinked();
3578 
3579  // Remove extrafields
3580  if (!$error) {
3581  $result = $this->deleteExtraFields();
3582  if ($result < 0) {
3583  $error++;
3584  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
3585  }
3586  }
3587 
3588  if (!$error) {
3589  // Supprime ligne
3590  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det ';
3591  $sql .= " WHERE rowid = ".((int) $this->id);
3592  dol_syslog(get_class($this)."::delete", LOG_DEBUG);
3593  $resql = $this->db->query($sql);
3594  if (!$resql) {
3595  $error++;
3596  $this->error = $this->db->lasterror();
3597  }
3598  }
3599 
3600  if (!$error) {
3601  $this->db->commit();
3602  return 1;
3603  } else {
3604  $this->db->rollback();
3605  return -1;
3606  }
3607  }
3608 
3615  public function update($notrigger = 0)
3616  {
3617  global $conf;
3618 
3619  $pu = price2num($this->pu_ht);
3620  $qty = price2num($this->qty);
3621 
3622  // Check parameters
3623  if (empty($this->qty)) {
3624  $this->qty = 0;
3625  }
3626 
3627  if ($this->product_type < 0) {
3628  return -1;
3629  }
3630 
3631  // Clean parameters
3632  if (empty($this->remise_percent)) {
3633  $this->remise_percent = 0;
3634  }
3635  if (empty($this->tva_tx)) {
3636  $this->tva_tx = 0;
3637  }
3638  if (empty($this->localtax1_tx)) {
3639  $this->localtax1_tx = 0;
3640  }
3641  if (empty($this->localtax2_tx)) {
3642  $this->localtax2_tx = 0;
3643  }
3644 
3645  if (empty($this->pa_ht)) {
3646  $this->pa_ht = 0;
3647  }
3648  if (empty($this->multicurrency_subprice)) {
3649  $this->multicurrency_subprice = 0;
3650  }
3651  if (empty($this->multicurrency_total_ht)) {
3652  $this->multicurrency_total_ht = 0;
3653  }
3654  if (empty($this->multicurrency_total_tva)) {
3655  $this->multicurrency_total_tva = 0;
3656  }
3657  if (empty($this->multicurrency_total_ttc)) {
3658  $this->multicurrency_total_ttc = 0;
3659  }
3660 
3661  $fk_product = (int) $this->fk_product;
3662  $fk_unit = (int) $this->fk_unit;
3663 
3664  $this->db->begin();
3665 
3666  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
3667  $sql .= " description = '".$this->db->escape($this->description)."'";
3668  $sql .= ", ref = '".$this->db->escape($this->ref_supplier ? $this->ref_supplier : $this->ref)."'";
3669  $sql .= ", date_start = ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : "null");
3670  $sql .= ", date_end = ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : "null");
3671  $sql .= ", pu_ht = ".price2num($this->pu_ht);
3672  $sql .= ", pu_ttc = ".price2num($this->pu_ttc);
3673  $sql .= ", qty = ".price2num($this->qty);
3674  $sql .= ", remise_percent = ".price2num($this->remise_percent);
3675  if ($this->fk_remise_except > 0) $sql .= ", fk_remise_except=".((int) $this->fk_remise_except);
3676  else $sql .= ", fk_remise_except=null";
3677  $sql .= ", vat_src_code = '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."'";
3678  $sql .= ", tva_tx = ".price2num($this->tva_tx);
3679  $sql .= ", localtax1_tx = ".price2num($this->localtax1_tx);
3680  $sql .= ", localtax2_tx = ".price2num($this->localtax2_tx);
3681  $sql .= ", localtax1_type = '".$this->db->escape($this->localtax1_type)."'";
3682  $sql .= ", localtax2_type = '".$this->db->escape($this->localtax2_type)."'";
3683  $sql .= ", total_ht = ".price2num($this->total_ht);
3684  $sql .= ", tva= ".price2num($this->total_tva);
3685  $sql .= ", total_localtax1= ".price2num($this->total_localtax1);
3686  $sql .= ", total_localtax2= ".price2num($this->total_localtax2);
3687  $sql .= ", total_ttc = ".price2num($this->total_ttc);
3688  $sql .= ", fk_product = ".($fk_product > 0 ? (int) $fk_product : 'null');
3689  $sql .= ", product_type = ".((int) $this->product_type);
3690  $sql .= ", info_bits = ".((int) $this->info_bits);
3691  $sql .= ", fk_unit = ".($fk_unit > 0 ? (int) $fk_unit : 'null');
3692 
3693  if (!empty($this->rang)) {
3694  $sql .= ", rang=".((int) $this->rang);
3695  }
3696 
3697  // Multicurrency
3698  $sql .= " , multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
3699  $sql .= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
3700  $sql .= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
3701  $sql .= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
3702 
3703  $sql .= " WHERE rowid = ".((int) $this->id);
3704 
3705  dol_syslog(get_class($this)."::update", LOG_DEBUG);
3706  $resql = $this->db->query($sql);
3707 
3708  if (!$resql) {
3709  $this->db->rollback();
3710  $this->error = $this->db->lasterror();
3711  return -1;
3712  }
3713 
3714  $this->rowid = $this->id;
3715  $error = 0;
3716 
3717  if (!$error) {
3718  $result = $this->insertExtraFields();
3719  if ($result < 0) {
3720  $error++;
3721  }
3722  }
3723 
3724  if (!$error && !$notrigger) {
3725  global $langs, $user;
3726 
3727  // Call trigger
3728  if ($this->call_trigger('LINEBILL_SUPPLIER_MODIFY', $user) < 0) {
3729  $this->db->rollback();
3730  return -1;
3731  }
3732  // End call triggers
3733  }
3734 
3735  if ($error) {
3736  $this->db->rollback();
3737  return -1;
3738  }
3739 
3740  $this->db->commit();
3741  return 1;
3742  }
3743 
3750  public function insert($notrigger = 0)
3751  {
3752  global $user, $conf, $langs;
3753 
3754  $error = 0;
3755 
3756  dol_syslog(get_class($this)."::insert rang=".$this->rang, LOG_DEBUG);
3757 
3758  // Clean parameters
3759  $this->desc = trim($this->desc);
3760  if (empty($this->tva_tx)) {
3761  $this->tva_tx = 0;
3762  }
3763  if (empty($this->localtax1_tx)) {
3764  $this->localtax1_tx = 0;
3765  }
3766  if (empty($this->localtax2_tx)) {
3767  $this->localtax2_tx = 0;
3768  }
3769  if (empty($this->localtax1_type)) {
3770  $this->localtax1_type = '0';
3771  }
3772  if (empty($this->localtax2_type)) {
3773  $this->localtax2_type = '0';
3774  }
3775  if (empty($this->total_tva)) {
3776  $this->total_tva = 0;
3777  }
3778  if (empty($this->total_localtax1)) {
3779  $this->total_localtax1 = 0;
3780  }
3781  if (empty($this->total_localtax2)) {
3782  $this->total_localtax2 = 0;
3783  }
3784  if (empty($this->rang)) {
3785  $this->rang = 0;
3786  }
3787  if (empty($this->remise_percent)) {
3788  $this->remise_percent = 0;
3789  }
3790  if (empty($this->info_bits)) {
3791  $this->info_bits = 0;
3792  }
3793  if (empty($this->subprice)) {
3794  $this->subprice = 0;
3795  }
3796  if (empty($this->special_code)) {
3797  $this->special_code = 0;
3798  }
3799  if (empty($this->fk_parent_line)) {
3800  $this->fk_parent_line = 0;
3801  }
3802  if (!isset($this->situation_percent) || $this->situation_percent > 100 || (string) $this->situation_percent == '') {
3803  $this->situation_percent = 100;
3804  }
3805 
3806  if (empty($this->pa_ht)) {
3807  $this->pa_ht = 0;
3808  }
3809  if (empty($this->multicurrency_subprice)) {
3810  $this->multicurrency_subprice = 0;
3811  }
3812  if (empty($this->multicurrency_total_ht)) {
3813  $this->multicurrency_total_ht = 0;
3814  }
3815  if (empty($this->multicurrency_total_tva)) {
3816  $this->multicurrency_total_tva = 0;
3817  }
3818  if (empty($this->multicurrency_total_ttc)) {
3819  $this->multicurrency_total_ttc = 0;
3820  }
3821 
3822 
3823  // Check parameters
3824  if ($this->product_type < 0) {
3825  $this->error = 'ErrorProductTypeMustBe0orMore';
3826  return -1;
3827  }
3828  if (!empty($this->fk_product) && $this->fk_product > 0) {
3829  // Check product exists
3830  $result = Product::isExistingObject('product', $this->fk_product);
3831  if ($result <= 0) {
3832  $this->error = 'ErrorProductIdDoesNotExists';
3833  return -1;
3834  }
3835  }
3836 
3837  $this->db->begin();
3838 
3839  // Insertion dans base de la ligne
3840  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
3841  $sql .= ' (fk_facture_fourn, fk_parent_line, label, description, ref, qty,';
3842  $sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3843  $sql .= ' fk_product, product_type, remise_percent, fk_remise_except, pu_ht, pu_ttc,';
3844  $sql .= ' date_start, date_end, fk_code_ventilation, rang, special_code,';
3845  $sql .= ' info_bits, total_ht, tva, total_ttc, total_localtax1, total_localtax2, fk_unit';
3846  $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
3847  $sql .= ')';
3848  $sql .= " VALUES (".$this->fk_facture_fourn.",";
3849  $sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape($this->fk_parent_line)."'" : "null").",";
3850  $sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
3851  $sql .= " '".$this->db->escape($this->desc ? $this->desc : $this->description)."',";
3852  $sql .= " '".$this->db->escape($this->ref_supplier)."',";
3853  $sql .= " ".price2num($this->qty).",";
3854 
3855  $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape($this->vat_src_code)."'").",";
3856  $sql .= " ".price2num($this->tva_tx).",";
3857  $sql .= " ".price2num($this->localtax1_tx).",";
3858  $sql .= " ".price2num($this->localtax2_tx).",";
3859  $sql .= " '".$this->db->escape($this->localtax1_type)."',";
3860  $sql .= " '".$this->db->escape($this->localtax2_type)."',";
3861  $sql .= ' '.((!empty($this->fk_product) && $this->fk_product > 0) ? $this->fk_product : "null").',';
3862  $sql .= " ".((int) $this->product_type).",";
3863  $sql .= " ".price2num($this->remise_percent).",";
3864  $sql .= ' '.(! empty($this->fk_remise_except) ? ((int) $this->fk_remise_except) : "null").',';
3865  $sql .= " ".price2num($this->subprice).",";
3866  $sql .= " ".(!empty($this->qty) ?price2num($this->total_ttc / $this->qty) : price2num($this->total_ttc)).",";
3867  $sql .= " ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null").",";
3868  $sql .= " ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").",";
3869  $sql .= ' '.(!empty($this->fk_code_ventilation) ? $this->fk_code_ventilation : 0).',';
3870  $sql .= ' '.((int) $this->rang).',';
3871  $sql .= ' '.((int) $this->special_code).',';
3872  $sql .= " ".((int) $this->info_bits).",";
3873  $sql .= " ".price2num($this->total_ht).",";
3874  $sql .= " ".price2num($this->total_tva).",";
3875  $sql .= " ".price2num($this->total_ttc).",";
3876  $sql .= " ".price2num($this->total_localtax1).",";
3877  $sql .= " ".price2num($this->total_localtax2);
3878  $sql .= ", ".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
3879  $sql .= ", ".(int) $this->fk_multicurrency;
3880  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
3881  $sql .= ", ".price2num($this->multicurrency_subprice);
3882  $sql .= ", ".price2num($this->multicurrency_total_ht);
3883  $sql .= ", ".price2num($this->multicurrency_total_tva);
3884  $sql .= ", ".price2num($this->multicurrency_total_ttc);
3885  $sql .= ')';
3886 
3887  $resql = $this->db->query($sql);
3888  if ($resql) {
3889  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
3890  $this->rowid = $this->id; // backward compatibility
3891 
3892  if (!$error) {
3893  $result = $this->insertExtraFields();
3894  if ($result < 0) {
3895  $error++;
3896  }
3897  }
3898 
3899  // Si fk_remise_except defini, on lie la remise a la facture
3900  // ce qui la flague comme "consommee".
3901  if ($this->fk_remise_except) {
3902  $discount = new DiscountAbsolute($this->db);
3903  $result = $discount->fetch($this->fk_remise_except);
3904  if ($result >= 0) {
3905  // Check if discount was found
3906  if ($result > 0) {
3907  // Check if discount not already affected to another invoice
3908  if ($discount->fk_facture_line > 0) {
3909  if (empty($noerrorifdiscountalreadylinked)) {
3910  $this->error = $langs->trans("ErrorDiscountAlreadyUsed", $discount->id);
3911  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
3912  $this->db->rollback();
3913  return -3;
3914  }
3915  } else {
3916  $result = $discount->link_to_invoice($this->rowid, 0);
3917  if ($result < 0) {
3918  $this->error = $discount->error;
3919  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
3920  $this->db->rollback();
3921  return -3;
3922  }
3923  }
3924  } else {
3925  $this->error = $langs->trans("ErrorADiscountThatHasBeenRemovedIsIncluded");
3926  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
3927  $this->db->rollback();
3928  return -3;
3929  }
3930  } else {
3931  $this->error = $discount->error;
3932  dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
3933  $this->db->rollback();
3934  return -3;
3935  }
3936  }
3937 
3938  if (!$error && !$notrigger) {
3939  // Call trigger
3940  $result = $this->call_trigger('LINEBILL_SUPPLIER_CREATE', $user);
3941  if ($result < 0) {
3942  $this->db->rollback();
3943  return -2;
3944  }
3945  // End call triggers
3946  }
3947 
3948  $this->db->commit();
3949  return $this->id;
3950  } else {
3951  $this->error = $this->db->error();
3952  $this->db->rollback();
3953  return -2;
3954  }
3955  }
3956 
3957  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3963  public function update_total()
3964  {
3965  // phpcs:enable
3966  $this->db->begin();
3967 
3968  // Mise a jour ligne en base
3969  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
3970  $sql .= " total_ht = ".price2num($this->total_ht);
3971  $sql .= ", tva= ".price2num($this->total_tva);
3972  $sql .= ", total_localtax1 = ".price2num($this->total_localtax1);
3973  $sql .= ", total_localtax2 = ".price2num($this->total_localtax2);
3974  $sql .= ", total_ttc = ".price2num($this->total_ttc);
3975  $sql .= " WHERE rowid = ".((int) $this->rowid);
3976 
3977  dol_syslog("FactureFournisseurLigne.class.php::update_total", LOG_DEBUG);
3978 
3979  $resql = $this->db->query($sql);
3980  if ($resql) {
3981  $this->db->commit();
3982  return 1;
3983  } else {
3984  $this->error = $this->db->error();
3985  $this->db->rollback();
3986  return -2;
3987  }
3988  }
3989 }
FactureFournisseur\update
update($user=null, $notrigger=0)
Update database.
Definition: fournisseur.facture.class.php:1134
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:7824
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:6083
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:1454
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:3791
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:3482
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:3165
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1212
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:2495
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:4830
FactureFournisseur\hasDelay
hasDelay()
Is the payment of the supplier invoice having a delay?
Definition: fournisseur.facture.class.php:3196
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:3615
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:2284
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:2441
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:1764
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:2903
SupplierInvoiceLine\$ref
$ref
Definition: fournisseur.facture.class.php:3256
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:5647
SupplierInvoiceLine
Class to manage line invoices.
Definition: fournisseur.facture.class.php:3238
FactureFournisseur\load_board
load_board($user)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: fournisseur.facture.class.php:2643
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:2500
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:7234
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:3866
FactureFournisseur\isCreditNoteUsed
isCreditNoteUsed()
Is credit note used.
Definition: fournisseur.facture.class.php:3216
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:2852
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:3471
FactureFournisseur\setPaid
setPaid($user, $close_code='', $close_note='')
Tag invoice as a paid invoice.
Definition: fournisseur.facture.class.php:1583
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:6535
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:3182
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:3750
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:7261
FactureFournisseur\setDraft
setDraft($user, $idwarehouse=-1)
Set draft status.
Definition: fournisseur.facture.class.php:1919
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:6680
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:1322
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:1589
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:2022
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:2592
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:1646
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3733
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:1568
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:1707
FactureFournisseur\getRights
getRights()
Returns the rights used for this class.
Definition: fournisseur.facture.class.php:3150
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:1661
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:4197
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:2831
$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:5527
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:3042
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:2712
FactureFournisseur\load_state_board
load_state_board()
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: fournisseur.facture.class.php:3001
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:3121
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:3963
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:7946
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:2542
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