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