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