dolibarr 19.0.3
fournisseur.facture.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2002-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Christophe Combelles <ccomb@free.fr>
5 * Copyright (C) 2005 Marc Barilley <marc@ocebo.com>
6 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
7 * Copyright (C) 2010-2020 Juanjo Menent <jmenent@2byte.es>
8 * Copyright (C) 2013-2019 Philippe Grand <philippe.grand@atoo-net.com>
9 * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
10 * Copyright (C) 2014-2016 Marcos García <marcosgdf@gmail.com>
11 * Copyright (C) 2015 Bahfir Abbes <bafbes@gmail.com>
12 * Copyright (C) 2015-2022 Ferran Marcet <fmarcet@2byte.es>
13 * Copyright (C) 2016-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 (isset($this->total_localtax1)) $this->total_localtax1=trim($this->total_localtax1);
1183 // if (isset($this->total_localtax2)) $this->total_localtax2=trim($this->total_localtax2);
1184 if (isset($this->total_ttc)) {
1185 $this->total_ttc = trim($this->total_ttc);
1186 }
1187 if (isset($this->statut)) {
1188 $this->statut = (int) $this->statut;
1189 }
1190 if (isset($this->status)) {
1191 $this->status = (int) $this->status;
1192 }
1193 if (isset($this->author)) {
1194 $this->author = trim($this->author);
1195 }
1196 if (isset($this->fk_user_valid)) {
1197 $this->fk_user_valid = trim($this->fk_user_valid);
1198 }
1199 if (isset($this->fk_facture_source)) {
1200 $this->fk_facture_source = trim($this->fk_facture_source);
1201 }
1202 if (isset($this->fk_project)) {
1203 if (empty($this->fk_project)) {
1204 $this->fk_project = null;
1205 } else {
1206 $this->fk_project = intval($this->fk_project);
1207 }
1208 }
1209 if (isset($this->cond_reglement_id)) {
1210 $this->cond_reglement_id = trim($this->cond_reglement_id);
1211 }
1212 if (isset($this->note_private)) {
1213 $this->note = trim($this->note_private);
1214 }
1215 if (isset($this->note_public)) {
1216 $this->note_public = trim($this->note_public);
1217 }
1218 if (isset($this->model_pdf)) {
1219 $this->model_pdf = trim($this->model_pdf);
1220 }
1221 if (isset($this->import_key)) {
1222 $this->import_key = trim($this->import_key);
1223 }
1224
1225
1226 // Check parameters
1227 // Put here code to add control on parameters values
1228
1229 // Update request
1230 $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn SET";
1231 $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
1232 $sql .= " ref_supplier=".(isset($this->ref_supplier) ? "'".$this->db->escape($this->ref_supplier)."'" : "null").",";
1233 $sql .= " ref_ext=".(isset($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : "null").",";
1234 $sql .= " entity=".(isset($this->entity) ? ((int) $this->entity) : "null").",";
1235 $sql .= " type=".(isset($this->type) ? ((int) $this->type) : "null").",";
1236 $sql .= " subtype=".(isset($this->subtype) ? $this->db->escape($this->subtype) : "null").",";
1237 $sql .= " fk_soc=".(isset($this->socid) ? ((int) $this->socid) : "null").",";
1238 $sql .= " datec=".(dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
1239 $sql .= " datef=".(dol_strlen($this->date) != 0 ? "'".$this->db->idate($this->date)."'" : 'null').",";
1240 if (dol_strlen($this->tms) != 0) {
1241 $sql .= " tms=".(dol_strlen($this->tms) != 0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
1242 }
1243 $sql .= " libelle=".(isset($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
1244 $sql .= " paye=".(isset($this->paye) ? ((int) $this->paye) : "0").",";
1245 $sql .= " close_code=".(isset($this->close_code) ? "'".$this->db->escape($this->close_code)."'" : "null").",";
1246 $sql .= " close_note=".(isset($this->close_note) ? "'".$this->db->escape($this->close_note)."'" : "null").",";
1247 $sql .= " localtax1=".(isset($this->localtax1) ? ((float) $this->localtax1) : "null").",";
1248 $sql .= " localtax2=".(isset($this->localtax2) ? ((float) $this->localtax2) : "null").",";
1249 $sql .= " total_ht=".(isset($this->total_ht) ? ((float) $this->total_ht) : "null").",";
1250 $sql .= " total_tva=".(isset($this->total_tva) ? ((float) $this->total_tva) : "null").",";
1251 $sql .= " total_ttc=".(isset($this->total_ttc) ? ((float) $this->total_ttc) : "null").",";
1252 $sql .= " fk_statut=".(isset($this->status) ? ((int) $this->status) : (isset($this->statut) ? ((int) $this->statut) : "null")).",";
1253 $sql .= " fk_user_author=".(isset($this->author) ? ((int) $this->author) : "null").",";
1254 $sql .= " fk_user_valid=".(isset($this->fk_user_valid) ? ((int) $this->fk_user_valid) : "null").",";
1255 $sql .= " fk_facture_source=".($this->fk_facture_source ? ((int) $this->fk_facture_source) : "null").",";
1256 $sql .= " vat_reverse_charge = ".($this->vat_reverse_charge != '' ? ((int) $this->db->escape($this->vat_reverse_charge)) : 0).",";
1257 $sql .= " fk_projet=".(!empty($this->fk_project) ? ((int) $this->fk_project) : "null").",";
1258 $sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? ((int) $this->cond_reglement_id) : "null").",";
1259 $sql .= " date_lim_reglement=".(dol_strlen($this->date_echeance) != 0 ? "'".$this->db->idate($this->date_echeance)."'" : 'null').",";
1260 $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
1261 $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
1262 $sql .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
1263 $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null");
1264 $sql .= " WHERE rowid=".((int) $this->id);
1265
1266 $this->db->begin();
1267
1268 dol_syslog(get_class($this)."::update", LOG_DEBUG);
1269 $resql = $this->db->query($sql);
1270
1271 if (!$resql) {
1272 $error++;
1273
1274 if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1275 $this->errors[] = $langs->trans('ErrorRefAlreadyExists');
1276 } else {
1277 $this->errors[] = "Error ".$this->db->lasterror();
1278 }
1279 }
1280
1281 if (!$error) {
1282 $result = $this->insertExtraFields();
1283 if ($result < 0) {
1284 $error++;
1285 }
1286 }
1287
1288 if (!$error) {
1289 if (!$notrigger) {
1290 // Call trigger
1291 $result = $this->call_trigger('BILL_SUPPLIER_MODIFY', $user);
1292 if ($result < 0) {
1293 $error++;
1294 }
1295 // End call triggers
1296 }
1297 }
1298
1299 // Commit or rollback
1300 if ($error) {
1301 foreach ($this->errors as $errmsg) {
1302 dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
1303 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1304 }
1305 $this->db->rollback();
1306 return -1 * $error;
1307 } else {
1308 $this->db->commit();
1309 return 1;
1310 }
1311 }
1312
1313 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1320 public function insert_discount($idremise)
1321 {
1322 // phpcs:enable
1323 global $conf, $langs;
1324
1325 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1326 include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
1327
1328 $this->db->begin();
1329
1330 $remise = new DiscountAbsolute($this->db);
1331 $result = $remise->fetch($idremise);
1332
1333 if ($result > 0) {
1334 if ($remise->fk_invoice_supplier) { // Protection against multiple submission
1335 $this->error = $langs->trans("ErrorDiscountAlreadyUsed");
1336 $this->db->rollback();
1337 return -5;
1338 }
1339
1340 $facligne = new SupplierInvoiceLine($this->db);
1341 $facligne->fk_facture_fourn = $this->id;
1342 $facligne->fk_remise_except = $remise->id;
1343 $facligne->desc = $remise->description; // Description ligne
1344 $facligne->vat_src_code = $remise->vat_src_code;
1345 $facligne->tva_tx = $remise->tva_tx;
1346 $facligne->subprice = -$remise->amount_ht;
1347 $facligne->fk_product = 0; // Id produit predefini
1348 $facligne->product_type = 0;
1349 $facligne->qty = 1;
1350 $facligne->remise_percent = 0;
1351 $facligne->rang = -1;
1352 $facligne->info_bits = 2;
1353
1354 if (getDolGlobalString('MAIN_ADD_LINE_AT_POSITION')) {
1355 $facligne->rang = 1;
1356 $linecount = count($this->lines);
1357 for ($ii = 1; $ii <= $linecount; $ii++) {
1358 $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii+1);
1359 }
1360 }
1361
1362 // Get buy/cost price of invoice that is source of discount
1363 if ($remise->fk_invoice_supplier_source > 0) {
1364 $srcinvoice = new FactureFournisseur($this->db);
1365 $srcinvoice->fetch($remise->fk_invoice_supplier_source);
1366 $totalcostpriceofinvoice = 0;
1367 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php'; // TODO Move this into commonobject
1368 $formmargin = new FormMargin($this->db);
1369 $arraytmp = $formmargin->getMarginInfosArray($srcinvoice, false);
1370 $facligne->pa_ht = $arraytmp['pa_total'];
1371 }
1372
1373 $facligne->total_ht = -$remise->amount_ht;
1374 $facligne->total_tva = -$remise->amount_tva;
1375 $facligne->total_ttc = -$remise->amount_ttc;
1376
1377 $facligne->multicurrency_subprice = -$remise->multicurrency_subprice;
1378 $facligne->multicurrency_total_ht = -$remise->multicurrency_total_ht;
1379 $facligne->multicurrency_total_tva = -$remise->multicurrency_total_tva;
1380 $facligne->multicurrency_total_ttc = -$remise->multicurrency_total_ttc;
1381
1382 $lineid = $facligne->insert();
1383 if ($lineid > 0) {
1384 $result = $this->update_price(1);
1385 if ($result > 0) {
1386 // Create link between discount and invoice line
1387 $result = $remise->link_to_invoice($lineid, 0);
1388 if ($result < 0) {
1389 $this->error = $remise->error;
1390 $this->db->rollback();
1391 return -4;
1392 }
1393
1394 $this->db->commit();
1395 return 1;
1396 } else {
1397 $this->error = $facligne->error;
1398 $this->db->rollback();
1399 return -1;
1400 }
1401 } else {
1402 $this->error = $facligne->error;
1403 $this->db->rollback();
1404 return -2;
1405 }
1406 } else {
1407 $this->db->rollback();
1408 return -3;
1409 }
1410 }
1411
1412
1420 public function delete(User $user, $notrigger = 0)
1421 {
1422 global $conf;
1423
1424 $rowid = $this->id;
1425
1426 dol_syslog("FactureFournisseur::delete rowid=".$rowid, LOG_DEBUG);
1427
1428 // TODO Test if there is at least on payment. If yes, refuse to delete.
1429
1430 $error = 0;
1431 $this->db->begin();
1432
1433 if (!$error && !$notrigger) {
1434 // Call trigger
1435 $result = $this->call_trigger('BILL_SUPPLIER_DELETE', $user);
1436 if ($result < 0) {
1437 $this->db->rollback();
1438 return -1;
1439 }
1440 // Fin appel triggers
1441 }
1442
1443 if (!$error) {
1444 // If invoice was converted into a discount not yet consumed, we remove discount
1445 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'societe_remise_except';
1446 $sql .= ' WHERE fk_invoice_supplier_source = '.((int) $rowid);
1447 $sql .= ' AND fk_invoice_supplier_line IS NULL';
1448 $resql = $this->db->query($sql);
1449
1450 // If invoice has consumned discounts
1451 $this->fetch_lines();
1452 $list_rowid_det = array();
1453 foreach ($this->lines as $key => $invoiceline) {
1454 $list_rowid_det[] = $invoiceline->rowid;
1455 }
1456
1457 // Consumned discounts are freed
1458 if (count($list_rowid_det)) {
1459 $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
1460 $sql .= ' SET fk_invoice_supplier = NULL, fk_invoice_supplier_line = NULL';
1461 $sql .= ' WHERE fk_invoice_supplier_line IN ('.$this->db->sanitize(join(',', $list_rowid_det)).')';
1462
1463 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1464 if (!$this->db->query($sql)) {
1465 $error++;
1466 }
1467 }
1468 }
1469
1470 if (!$error) {
1471 $main = MAIN_DB_PREFIX.'facture_fourn_det';
1472 $ef = $main."_extrafields";
1473 $sqlef = "DELETE FROM $ef WHERE fk_object IN (SELECT rowid FROM ".$main." WHERE fk_facture_fourn = ".((int) $rowid).")";
1474 $resqlef = $this->db->query($sqlef);
1475 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det WHERE fk_facture_fourn = '.((int) $rowid);
1476 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1477 $resql = $this->db->query($sql);
1478 if ($resqlef && $resql) {
1479 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn WHERE rowid = '.((int) $rowid);
1480 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1481 $resql2 = $this->db->query($sql);
1482 if (!$resql2) {
1483 $error++;
1484 }
1485 } else {
1486 $error++;
1487 }
1488 }
1489
1490 if (!$error) {
1491 // Delete linked object
1492 $res = $this->deleteObjectLinked();
1493 if ($res < 0) {
1494 $error++;
1495 }
1496 }
1497
1498 if (!$error) {
1499 // Delete record into ECM index (Note that delete is also done when deleting files with the dol_delete_dir_recursive
1500 $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
1501 $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive
1502
1503 // We remove directory
1504 if ($conf->fournisseur->facture->dir_output) {
1505 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1506
1507 $ref = dol_sanitizeFileName($this->ref);
1508 $dir = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$ref;
1509 $file = $dir."/".$ref.".pdf";
1510 if (file_exists($file)) {
1511 if (!dol_delete_file($file, 0, 0, 0, $this)) { // For triggers
1512 $this->error = 'ErrorFailToDeleteFile';
1513 $error++;
1514 }
1515 }
1516 if (file_exists($dir)) {
1517 $res = @dol_delete_dir_recursive($dir);
1518
1519 if (!$res) {
1520 $this->error = 'ErrorFailToDeleteDir';
1521 $error++;
1522 }
1523 }
1524 }
1525 }
1526
1527 // Remove extrafields
1528 if (!$error) {
1529 $result = $this->deleteExtraFields();
1530 if ($result < 0) {
1531 $error++;
1532 dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1533 }
1534 }
1535
1536 if (!$error) {
1537 dol_syslog(get_class($this)."::delete $this->id by $user->id", LOG_DEBUG);
1538 $this->db->commit();
1539 return 1;
1540 } else {
1541 $this->error = $this->db->lasterror();
1542 $this->db->rollback();
1543 return -$error;
1544 }
1545 }
1546
1547
1548 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1559 public function set_paid($user, $close_code = '', $close_note = '')
1560 {
1561 // phpcs:enable
1562 dol_syslog(get_class($this)."::set_paid is deprecated, use setPaid instead", LOG_NOTICE);
1563 return $this->setPaid($user, $close_code, $close_note);
1564 }
1565
1574 public function setPaid($user, $close_code = '', $close_note = '')
1575 {
1576 $error = 0;
1577
1578 if ($this->paye != 1) {
1579 $this->db->begin();
1580
1581 $now = dol_now();
1582
1583 dol_syslog("FactureFournisseur::setPaid", LOG_DEBUG);
1584
1585 $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn SET';
1586 $sql .= ' fk_statut = '.self::STATUS_CLOSED;
1587 if (!$close_code) {
1588 $sql .= ', paye=1';
1589 }
1590 if ($close_code) {
1591 $sql .= ", close_code='".$this->db->escape($close_code)."'";
1592 }
1593 if ($close_note) {
1594 $sql .= ", close_note='".$this->db->escape($close_note)."'";
1595 }
1596 $sql .= ', fk_user_closing = '.((int) $user->id);
1597 $sql .= ", date_closing = '".$this->db->idate($now)."'";
1598 $sql .= ' WHERE rowid = '.((int) $this->id);
1599
1600 $resql = $this->db->query($sql);
1601 if ($resql) {
1602 // Call trigger
1603 $result = $this->call_trigger('BILL_SUPPLIER_PAYED', $user);
1604 if ($result < 0) {
1605 $error++;
1606 }
1607 // End call triggers
1608 } else {
1609 $error++;
1610 $this->error = $this->db->error();
1611 dol_print_error($this->db);
1612 }
1613
1614 if (!$error) {
1615 $this->db->commit();
1616 return 1;
1617 } else {
1618 $this->db->rollback();
1619 return -1;
1620 }
1621 } else {
1622 return 0;
1623 }
1624 }
1625
1626 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1637 public function set_unpaid($user)
1638 {
1639 // phpcs:enable
1640 dol_syslog(get_class($this)."::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE);
1641 return $this->setUnpaid($user);
1642 }
1643
1652 public function setUnpaid($user)
1653 {
1654 $error = 0;
1655
1656 $this->db->begin();
1657
1658 $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn';
1659 $sql .= ' SET paye=0, fk_statut='.self::STATUS_VALIDATED.', close_code=null, close_note=null,';
1660 $sql .= ' date_closing=null,';
1661 $sql .= ' fk_user_closing=null';
1662 $sql .= ' WHERE rowid = '.((int) $this->id);
1663
1664 dol_syslog(get_class($this)."::set_unpaid", LOG_DEBUG);
1665 $resql = $this->db->query($sql);
1666 if ($resql) {
1667 // Call trigger
1668 $result = $this->call_trigger('BILL_SUPPLIER_UNPAYED', $user);
1669 if ($result < 0) {
1670 $error++;
1671 }
1672 // End call triggers
1673 } else {
1674 $error++;
1675 $this->error = $this->db->error();
1676 dol_print_error($this->db);
1677 }
1678
1679 if (!$error) {
1680 $this->db->commit();
1681 return 1;
1682 } else {
1683 $this->db->rollback();
1684 return -1;
1685 }
1686 }
1687
1698 public function setCanceled($user, $close_code = '', $close_note = '')
1699 {
1700 dol_syslog(get_class($this)."::setCanceled rowid=".((int) $this->id), LOG_DEBUG);
1701
1702 $this->db->begin();
1703
1704 $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn SET';
1705 $sql .= ' fk_statut='.self::STATUS_ABANDONED;
1706 if ($close_code) {
1707 $sql .= ", close_code='".$this->db->escape($close_code)."'";
1708 }
1709 if ($close_note) {
1710 $sql .= ", close_note='".$this->db->escape($close_note)."'";
1711 }
1712 $sql .= " WHERE rowid = ".((int) $this->id);
1713
1714 $resql = $this->db->query($sql);
1715 if ($resql) {
1716 // Bound discounts are deducted from the invoice
1717 // as they have not been used since the invoice is abandoned.
1718 $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
1719 $sql .= ' SET fk_invoice_supplier = NULL';
1720 $sql .= ' WHERE fk_invoice_supplier = '.((int) $this->id);
1721
1722 $resql = $this->db->query($sql);
1723 if ($resql) {
1724 // Call trigger
1725 $result = $this->call_trigger('BILL_SUPPLIER_CANCEL', $user);
1726 if ($result < 0) {
1727 $this->db->rollback();
1728 return -1;
1729 }
1730 // End call triggers
1731
1732 $this->db->commit();
1733 return 1;
1734 } else {
1735 $this->error = $this->db->error()." sql=".$sql;
1736 $this->db->rollback();
1737 return -1;
1738 }
1739 } else {
1740 $this->error = $this->db->error()." sql=".$sql;
1741 $this->db->rollback();
1742 return -2;
1743 }
1744 }
1745
1755 public function validate($user, $force_number = '', $idwarehouse = 0, $notrigger = 0)
1756 {
1757 global $mysoc, $conf, $langs;
1758
1759 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1760
1761 $now = dol_now();
1762
1763 $error = 0;
1764 dol_syslog(get_class($this).'::validate user='.$user->id.', force_number='.$force_number.', idwarehouse='.$idwarehouse);
1765
1766 // Force to have object complete for checks
1767 $this->fetch_thirdparty();
1768 $this->fetch_lines();
1769
1770 // Check parameters
1771 if ($this->statut > self::STATUS_DRAFT) { // This is to avoid to validate twice (avoid errors on logs and stock management)
1772 dol_syslog(get_class($this)."::validate no draft status", LOG_WARNING);
1773 return 0;
1774 }
1775 if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ').'/', $this->ref_supplier)) {
1776 $langs->load("errors");
1777 $this->error = $langs->trans("ErrorFieldFormat", $langs->transnoentities("RefSupplier")).'. '.$langs->trans('RemoveString', $langs->transnoentitiesnoconv("CopyOf"));
1778 return -1;
1779 }
1780 if (count($this->lines) <= 0) {
1781 $langs->load("errors");
1782 $this->error = $langs->trans("ErrorObjectMustHaveLinesToBeValidated", $this->ref);
1783 return -1;
1784 }
1785
1786 // Check for mandatory fields in thirdparty (defined into setup)
1787 if (!empty($this->thirdparty) && is_object($this->thirdparty)) {
1788 $array_to_check = array('IDPROF1', 'IDPROF2', 'IDPROF3', 'IDPROF4', 'IDPROF5', 'IDPROF6', 'EMAIL', 'ACCOUNTANCY_CODE_SUPPLIER');
1789 foreach ($array_to_check as $key) {
1790 $keymin = strtolower($key);
1791 if ($keymin == 'accountancy_code_supplier') {
1792 $keymin = 'code_compta_fournisseur';
1793 }
1794 if (!property_exists($this->thirdparty, $keymin)) {
1795 continue;
1796 }
1797 $vallabel = $this->thirdparty->$keymin;
1798
1799 $i = (int) preg_replace('/[^0-9]/', '', $key);
1800 if ($i > 0) {
1801 if ($this->thirdparty->isACompany()) {
1802 // Check for mandatory prof id (but only if country is other than ours)
1803 if ($mysoc->country_id > 0 && $this->thirdparty->country_id == $mysoc->country_id) {
1804 $idprof_mandatory = 'SOCIETE_'.$key.'_INVOICE_MANDATORY';
1805 if (!$vallabel && getDolGlobalString($idprof_mandatory)) {
1806 $langs->load("errors");
1807 $this->error = $langs->trans('ErrorProdIdIsMandatory', $langs->transcountry('ProfId'.$i, $this->thirdparty->country_code)).' ('.$langs->trans("ForbiddenBySetupRules").') ['.$langs->trans('Company').' : '.$this->thirdparty->name.']';
1808 dol_syslog(__METHOD__.' '.$this->error, LOG_ERR);
1809 return -1;
1810 }
1811 }
1812 }
1813 } else {
1814 if ($key == 'EMAIL') {
1815 // Check for mandatory
1816 if (getDolGlobalString('SOCIETE_EMAIL_INVOICE_MANDATORY') && !isValidEMail($this->thirdparty->email)) {
1817 $langs->load("errors");
1818 $this->error = $langs->trans("ErrorBadEMail", $this->thirdparty->email).' ('.$langs->trans("ForbiddenBySetupRules").') ['.$langs->trans('Company').' : '.$this->thirdparty->name.']';
1819 dol_syslog(__METHOD__.' '.$this->error, LOG_ERR);
1820 return -1;
1821 }
1822 } elseif ($key == 'ACCOUNTANCY_CODE_SUPPLIER') {
1823 // Check for mandatory
1824 if (getDolGlobalString('SOCIETE_ACCOUNTANCY_CODE_SUPPLIER_INVOICE_MANDATORY') && empty($this->thirdparty->code_compta_fournisseur)) {
1825 $langs->load("errors");
1826 $this->error = $langs->trans("ErrorAccountancyCodeSupplierIsMandatory", $this->thirdparty->name).' ('.$langs->trans("ForbiddenBySetupRules").')';
1827 dol_syslog(__METHOD__.' '.$this->error, LOG_ERR);
1828 return -1;
1829 }
1830 }
1831 }
1832 }
1833 }
1834
1835 $this->db->begin();
1836
1837 // Define new ref
1838 if ($force_number) {
1839 $num = $force_number;
1840 } elseif (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
1841 $num = $this->getNextNumRef($this->thirdparty);
1842 } else {
1843 $num = $this->ref;
1844 }
1845 $this->newref = dol_sanitizeFileName($num);
1846
1847 $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1848 $sql .= " SET ref='".$this->db->escape($num)."', fk_statut = 1, fk_user_valid = ".((int) $user->id).", date_valid = '".$this->db->idate($now)."'";
1849 $sql .= " WHERE rowid = ".((int) $this->id);
1850
1851 dol_syslog(get_class($this)."::validate", LOG_DEBUG);
1852 $resql = $this->db->query($sql);
1853 if ($resql) {
1854 // Si on incrémente le produit principal et ses composants à la validation de facture fournisseur
1855 if (!$error && isModEnabled('stock') && getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_BILL')) {
1856 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1857 $langs->load("agenda");
1858
1859 $cpt = count($this->lines);
1860 for ($i = 0; $i < $cpt; $i++) {
1861 if ($this->lines[$i]->fk_product > 0) {
1862 $mouvP = new MouvementStock($this->db);
1863 $mouvP->origin = &$this;
1864 $mouvP->setOrigin($this->element, $this->id);
1865 // We increase stock for product
1866 $up_ht_disc = $this->lines[$i]->subprice;
1867 if (!empty($this->lines[$i]->remise_percent) && !getDolGlobalString('STOCK_EXCLUDE_DISCOUNT_FOR_PMP')) {
1868 $up_ht_disc = price2num($up_ht_disc * (100 - $this->lines[$i]->remise_percent) / 100, 'MU');
1869 }
1871 $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1872 } else {
1873 $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1874 }
1875 if ($result < 0) {
1876 $this->error = $mouvP->error;
1877 if (count($mouvP->errors)) {
1878 $this->errors = $mouvP->errors;
1879 }
1880 return -2;
1881 }
1882 }
1883 }
1884 }
1885
1886 // Triggers call
1887 if (!$error && empty($notrigger)) {
1888 // Call trigger
1889 $result = $this->call_trigger('BILL_SUPPLIER_VALIDATE', $user);
1890 if ($result < 0) {
1891 $error++;
1892 }
1893 // End call triggers
1894 }
1895
1896 if (!$error) {
1897 $this->oldref = $this->ref;
1898
1899 // Rename directory if dir was a temporary ref
1900 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
1901 // Now we rename also files into index
1902 $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)."'";
1903 $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;
1904 $resql = $this->db->query($sql);
1905 if (!$resql) {
1906 $error++;
1907 $this->error = $this->db->lasterror();
1908 }
1909 $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)."'";
1910 $sql .= " WHERE filepath = 'fournisseur/facture/".get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1911 $resql = $this->db->query($sql);
1912 if (!$resql) {
1913 $error++;
1914 $this->error = $this->db->lasterror();
1915 }
1916
1917 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1918 $oldref = dol_sanitizeFileName($this->ref);
1919 $dirsource = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$oldref;
1920 $dirdest = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$this->newref;
1921 if (!$error && file_exists($dirsource)) {
1922 dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest);
1923
1924 if (@rename($dirsource, $dirdest)) {
1925 dol_syslog("Rename ok");
1926 // Rename docs starting with $oldref with $this->newref
1927 $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, '/'));
1928 foreach ($listoffiles as $fileentry) {
1929 $dirsource = $fileentry['name'];
1930 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $this->newref, $dirsource);
1931 $dirsource = $fileentry['path'].'/'.$dirsource;
1932 $dirdest = $fileentry['path'].'/'.$dirdest;
1933 @rename($dirsource, $dirdest);
1934 }
1935 }
1936 }
1937 }
1938 }
1939
1940 // Set new ref and define current statut
1941 if (!$error) {
1942 $this->ref = $this->newref;
1944 //$this->date_validation=$now; this is stored into log table
1945 }
1946
1947 if (!$error) {
1948 $this->db->commit();
1949 return 1;
1950 } else {
1951 $this->db->rollback();
1952 return -1;
1953 }
1954 } else {
1955 $this->error = $this->db->error();
1956 $this->db->rollback();
1957 return -1;
1958 }
1959 }
1960
1969 public function setDraft($user, $idwarehouse = -1, $notrigger = 0)
1970 {
1971 // phpcs:enable
1972 global $conf, $langs;
1973
1974 $error = 0;
1975
1976 if ($this->statut == self::STATUS_DRAFT) {
1977 dol_syslog(__METHOD__." already draft status", LOG_WARNING);
1978 return 0;
1979 }
1980
1981 dol_syslog(__METHOD__, LOG_DEBUG);
1982
1983 $this->db->begin();
1984
1985 $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1986 $sql .= " SET fk_statut = ".self::STATUS_DRAFT;
1987 $sql .= " WHERE rowid = ".((int) $this->id);
1988
1989 $result = $this->db->query($sql);
1990 if ($result) {
1991 if (!$error) {
1992 $this->oldcopy = clone $this;
1993 }
1994
1995 // Si on incremente le produit principal et ses composants a la validation de facture fournisseur, on decremente
1996 if ($result >= 0 && isModEnabled('stock') && getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_BILL')) {
1997 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1998 $langs->load("agenda");
1999
2000 $cpt = count($this->lines);
2001 for ($i = 0; $i < $cpt; $i++) {
2002 if ($this->lines[$i]->fk_product > 0) {
2003 $mouvP = new MouvementStock($this->db);
2004 $mouvP->origin = &$this;
2005 $mouvP->setOrigin($this->element, $this->id);
2006 // We increase stock for product
2008 $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
2009 } else {
2010 $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref));
2011 }
2012 }
2013 }
2014 }
2015 // Triggers call
2016 if (!$error && empty($notrigger)) {
2017 // Call trigger
2018 $result = $this->call_trigger('BILL_SUPPLIER_UNVALIDATE', $user);
2019 if ($result < 0) {
2020 $error++;
2021 }
2022 // End call triggers
2023 }
2024 if ($error == 0) {
2025 $this->db->commit();
2026 return 1;
2027 } else {
2028 $this->db->rollback();
2029 return -1;
2030 }
2031 } else {
2032 $this->error = $this->db->error();
2033 $this->db->rollback();
2034 return -1;
2035 }
2036 }
2037
2038
2072 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)
2073 {
2074 global $langs, $mysoc, $conf;
2075
2076 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);
2077 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2078
2079 if ($this->statut == self::STATUS_DRAFT) {
2080 // Clean parameters
2081 if (empty($remise_percent)) {
2082 $remise_percent = 0;
2083 }
2084 if (empty($qty)) {
2085 $qty = 0;
2086 }
2087 if (empty($info_bits)) {
2088 $info_bits = 0;
2089 }
2090 if (empty($rang)) {
2091 $rang = 0;
2092 }
2093 if (empty($ventil)) {
2094 $ventil = 0;
2095 }
2096 if (empty($txtva)) {
2097 $txtva = 0;
2098 }
2099 if (empty($txlocaltax1)) {
2100 $txlocaltax1 = 0;
2101 }
2102 if (empty($txlocaltax2)) {
2103 $txlocaltax2 = 0;
2104 }
2105
2106 $remise_percent = price2num($remise_percent);
2107 $qty = price2num($qty);
2108 $pu = price2num($pu);
2109 if (!preg_match('/\‍((.*)\‍)/', $txtva)) {
2110 $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
2111 }
2112 $txlocaltax1 = price2num($txlocaltax1);
2113 $txlocaltax2 = price2num($txlocaltax2);
2114
2115 if ($date_start && $date_end && $date_start > $date_end) {
2116 $langs->load("errors");
2117 $this->error = $langs->trans('ErrorStartDateGreaterEnd');
2118 return -1;
2119 }
2120
2121 $this->db->begin();
2122
2123 if ($fk_product > 0) {
2124 if (getDolGlobalString('SUPPLIER_INVOICE_WITH_PREDEFINED_PRICES_ONLY')) {
2125 // Check quantity is enough
2126 dol_syslog(get_class($this)."::addline we check supplier prices fk_product=".$fk_product." qty=".$qty." ref_supplier=".$ref_supplier);
2127 $prod = new ProductFournisseur($this->db);
2128 if ($prod->fetch($fk_product) > 0) {
2129 $product_type = $prod->type;
2130 $label = $prod->label;
2131 $fk_prod_fourn_price = 0;
2132
2133 // We use 'none' instead of $ref_supplier, because $ref_supplier may not exists anymore. So we will take the first supplier price ok.
2134 // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
2135 $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
2136 if ($result > 0) {
2137 if (empty($pu)) {
2138 $pu = $prod->fourn_pu; // Unit price supplier price set by get_buyprice
2139 }
2140 $ref_supplier = $prod->ref_supplier; // Ref supplier price set by get_buyprice
2141 // is remise percent not keyed but present for the product we add it
2142 if ($remise_percent == 0 && $prod->remise_percent != 0) {
2143 $remise_percent = $prod->remise_percent;
2144 }
2145 }
2146 if ($result == 0) { // If result == 0, we failed to found the supplier reference price
2147 $langs->load("errors");
2148 $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
2149 $this->db->rollback();
2150 dol_syslog(get_class($this)."::addline we did not found supplier price, so we can't guess unit price");
2151 //$pu = $prod->fourn_pu; // We do not overwrite unit price
2152 //$ref = $prod->ref_fourn; // We do not overwrite ref supplier price
2153 return -1;
2154 }
2155 if ($result == -1) {
2156 $langs->load("errors");
2157 $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
2158 $this->db->rollback();
2159 dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_DEBUG);
2160 return -1;
2161 }
2162 if ($result < -1) {
2163 $this->error = $prod->error;
2164 $this->db->rollback();
2165 dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_ERR);
2166 return -1;
2167 }
2168 } else {
2169 $this->error = $prod->error;
2170 $this->db->rollback();
2171 return -1;
2172 }
2173 }
2174 } else {
2175 $product_type = $type;
2176 }
2177
2178 if (isModEnabled("multicurrency") && $pu_devise > 0) {
2179 $pu = 0;
2180 }
2181
2182 $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $mysoc, $this->thirdparty);
2183
2184 // Clean vat code
2185 $reg = array();
2186 $vat_src_code = '';
2187 if (preg_match('/\‍((.*)\‍)/', $txtva, $reg)) {
2188 $vat_src_code = $reg[1];
2189 $txtva = preg_replace('/\s*\‍(.*\‍)/', '', $txtva); // Remove code into vatrate.
2190 }
2191
2192 // Calcul du total TTC et de la TVA pour la ligne a partir de
2193 // qty, pu, remise_percent et txtva
2194 // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2195 // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2196
2197 $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);
2198 $total_ht = $tabprice[0];
2199 $total_tva = $tabprice[1];
2200 $total_ttc = $tabprice[2];
2201 $total_localtax1 = $tabprice[9];
2202 $total_localtax2 = $tabprice[10];
2203 $pu_ht = $tabprice[3];
2204
2205 // MultiCurrency
2206 $multicurrency_total_ht = $tabprice[16];
2207 $multicurrency_total_tva = $tabprice[17];
2208 $multicurrency_total_ttc = $tabprice[18];
2209 $pu_ht_devise = $tabprice[19];
2210
2211 // Check parameters
2212 if ($type < 0) {
2213 return -1;
2214 }
2215
2216 if ($rang < 0) {
2217 $rangmax = $this->line_max();
2218 $rang = $rangmax + 1;
2219 }
2220
2221 // Insert line
2222 $supplierinvoiceline = new SupplierInvoiceLine($this->db);
2223
2224 $supplierinvoiceline->context = $this->context;
2225
2226 $supplierinvoiceline->fk_facture_fourn = $this->id;
2227 //$supplierinvoiceline->label=$label; // deprecated
2228 $supplierinvoiceline->desc = $desc;
2229 $supplierinvoiceline->ref_supplier = $ref_supplier;
2230
2231 $supplierinvoiceline->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs($qty) : $qty); // For credit note, quantity is always positive and unit price negative
2232 $supplierinvoiceline->subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2233
2234 $supplierinvoiceline->vat_src_code = $vat_src_code;
2235 $supplierinvoiceline->tva_tx = $txtva;
2236 $supplierinvoiceline->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
2237 $supplierinvoiceline->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
2238 $supplierinvoiceline->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
2239 $supplierinvoiceline->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
2240
2241 $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
2242 $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
2243 $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
2244 $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
2245 $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
2246
2247 $supplierinvoiceline->fk_product = $fk_product;
2248 $supplierinvoiceline->product_type = $type;
2249 $supplierinvoiceline->remise_percent = $remise_percent;
2250 $supplierinvoiceline->date_start = $date_start;
2251 $supplierinvoiceline->date_end = $date_end;
2252 $supplierinvoiceline->fk_code_ventilation = $ventil;
2253 $supplierinvoiceline->rang = $rang;
2254 $supplierinvoiceline->info_bits = $info_bits;
2255 $supplierinvoiceline->fk_remise_except = $fk_remise_except;
2256
2257
2258 $supplierinvoiceline->special_code = (string) $special_code;
2259 $supplierinvoiceline->fk_parent_line = $fk_parent_line;
2260 $supplierinvoiceline->origin = $this->origin;
2261 $supplierinvoiceline->origin_id = $origin_id;
2262 $supplierinvoiceline->fk_unit = $fk_unit;
2263
2264 // Multicurrency
2265 $supplierinvoiceline->fk_multicurrency = $this->fk_multicurrency;
2266 $supplierinvoiceline->multicurrency_code = $this->multicurrency_code;
2267 $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
2268
2269 $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
2270 $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
2271 $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
2272
2273 if (is_array($array_options) && count($array_options) > 0) {
2274 $supplierinvoiceline->array_options = $array_options;
2275 }
2276
2277 $result = $supplierinvoiceline->insert($notrigger);
2278 if ($result > 0) {
2279 // Reorder if child line
2280 if (!empty($fk_parent_line)) {
2281 $this->line_order(true, 'DESC');
2282 } elseif ($rang > 0 && $rang <= count($this->lines)) { // Update all rank of all other lines
2283 $linecount = count($this->lines);
2284 for ($ii = $rang; $ii <= $linecount; $ii++) {
2285 $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1);
2286 }
2287 }
2288
2289 // Mise a jour informations denormalisees au niveau de la facture meme
2290 $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.
2291 if ($result > 0) {
2292 $this->db->commit();
2293 return $supplierinvoiceline->id;
2294 } else {
2295 $this->error = $this->db->error();
2296 $this->db->rollback();
2297 return -1;
2298 }
2299 } else {
2300 $this->error = $supplierinvoiceline->error;
2301 $this->errors = $supplierinvoiceline->errors;
2302 $this->db->rollback();
2303 return -2;
2304 }
2305 } else {
2306 return 0;
2307 }
2308 }
2309
2335 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)
2336 {
2337 global $mysoc, $langs;
2338
2339 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);
2340 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2341
2342 $pu = price2num($pu);
2343 $qty = price2num($qty);
2344 $remise_percent = price2num($remise_percent);
2345 $pu_devise = price2num($pu_devise);
2346
2347 // Check parameters
2348 //if (! is_numeric($pu) || ! is_numeric($qty)) return -1;
2349 if ($type < 0) {
2350 return -1;
2351 }
2352
2353 if ($date_start && $date_end && $date_start > $date_end) {
2354 $langs->load("errors");
2355 $this->error = $langs->trans('ErrorStartDateGreaterEnd');
2356 return -1;
2357 }
2358
2359 // Clean parameters
2360 if (empty($vatrate)) {
2361 $vatrate = 0;
2362 }
2363 if (empty($txlocaltax1)) {
2364 $txlocaltax1 = 0;
2365 }
2366 if (empty($txlocaltax2)) {
2367 $txlocaltax2 = 0;
2368 }
2369
2370 $txlocaltax1 = price2num($txlocaltax1);
2371 $txlocaltax2 = price2num($txlocaltax2);
2372
2373 // Calcul du total TTC et de la TVA pour la ligne a partir de
2374 // qty, pu, remise_percent et txtva
2375 // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2376 // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2377
2378 $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $mysoc, $this->thirdparty);
2379
2380 $reg = array();
2381
2382 // Clean vat code
2383 $vat_src_code = '';
2384 if (preg_match('/\‍((.*)\‍)/', $vatrate, $reg)) {
2385 $vat_src_code = $reg[1];
2386 $vatrate = preg_replace('/\s*\‍(.*\‍)/', '', $vatrate); // Remove code into vatrate.
2387 }
2388
2389 $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);
2390 $total_ht = $tabprice[0];
2391 $total_tva = $tabprice[1];
2392 $total_ttc = $tabprice[2];
2393 $pu_ht = $tabprice[3];
2394 $pu_tva = $tabprice[4];
2395 $pu_ttc = $tabprice[5];
2396 $total_localtax1 = $tabprice[9];
2397 $total_localtax2 = $tabprice[10];
2398
2399 // MultiCurrency
2400 $multicurrency_total_ht = $tabprice[16];
2401 $multicurrency_total_tva = $tabprice[17];
2402 $multicurrency_total_ttc = $tabprice[18];
2403 $pu_ht_devise = $tabprice[19];
2404
2405 if (empty($info_bits)) {
2406 $info_bits = 0;
2407 }
2408
2409 //Fetch current line from the database and then clone the object and set it in $oldline property
2410 $line = new SupplierInvoiceLine($this->db);
2411 $line->fetch($id);
2412 $line->fetch_optionals();
2413
2414 $staticline = clone $line;
2415
2416 if ($idproduct) {
2417 $product = new Product($this->db);
2418 $result = $product->fetch($idproduct);
2419 $product_type = $product->type;
2420 } else {
2421 $idproduct = $staticline->fk_product;
2422 $product_type = $type;
2423 }
2424
2425 $line->oldline = $staticline;
2426 $line->context = $this->context;
2427
2428 $line->description = $desc;
2429
2430 $line->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs($qty) : $qty); // For credit note, quantity is always positive and unit price negative
2431 $line->subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2432 $line->pu_ht = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2433 $line->pu_ttc = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ttc) : $pu_ttc); // For credit note, unit price always negative, always positive otherwise
2434
2435 $line->remise_percent = $remise_percent;
2436 $line->ref_supplier = $ref_supplier;
2437
2438 $line->date_start = $date_start;
2439 $line->date_end = $date_end;
2440
2441 $line->vat_src_code = $vat_src_code;
2442 $line->tva_tx = $vatrate;
2443 $line->localtax1_tx = $txlocaltax1;
2444 $line->localtax2_tx = $txlocaltax2;
2445 $line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
2446 $line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
2447
2448 $line->total_ht = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_ht) : $total_ht);
2449 $line->total_tva = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_tva) : $total_tva);
2450 $line->total_localtax1 = $total_localtax1;
2451 $line->total_localtax2 = $total_localtax2;
2452 $line->total_ttc = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_ttc) : $total_ttc);
2453
2454 $line->fk_product = $idproduct;
2455 $line->product_type = $product_type;
2456 $line->info_bits = $info_bits;
2457 $line->fk_unit = $fk_unit;
2458 $line->rang = $rang;
2459
2460 if (is_array($array_options) && count($array_options) > 0) {
2461 // We replace values in this->line->array_options only for entries defined into $array_options
2462 foreach ($array_options as $key => $value) {
2463 $line->array_options[$key] = $array_options[$key];
2464 }
2465 }
2466
2467 // Multicurrency
2468 $line->multicurrency_subprice = $pu_ht_devise;
2469 $line->multicurrency_total_ht = $multicurrency_total_ht;
2470 $line->multicurrency_total_tva = $multicurrency_total_tva;
2471 $line->multicurrency_total_ttc = $multicurrency_total_ttc;
2472
2473 $res = $line->update($notrigger);
2474
2475 if ($res < 1) {
2476 $this->errors[] = $line->error;
2477 } else {
2478 // Update total price into invoice record
2479 $res = $this->update_price('1', 'auto', 0, $this->thirdparty);
2480 }
2481
2482 return $res;
2483 }
2484
2492 public function deleteline($rowid, $notrigger = 0)
2493 {
2494 if (!$rowid) {
2495 $rowid = $this->id;
2496 }
2497
2498 $this->db->begin();
2499
2500 // Free the discount linked to a line of invoice
2501 $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
2502 $sql .= ' SET fk_invoice_supplier_line = NULL';
2503 $sql .= ' WHERE fk_invoice_supplier_line = '.((int) $rowid);
2504
2505 dol_syslog(get_class($this)."::deleteline", LOG_DEBUG);
2506 $result = $this->db->query($sql);
2507 if (!$result) {
2508 $this->error = $this->db->error();
2509 $this->db->rollback();
2510 return -2;
2511 }
2512
2513 $line = new SupplierInvoiceLine($this->db);
2514
2515 if ($line->fetch($rowid) < 1) {
2516 return -1;
2517 }
2518
2519 $res = $line->delete($notrigger);
2520
2521 if ($res < 1) {
2522 $this->errors[] = $line->error;
2523 $this->db->rollback();
2524 return -3;
2525 } else {
2526 $res = $this->update_price(1);
2527
2528 if ($res > 0) {
2529 $this->db->commit();
2530 return 1;
2531 } else {
2532 $this->db->rollback();
2533 $this->error = $this->db->lasterror();
2534 return -4;
2535 }
2536 }
2537 }
2538
2539
2546 public function info($id)
2547 {
2548 $sql = 'SELECT c.rowid, datec, tms as datem, ';
2549 $sql .= ' fk_user_author, fk_user_modif, fk_user_valid';
2550 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as c';
2551 $sql .= ' WHERE c.rowid = '.((int) $id);
2552
2553 $result = $this->db->query($sql);
2554 if ($result) {
2555 if ($this->db->num_rows($result)) {
2556 $obj = $this->db->fetch_object($result);
2557
2558 $this->id = $obj->rowid;
2559
2560 $this->user_creation_id = $obj->fk_user_author;
2561 $this->user_validation_id = $obj->fk_user_valid;
2562 $this->user_modification_id = $obj->fk_user_modif;
2563 $this->date_creation = $this->db->jdate($obj->datec);
2564 $this->date_modification = $this->db->jdate($obj->datem);
2565 //$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)
2566 }
2567 $this->db->free($result);
2568 } else {
2569 dol_print_error($this->db);
2570 }
2571 }
2572
2573 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2582 public function list_replacable_supplier_invoices($socid = 0)
2583 {
2584 // phpcs:enable
2585 global $conf;
2586
2587 $return = array();
2588
2589 $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut,";
2590 $sql .= " ff.rowid as rowidnext";
2591 $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2592 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2593 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture_fourn as ff ON f.rowid = ff.fk_facture_source";
2594 $sql .= " WHERE (f.fk_statut = ".self::STATUS_VALIDATED." OR (f.fk_statut = ".self::STATUS_ABANDONED." AND f.close_code = '".self::CLOSECODE_ABANDONED."'))";
2595 $sql .= " AND f.entity = ".$conf->entity;
2596 $sql .= " AND f.paye = 0"; // Pas classee payee completement
2597 $sql .= " AND pf.fk_paiementfourn IS NULL"; // Aucun paiement deja fait
2598 $sql .= " AND ff.fk_statut IS NULL"; // Renvoi vrai si pas facture de remplacement
2599 if ($socid > 0) {
2600 $sql .= " AND f.fk_soc = ".((int) $socid);
2601 }
2602 $sql .= " ORDER BY f.ref";
2603
2604 dol_syslog(get_class($this)."::list_replacable_supplier_invoices", LOG_DEBUG);
2605 $resql = $this->db->query($sql);
2606 if ($resql) {
2607 while ($obj = $this->db->fetch_object($resql)) {
2608 $return[$obj->rowid] = array(
2609 'id' => $obj->rowid,
2610 'ref' => $obj->ref,
2611 'status' => $obj->fk_statut
2612 );
2613 }
2614 //print_r($return);
2615 return $return;
2616 } else {
2617 $this->error = $this->db->error();
2618 return -1;
2619 }
2620 }
2621
2622 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2632 public function list_qualified_avoir_supplier_invoices($socid = 0)
2633 {
2634 // phpcs:enable
2635 global $conf;
2636
2637 $return = array();
2638
2639 $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.subtype, f.paye, pf.fk_paiementfourn";
2640 $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2641 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2642 $sql .= " WHERE f.entity = ".$conf->entity;
2643 $sql .= " AND f.fk_statut in (".self::STATUS_VALIDATED.",".self::STATUS_CLOSED.")";
2644 $sql .= " AND NOT EXISTS (SELECT rowid from ".MAIN_DB_PREFIX."facture_fourn as ff WHERE f.rowid = ff.fk_facture_source";
2645 $sql .= " AND ff.type=".self::TYPE_REPLACEMENT.")";
2646 $sql .= " AND f.type != ".self::TYPE_CREDIT_NOTE; // Type non 2 si facture non avoir
2647 if ($socid > 0) {
2648 $sql .= " AND f.fk_soc = ".((int) $socid);
2649 }
2650 $sql .= " ORDER BY f.ref";
2651
2652 dol_syslog(get_class($this)."::list_qualified_avoir_supplier_invoices", LOG_DEBUG);
2653 $resql = $this->db->query($sql);
2654 if ($resql) {
2655 while ($obj = $this->db->fetch_object($resql)) {
2656 $qualified = 0;
2657 if ($obj->fk_statut == self::STATUS_VALIDATED) {
2658 $qualified = 1;
2659 }
2660 if ($obj->fk_statut == self::STATUS_CLOSED) {
2661 $qualified = 1;
2662 }
2663 if ($qualified) {
2664 $paymentornot = ($obj->fk_paiementfourn ? 1 : 0);
2665 $return[$obj->rowid] = array('ref'=>$obj->ref, 'status'=>$obj->fk_statut, 'type'=>$obj->type, 'paye'=>$obj->paye, 'paymentornot'=>$paymentornot);
2666 }
2667 }
2668
2669 return $return;
2670 } else {
2671 $this->error = $this->db->error();
2672 return -1;
2673 }
2674 }
2675
2676 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2683 public function load_board($user)
2684 {
2685 // phpcs:enable
2686 global $conf, $langs;
2687
2688 $sql = 'SELECT ff.rowid, ff.date_lim_reglement as datefin, ff.fk_statut as status, ff.total_ht, ff.total_ttc';
2689 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as ff';
2690 if (!$user->hasRight("societe", "client", "voir") && !$user->socid) {
2691 $sql .= " JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ff.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
2692 }
2693 $sql .= ' WHERE ff.paye = 0';
2694 $sql .= " AND ff.fk_statut IN (".self::STATUS_VALIDATED.")";
2695 $sql .= " AND ff.entity = ".$conf->entity;
2696 if ($user->socid) {
2697 $sql .= ' AND ff.fk_soc = '.((int) $user->socid);
2698 }
2699
2700 $resql = $this->db->query($sql);
2701 if ($resql) {
2702 $langs->load("bills");
2703 $now = dol_now();
2704
2705 $response = new WorkboardResponse();
2706 $response->warning_delay = $conf->facture->fournisseur->warning_delay / 60 / 60 / 24;
2707 $response->label = $langs->trans("SupplierBillsToPay");
2708 $response->labelShort = $langs->trans("StatusToPay");
2709
2710 $response->url = DOL_URL_ROOT.'/fourn/facture/list.php?search_status=1&mainmenu=billing&leftmenu=suppliers_bills';
2711 $response->img = img_object($langs->trans("Bills"), "bill");
2712
2713 $facturestatic = new FactureFournisseur($this->db);
2714
2715 while ($obj = $this->db->fetch_object($resql)) {
2716 $facturestatic->date_echeance = $this->db->jdate($obj->datefin);
2717 $facturestatic->statut = $obj->status; // For backward compatibility
2718 $facturestatic->status = $obj->status;
2719
2720 $response->nbtodo++;
2721 $response->total += $obj->total_ht;
2722
2723 if ($facturestatic->hasDelay()) {
2724 $response->nbtodolate++;
2725 $response->url_late = DOL_URL_ROOT.'/fourn/facture/list.php?search_option=late&mainmenu=billing&leftmenu=suppliers_bills';
2726 }
2727 }
2728
2729 $this->db->free($resql);
2730 return $response;
2731 } else {
2732 dol_print_error($this->db);
2733 $this->error = $this->db->error();
2734 return -1;
2735 }
2736 }
2737
2745 public function getTooltipContentArray($params)
2746 {
2747 global $conf, $langs, $mysoc;
2748
2749 $langs->load('bills');
2750
2751 $datas = [];
2752 $moretitle = $params['moretitle'] ?? '';
2753 $picto = $this->picto;
2754 if ($this->type == self::TYPE_REPLACEMENT) {
2755 $picto .= 'r'; // Replacement invoice
2756 }
2757 if ($this->type == self::TYPE_CREDIT_NOTE) {
2758 $picto .= 'a'; // Credit note
2759 }
2760 if ($this->type == self::TYPE_DEPOSIT) {
2761 $picto .= 'd'; // Deposit invoice
2762 }
2763
2764 $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("SupplierInvoice").'</u>';
2765 if ($this->type == self::TYPE_REPLACEMENT) {
2766 $datas['picto'] .= '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("InvoiceReplace").'</u>';
2767 } elseif ($this->type == self::TYPE_CREDIT_NOTE) {
2768 $datas['picto'] .= '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("CreditNote").'</u>';
2769 } elseif ($this->type == self::TYPE_DEPOSIT) {
2770 $datas['picto'] .= '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("Deposit").'</u>';
2771 }
2772 if (isset($this->status)) {
2773 $alreadypaid = -1;
2774 if (isset($this->alreadypaid)) {
2775 $alreadypaid = $this->alreadypaid;
2776 }
2777
2778 $datas['picto'] .= ' '.$this->getLibStatut(5, $alreadypaid);
2779 }
2780 if ($moretitle) {
2781 $datas['picto'] .= ' - '.$moretitle;
2782 }
2783 if (!empty($this->ref)) {
2784 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
2785 }
2786 if (!empty($this->ref_supplier)) {
2787 $datas['refsupplier'] = '<br><b>'.$langs->trans('RefSupplier').':</b> '.$this->ref_supplier;
2788 }
2789 if (!empty($this->label)) {
2790 $datas['label'] = '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
2791 }
2792 if (!empty($this->date)) {
2793 $datas['date'] = '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
2794 }
2795 if (!empty($this->date_echeance)) {
2796 $datas['date_echeance'] = '<br><b>'.$langs->trans('DateDue').':</b> '.dol_print_date($this->date_echeance, 'day');
2797 }
2798 if (!empty($this->total_ht)) {
2799 $datas['amountht'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
2800 }
2801 if (!empty($this->total_tva)) {
2802 $datas['totaltva'] = '<br><b>'.$langs->trans('AmountVAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
2803 }
2804 if (!empty($this->total_localtax1) && $this->total_localtax1 != 0) {
2805 // We keep test != 0 because $this->total_localtax1 can be '0.00000000'
2806 $datas['amountlt1'] = '<br><b>'.$langs->transcountry('AmountLT1', $mysoc->country_code).':</b> '.price($this->total_localtax1, 0, $langs, 0, -1, -1, $conf->currency);
2807 }
2808 if (!empty($this->total_localtax2) && $this->total_localtax2 != 0) {
2809 $datas['amountlt2'] = '<br><b>'.$langs->transcountry('AmountLT2', $mysoc->country_code).':</b> '.price($this->total_localtax2, 0, $langs, 0, -1, -1, $conf->currency);
2810 }
2811 if (!empty($this->revenuestamp)) {
2812 $datas['amountrevenustamp'] = '<br><b>'.$langs->trans('RevenueStamp').':</b> '.price($this->revenuestamp, 0, $langs, 0, -1, -1, $conf->currency);
2813 }
2814 if (!empty($this->total_ttc)) {
2815 $datas['totalttc'] = '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
2816 }
2817 return $datas;
2818 }
2819
2833 public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
2834 {
2835 global $langs, $conf, $user, $hookmanager;
2836
2837 $result = '';
2838
2839 if ($option == 'withdraw') {
2840 $url = DOL_URL_ROOT.'/compta/facture/prelevement.php?facid='.$this->id.'&type=bank-transfer';
2841 } elseif ($option == 'document') {
2842 $url = DOL_URL_ROOT.'/fourn/facture/document.php?facid='.$this->id;
2843 } else {
2844 $url = DOL_URL_ROOT.'/fourn/facture/card.php?facid='.$this->id;
2845 }
2846
2847 if ($short) {
2848 return $url;
2849 }
2850
2851 if ($option !== 'nolink') {
2852 // Add param to save lastsearch_values or not
2853 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
2854 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
2855 $add_save_lastsearch_values = 1;
2856 }
2857 if ($add_save_lastsearch_values) {
2858 $url .= '&save_lastsearch_values=1';
2859 }
2860 }
2861
2862 $picto = $this->picto;
2863 if ($this->type == self::TYPE_REPLACEMENT) {
2864 $picto .= 'r'; // Replacement invoice
2865 }
2866 if ($this->type == self::TYPE_CREDIT_NOTE) {
2867 $picto .= 'a'; // Credit note
2868 }
2869 if ($this->type == self::TYPE_DEPOSIT) {
2870 $picto .= 'd'; // Deposit invoice
2871 }
2872 $params = [
2873 'id' => $this->id,
2874 'objecttype' => $this->element,
2875 'option' => $option,
2876 'moretitle' => $moretitle,
2877 ];
2878 $classfortooltip = 'classfortooltip';
2879 $dataparams = '';
2880 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
2881 $classfortooltip = 'classforajaxtooltip';
2882 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
2883 $label = '';
2884 } else {
2885 $label = implode($this->getTooltipContentArray($params));
2886 }
2887
2888 $ref = $this->ref;
2889 if (empty($ref)) {
2890 $ref = $this->id;
2891 }
2892
2893 $linkclose = '';
2894 if (empty($notooltip)) {
2895 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2896 $label = $langs->trans("ShowSupplierInvoice");
2897 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
2898 }
2899 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
2900 $linkclose .= $dataparams.' class="'.$classfortooltip.'"';
2901 }
2902
2903 $linkstart = '<a href="'.$url.'"';
2904 $linkstart .= $linkclose.'>';
2905 $linkend = '</a>';
2906
2907 $result .= $linkstart;
2908 if ($withpicto) {
2909 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'"'), 0, 0, $notooltip ? 0 : 1);
2910 }
2911 if ($withpicto != 2) {
2912 $result .= ($max ? dol_trunc($ref, $max) : $ref);
2913 }
2914 $result .= $linkend;
2915
2916 if ($addlinktonotes) {
2917 $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
2918 if ($txttoshow) {
2919 $notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
2920 $result .= ' <span class="note inline-block">';
2921 $result .= '<a href="'.DOL_URL_ROOT.'/fourn/facture/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
2922 $result .= img_picto('', 'note');
2923 $result .= '</a>';
2924 $result .= '</span>';
2925 }
2926 }
2927 global $action;
2928 $hookmanager->initHooks(array($this->element . 'dao'));
2929 $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
2930 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2931 if ($reshook > 0) {
2932 $result = $hookmanager->resPrint;
2933 } else {
2934 $result .= $hookmanager->resPrint;
2935 }
2936 return $result;
2937 }
2938
2947 public function getNextNumRef($soc, $mode = 'next')
2948 {
2949 global $db, $langs, $conf;
2950 $langs->load("orders");
2951
2952 // Clean parameters (if not defined or using deprecated value)
2953 if (!getDolGlobalString('INVOICE_SUPPLIER_ADDON_NUMBER')) {
2954 $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER = 'mod_facture_fournisseur_cactus';
2955 }
2956
2957 $mybool = false;
2958
2959 $file = getDolGlobalString('INVOICE_SUPPLIER_ADDON_NUMBER') . ".php";
2960 $classname = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER;
2961
2962 // Include file with class
2963 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2964
2965 foreach ($dirmodels as $reldir) {
2966 $dir = dol_buildpath($reldir."core/modules/supplier_invoice/");
2967
2968 // Load file with numbering class (if found)
2969 $mybool |= @include_once $dir.$file;
2970 }
2971
2972 if ($mybool === false) {
2973 dol_print_error('', "Failed to include file ".$file);
2974 return '';
2975 }
2976
2977 $obj = new $classname();
2978 $numref = "";
2979 $numref = $obj->getNumRef($soc, $this, $mode);
2980
2981 if ($numref != "") {
2982 return $numref;
2983 } else {
2984 $this->error = $obj->error;
2985 return -1;
2986 }
2987 }
2988
2989
2998 public function initAsSpecimen($option = '')
2999 {
3000 global $langs, $conf;
3001 include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
3002
3003 $now = dol_now();
3004
3005 // Load array of products prodids
3006 $num_prods = 0;
3007 $prodids = array();
3008
3009 $sql = "SELECT rowid";
3010 $sql .= " FROM ".MAIN_DB_PREFIX."product";
3011 $sql .= " WHERE entity IN (".getEntity('product').")";
3012 $sql .= $this->db->plimit(100);
3013
3014 $resql = $this->db->query($sql);
3015 if ($resql) {
3016 $num_prods = $this->db->num_rows($resql);
3017 $i = 0;
3018 while ($i < $num_prods) {
3019 $i++;
3020 $row = $this->db->fetch_row($resql);
3021 $prodids[$i] = $row[0];
3022 }
3023 }
3024
3025 // Initialise parametres
3026 $this->id = 0;
3027 $this->ref = 'SPECIMEN';
3028 $this->ref_supplier = 'SUPPLIER_REF_SPECIMEN';
3029 $this->specimen = 1;
3030 $this->socid = 1;
3031 $this->date = $now;
3032 $this->date_lim_reglement = $this->date + 3600 * 24 * 30;
3033 $this->cond_reglement_code = 'RECEP';
3034 $this->mode_reglement_code = 'CHQ';
3035
3036 $this->note_public = 'This is a comment (public)';
3037 $this->note_private = 'This is a comment (private)';
3038
3039 $this->multicurrency_tx = 1;
3040 $this->multicurrency_code = $conf->currency;
3041
3042 $xnbp = 0;
3043 if (empty($option) || $option != 'nolines') {
3044 // Lines
3045 $nbp = 5;
3046 while ($xnbp < $nbp) {
3047 $line = new SupplierInvoiceLine($this->db);
3048 $line->desc = $langs->trans("Description")." ".$xnbp;
3049 $line->qty = 1;
3050 $line->subprice = 100;
3051 $line->pu_ht = 100; // the canelle template use pu_ht and not subprice
3052 $line->price = 100;
3053 $line->tva_tx = 19.6;
3054 $line->localtax1_tx = 0;
3055 $line->localtax2_tx = 0;
3056 if ($xnbp == 2) {
3057 $line->total_ht = 50;
3058 $line->total_ttc = 59.8;
3059 $line->total_tva = 9.8;
3060 $line->remise_percent = 50;
3061 } else {
3062 $line->total_ht = 100;
3063 $line->total_ttc = 119.6;
3064 $line->total_tva = 19.6;
3065 $line->remise_percent = 0;
3066 }
3067
3068 if ($num_prods > 0) {
3069 $prodid = mt_rand(1, $num_prods);
3070 $line->fk_product = $prodids[$prodid];
3071 }
3072 $line->product_type = 0;
3073
3074 $this->lines[$xnbp] = $line;
3075
3076 $this->total_ht += $line->total_ht;
3077 $this->total_tva += $line->total_tva;
3078 $this->total_ttc += $line->total_ttc;
3079
3080 $xnbp++;
3081 }
3082 }
3083
3084 $this->total_ht = $xnbp * 100;
3085 $this->total_tva = $xnbp * 19.6;
3086 $this->total_ttc = $xnbp * 119.6;
3087 }
3088
3089 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3095 public function load_state_board()
3096 {
3097 // phpcs:enable
3098 global $conf, $user;
3099
3100 $this->nb = array();
3101
3102 $clause = "WHERE";
3103
3104 $sql = "SELECT count(f.rowid) as nb";
3105 $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
3106 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
3107 if (!$user->hasRight("societe", "client", "voir") && !$user->socid) {
3108 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
3109 $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3110 $clause = "AND";
3111 }
3112 $sql .= " ".$clause." f.entity = ".$conf->entity;
3113
3114 $resql = $this->db->query($sql);
3115 if ($resql) {
3116 while ($obj = $this->db->fetch_object($resql)) {
3117 $this->nb["supplier_invoices"] = $obj->nb;
3118 }
3119 $this->db->free($resql);
3120 return 1;
3121 } else {
3122 dol_print_error($this->db);
3123 $this->error = $this->db->error();
3124 return -1;
3125 }
3126 }
3127
3136 public function createFromClone(User $user, $fromid, $invertdetail = 0)
3137 {
3138 global $conf, $langs;
3139
3140 $error = 0;
3141
3142 $object = new FactureFournisseur($this->db);
3143
3144 $this->db->begin();
3145
3146 // Load source object
3147 $object->fetch($fromid);
3148 $object->id = 0;
3149 $object->statut = self::STATUS_DRAFT; // For backward compatibility
3150 $object->status = self::STATUS_DRAFT;
3151
3152 $object->fetch_thirdparty(); // We need it to recalculate VAT localtaxes according to main sale taxes and vendor
3153
3154 // Clear fields
3155 $object->ref_supplier = (empty($this->ref_supplier) ? $langs->trans("CopyOf").' '.$object->ref_supplier : $this->ref_supplier);
3156 $object->author = $user->id;
3157 $object->user_validation_id = 0;
3158 $object->fk_facture_source = 0;
3159 $object->date_creation = '';
3160 $object->date_validation = '';
3161 $object->date = (empty($this->date) ? dol_now() : $this->date);
3162 $object->ref_client = '';
3163 $object->close_code = '';
3164 $object->close_note = '';
3165 if (getDolGlobalInt('MAIN_DONT_KEEP_NOTE_ON_CLONING') == 1) {
3166 $object->note_private = '';
3167 $object->note_public = '';
3168 }
3169
3170 $object->date_echeance = $object->calculate_date_lim_reglement();
3171
3172 // Loop on each line of new invoice
3173 foreach ($object->lines as $i => $line) {
3174 if (isset($object->lines[$i]->info_bits) && ($object->lines[$i]->info_bits & 0x02) == 0x02) { // We do not clone line of discounts
3175 unset($object->lines[$i]);
3176 }
3177 }
3178
3179 // Create clone
3180 $object->context['createfromclone'] = 'createfromclone';
3181 $result = $object->create($user);
3182
3183 // Other options
3184 if ($result < 0) {
3185 $this->error = $object->error;
3186 $this->errors = $object->errors;
3187 $error++;
3188 }
3189
3190 if (!$error) {
3191 }
3192
3193 unset($object->context['createfromclone']);
3194
3195 // End
3196 if (!$error) {
3197 $this->db->commit();
3198 return $object->id;
3199 } else {
3200 $this->db->rollback();
3201 return -1;
3202 }
3203 }
3204
3216 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
3217 {
3218 global $conf, $user, $langs;
3219
3220 $langs->load("suppliers");
3221 $outputlangs->load("products");
3222
3223 // Set the model on the model name to use
3224 if (empty($modele)) {
3225 if (getDolGlobalString('INVOICE_SUPPLIER_ADDON_PDF')) {
3226 $modele = $conf->global->INVOICE_SUPPLIER_ADDON_PDF;
3227 } else {
3228 $modele = ''; // No default value. For supplier invoice, we allow to disable all PDF generation
3229 }
3230 }
3231
3232 if (empty($modele)) {
3233 return 0;
3234 } else {
3235 $modelpath = "core/modules/supplier_invoice/doc/";
3236
3237 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
3238 }
3239 }
3240
3245 public function getRights()
3246 {
3247 global $user;
3248
3249 return $user->hasRight("fournisseur", "facture");
3250 }
3251
3260 public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
3261 {
3262 $tables = array(
3263 'facture_fourn'
3264 );
3265
3266 return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
3267 }
3268
3277 public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
3278 {
3279 $tables = array(
3280 'facture_fourn_det'
3281 );
3282
3283 return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
3284 }
3285
3291 public function hasDelay()
3292 {
3293 global $conf;
3294
3295 $now = dol_now();
3296
3297 if (!$this->date_echeance) {
3298 return false;
3299 }
3300
3301 $status = isset($this->status) ? $this->status : $this->statut;
3302
3303 return ($status == self::STATUS_VALIDATED) && ($this->date_echeance < ($now - $conf->facture->fournisseur->warning_delay));
3304 }
3305
3311 public function isCreditNoteUsed()
3312 {
3313 $isUsed = false;
3314
3315 $sql = "SELECT fk_invoice_supplier FROM ".MAIN_DB_PREFIX."societe_remise_except WHERE fk_invoice_supplier_source = ".((int) $this->id);
3316 $resql = $this->db->query($sql);
3317 if (!empty($resql)) {
3318 $obj = $this->db->fetch_object($resql);
3319 if (!empty($obj->fk_invoice_supplier)) {
3320 $isUsed = true;
3321 }
3322 }
3323
3324 return $isUsed;
3325 }
3333 public function getKanbanView($option = '', $arraydata = null)
3334 {
3335 global $langs;
3336
3337 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
3338
3339 $return = '<div class="box-flex-item box-flex-grow-zero">';
3340 $return .= '<div class="info-box info-box-sm">';
3341 $return .= '<span class="info-box-icon bg-infobox-action">';
3342 $return .= img_picto('', $this->picto);
3343 $return .= '</span>';
3344 $return .= '<div class="info-box-content">';
3345 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
3346 if ($selected >= 0) {
3347 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
3348 }
3349 if (!empty($arraydata['thirdparty'])) {
3350 $return .= '<br><span class="info-box-label">'.$arraydata['thirdparty'].'</span>';
3351 }
3352 if (property_exists($this, 'date')) {
3353 $return .= '<br><span class="info-box-label">'.dol_print_date($this->date, 'day').'</span>';
3354 }
3355 if (property_exists($this, 'total_ht')) {
3356 $return .= ' &nbsp; <span class="info-box-label amount" title="'.dol_escape_htmltag($langs->trans("AmountHT")).'">'.price($this->total_ht);
3357 $return .= ' '.$langs->trans("HT");
3358 $return .= '</span>';
3359 }
3360 if (method_exists($this, 'getLibStatut')) {
3361 $alreadypaid = (empty($arraydata['alreadypaid']) ? 0 : $arraydata['alreadypaid']);
3362 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3, $alreadypaid).'</div>';
3363 }
3364 $return .= '</div>';
3365 $return .= '</div>';
3366 $return .= '</div>';
3367 return $return;
3368 }
3369
3376 public function setVATReverseCharge($vatreversecharge)
3377 {
3378 if (!$this->table_element) {
3379 dol_syslog(get_class($this)."::setVATReverseCharge was called on objet with property table_element not defined", LOG_ERR);
3380 return -1;
3381 }
3382
3383 dol_syslog(get_class($this).'::setVATReverseCharge('.$vatreversecharge.')');
3384
3385 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3386 $sql .= " SET vat_reverse_charge = ".((int) $vatreversecharge);
3387 $sql .= " WHERE rowid=".((int) $this->id);
3388
3389 if ($this->db->query($sql)) {
3390 $this->vat_reverse_charge = ($vatreversecharge == 0) ? 0 : 1;
3391 return 1;
3392 } else {
3393 dol_syslog(get_class($this).'::setVATReverseCharge Error ', LOG_DEBUG);
3394 $this->error = $this->db->error();
3395 return 0;
3396 }
3397 }
3398}
3399
3400
3401
3406{
3410 public $element = 'facture_fourn_det';
3411
3415 public $table_element = 'facture_fourn_det';
3416
3417 public $oldline;
3418
3423 public $ref;
3424
3429 public $product_ref;
3430
3436 public $ref_supplier;
3437
3442 public $product_desc;
3443
3450 public $pu_ht;
3451
3456 public $subprice;
3457
3462 public $pu_ttc;
3463
3464
3469 public $fk_facture_fourn;
3470
3476 public $label;
3477
3482 public $description;
3483
3484 public $date_start;
3485 public $date_end;
3486
3487 public $skip_update_total; // Skip update price total for special lines
3488
3492 public $situation_percent;
3493
3497 public $fk_prev_id;
3498
3503 public $vat_src_code;
3504
3509 public $tva_tx;
3510
3515 public $localtax1_tx;
3516
3521 public $localtax2_tx;
3522
3527 public $qty;
3528
3533 public $remise_percent;
3534
3539 public $pa_ht;
3540
3545 public $total_ht;
3546
3551 public $total_ttc;
3552
3557 public $total_tva;
3558
3563 public $total_localtax1;
3564
3569 public $total_localtax2;
3570
3574 public $fk_product;
3575
3580 public $product_type;
3581
3586 public $product_label;
3587
3594 public $info_bits;
3595
3600 public $fk_remise_except;
3601
3605 public $fk_parent_line;
3606
3607 public $special_code;
3608
3612 public $rang;
3613
3618 public $localtax1_type;
3619
3624 public $localtax2_type;
3625
3626
3632 public function __construct($db)
3633 {
3634 $this->db = $db;
3635 }
3636
3643 public function fetch($rowid)
3644 {
3645 $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';
3646 $sql .= ', f.localtax1_type, f.localtax2_type, f.localtax1_tx, f.localtax2_tx, f.total_localtax1, f.total_localtax2, f.fk_remise_except';
3647 $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';
3648 $sql .= ', p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.description as product_desc';
3649 $sql .= ', f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, multicurrency_total_ttc';
3650 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
3651 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
3652 $sql .= ' WHERE f.rowid = '.((int) $rowid);
3653 $sql .= ' ORDER BY f.rang, f.rowid';
3654
3655 $query = $this->db->query($sql);
3656
3657 if (!$query) {
3658 $this->errors[] = $this->db->error();
3659 return -1;
3660 }
3661
3662 if (!$this->db->num_rows($query)) {
3663 return 0;
3664 }
3665
3666 $obj = $this->db->fetch_object($query);
3667
3668 $this->id = $obj->rowid;
3669 $this->rowid = $obj->rowid;
3670 $this->fk_facture_fourn = $obj->fk_facture_fourn;
3671 $this->description = $obj->description;
3672 $this->date_start = $obj->date_start;
3673 $this->date_end = $obj->date_end;
3674 $this->product_ref = $obj->product_ref;
3675 $this->ref_supplier = $obj->ref_supplier;
3676 $this->product_desc = $obj->product_desc;
3677
3678 $this->subprice = $obj->pu_ht;
3679 $this->pu_ht = $obj->pu_ht;
3680 $this->pu_ttc = $obj->pu_ttc;
3681 $this->tva_tx = $obj->tva_tx;
3682 $this->localtax1_tx = $obj->localtax1_tx;
3683 $this->localtax2_tx = $obj->localtax2_tx;
3684 $this->localtax1_type = $obj->localtax1_type;
3685 $this->localtax2_type = $obj->localtax2_type;
3686
3687 $this->qty = $obj->qty;
3688 $this->remise_percent = $obj->remise_percent;
3689 $this->fk_remise_except = $obj->fk_remise_except;
3690 //$this->tva = $obj->total_tva; // deprecated
3691 $this->total_ht = $obj->total_ht;
3692 $this->total_tva = $obj->total_tva;
3693 $this->total_localtax1 = $obj->total_localtax1;
3694 $this->total_localtax2 = $obj->total_localtax2;
3695 $this->total_ttc = $obj->total_ttc;
3696 $this->fk_product = $obj->fk_product;
3697 $this->product_type = $obj->product_type;
3698 $this->product_label = $obj->product_label;
3699 $this->info_bits = $obj->info_bits;
3700 $this->fk_parent_line = $obj->fk_parent_line;
3701 $this->special_code = $obj->special_code;
3702 $this->rang = $obj->rang;
3703 $this->fk_unit = $obj->fk_unit;
3704
3705 $this->multicurrency_subprice = $obj->multicurrency_subprice;
3706 $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
3707 $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
3708 $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
3709
3710 $this->fetch_optionals();
3711
3712 return 1;
3713 }
3714
3721 public function delete($notrigger = 0)
3722 {
3723 global $user;
3724
3725 dol_syslog(get_class($this)."::deleteline rowid=".((int) $this->id), LOG_DEBUG);
3726
3727 $error = 0;
3728
3729 $this->db->begin();
3730
3731 if (!$notrigger) {
3732 if ($this->call_trigger('LINEBILL_SUPPLIER_DELETE', $user) < 0) {
3733 $error++;
3734 }
3735 }
3736
3737 $this->deleteObjectLinked();
3738
3739 // Remove extrafields
3740 if (!$error) {
3741 $result = $this->deleteExtraFields();
3742 if ($result < 0) {
3743 $error++;
3744 dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
3745 }
3746 }
3747
3748 if (!$error) {
3749 // Supprime ligne
3750 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det ';
3751 $sql .= " WHERE rowid = ".((int) $this->id);
3752 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
3753 $resql = $this->db->query($sql);
3754 if (!$resql) {
3755 $error++;
3756 $this->error = $this->db->lasterror();
3757 }
3758 }
3759
3760 if (!$error) {
3761 $this->db->commit();
3762 return 1;
3763 } else {
3764 $this->db->rollback();
3765 return -1;
3766 }
3767 }
3768
3775 public function update($notrigger = 0)
3776 {
3777 global $conf;
3778
3779 $pu = price2num($this->pu_ht);
3780 $qty = price2num($this->qty);
3781
3782 // Check parameters
3783 if (empty($this->qty)) {
3784 $this->qty = 0;
3785 }
3786
3787 if ($this->product_type < 0) {
3788 return -1;
3789 }
3790
3791 // Clean parameters
3792 if (empty($this->remise_percent)) {
3793 $this->remise_percent = 0;
3794 }
3795 if (empty($this->tva_tx)) {
3796 $this->tva_tx = 0;
3797 }
3798 if (empty($this->localtax1_tx)) {
3799 $this->localtax1_tx = 0;
3800 }
3801 if (empty($this->localtax2_tx)) {
3802 $this->localtax2_tx = 0;
3803 }
3804
3805 if (empty($this->pa_ht)) {
3806 $this->pa_ht = 0;
3807 }
3808 if (empty($this->multicurrency_subprice)) {
3809 $this->multicurrency_subprice = 0;
3810 }
3811 if (empty($this->multicurrency_total_ht)) {
3812 $this->multicurrency_total_ht = 0;
3813 }
3814 if (empty($this->multicurrency_total_tva)) {
3815 $this->multicurrency_total_tva = 0;
3816 }
3817 if (empty($this->multicurrency_total_ttc)) {
3818 $this->multicurrency_total_ttc = 0;
3819 }
3820
3821 $fk_product = (int) $this->fk_product;
3822 $fk_unit = (int) $this->fk_unit;
3823
3824 $this->db->begin();
3825
3826 $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
3827 $sql .= " description = '".$this->db->escape($this->description)."'";
3828 $sql .= ", ref = '".$this->db->escape($this->ref_supplier ? $this->ref_supplier : $this->ref)."'";
3829 $sql .= ", date_start = ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : "null");
3830 $sql .= ", date_end = ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : "null");
3831 $sql .= ", pu_ht = ".price2num($this->pu_ht);
3832 $sql .= ", pu_ttc = ".price2num($this->pu_ttc);
3833 $sql .= ", qty = ".price2num($this->qty);
3834 $sql .= ", remise_percent = ".price2num($this->remise_percent);
3835 if ($this->fk_remise_except > 0) {
3836 $sql .= ", fk_remise_except=".((int) $this->fk_remise_except);
3837 } else {
3838 $sql .= ", fk_remise_except=null";
3839 }
3840 $sql .= ", vat_src_code = '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."'";
3841 $sql .= ", tva_tx = ".price2num($this->tva_tx);
3842 $sql .= ", localtax1_tx = ".price2num($this->localtax1_tx);
3843 $sql .= ", localtax2_tx = ".price2num($this->localtax2_tx);
3844 $sql .= ", localtax1_type = '".$this->db->escape($this->localtax1_type)."'";
3845 $sql .= ", localtax2_type = '".$this->db->escape($this->localtax2_type)."'";
3846 $sql .= ", total_ht = ".price2num($this->total_ht);
3847 $sql .= ", tva= ".price2num($this->total_tva);
3848 $sql .= ", total_localtax1= ".price2num($this->total_localtax1);
3849 $sql .= ", total_localtax2= ".price2num($this->total_localtax2);
3850 $sql .= ", total_ttc = ".price2num($this->total_ttc);
3851 $sql .= ", fk_product = ".($fk_product > 0 ? (int) $fk_product : 'null');
3852 $sql .= ", product_type = ".((int) $this->product_type);
3853 $sql .= ", info_bits = ".((int) $this->info_bits);
3854 $sql .= ", fk_unit = ".($fk_unit > 0 ? (int) $fk_unit : 'null');
3855
3856 if (!empty($this->rang)) {
3857 $sql .= ", rang=".((int) $this->rang);
3858 }
3859
3860 // Multicurrency
3861 $sql .= " , multicurrency_subprice=".price2num($this->multicurrency_subprice);
3862 $sql .= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht);
3863 $sql .= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva);
3864 $sql .= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc);
3865
3866 $sql .= " WHERE rowid = ".((int) $this->id);
3867
3868 dol_syslog(get_class($this)."::update", LOG_DEBUG);
3869 $resql = $this->db->query($sql);
3870
3871 if (!$resql) {
3872 $this->db->rollback();
3873 $this->error = $this->db->lasterror();
3874 return -1;
3875 }
3876
3877 $this->rowid = $this->id;
3878 $error = 0;
3879
3880 if (!$error) {
3881 $result = $this->insertExtraFields();
3882 if ($result < 0) {
3883 $error++;
3884 }
3885 }
3886
3887 if (!$error && !$notrigger) {
3888 global $langs, $user;
3889
3890 // Call trigger
3891 if ($this->call_trigger('LINEBILL_SUPPLIER_MODIFY', $user) < 0) {
3892 $this->db->rollback();
3893 return -1;
3894 }
3895 // End call triggers
3896 }
3897
3898 if ($error) {
3899 $this->db->rollback();
3900 return -1;
3901 }
3902
3903 $this->db->commit();
3904 return 1;
3905 }
3906
3914 public function insert($notrigger = 0, $noerrorifdiscountalreadylinked = 0)
3915 {
3916 global $user, $langs;
3917
3918 $error = 0;
3919
3920 dol_syslog(get_class($this)."::insert rang=".$this->rang, LOG_DEBUG);
3921
3922 // Clean parameters
3923 $this->desc = trim($this->desc);
3924 if (empty($this->tva_tx)) {
3925 $this->tva_tx = 0;
3926 }
3927 if (empty($this->localtax1_tx)) {
3928 $this->localtax1_tx = 0;
3929 }
3930 if (empty($this->localtax2_tx)) {
3931 $this->localtax2_tx = 0;
3932 }
3933 if (empty($this->localtax1_type)) {
3934 $this->localtax1_type = '0';
3935 }
3936 if (empty($this->localtax2_type)) {
3937 $this->localtax2_type = '0';
3938 }
3939 if (empty($this->total_tva)) {
3940 $this->total_tva = 0;
3941 }
3942 if (empty($this->total_localtax1)) {
3943 $this->total_localtax1 = 0;
3944 }
3945 if (empty($this->total_localtax2)) {
3946 $this->total_localtax2 = 0;
3947 }
3948 if (empty($this->rang)) {
3949 $this->rang = 0;
3950 }
3951 if (empty($this->remise_percent)) {
3952 $this->remise_percent = 0;
3953 }
3954 if (empty($this->info_bits)) {
3955 $this->info_bits = 0;
3956 }
3957 if (empty($this->subprice)) {
3958 $this->subprice = 0;
3959 }
3960 if (empty($this->special_code)) {
3961 $this->special_code = 0;
3962 }
3963 if (empty($this->fk_parent_line)) {
3964 $this->fk_parent_line = 0;
3965 }
3966 if (!isset($this->situation_percent) || $this->situation_percent > 100 || (string) $this->situation_percent == '') {
3967 $this->situation_percent = 100;
3968 }
3969
3970 if (empty($this->pa_ht)) {
3971 $this->pa_ht = 0;
3972 }
3973 if (empty($this->multicurrency_subprice)) {
3974 $this->multicurrency_subprice = 0;
3975 }
3976 if (empty($this->multicurrency_total_ht)) {
3977 $this->multicurrency_total_ht = 0;
3978 }
3979 if (empty($this->multicurrency_total_tva)) {
3980 $this->multicurrency_total_tva = 0;
3981 }
3982 if (empty($this->multicurrency_total_ttc)) {
3983 $this->multicurrency_total_ttc = 0;
3984 }
3985
3986
3987 // Check parameters
3988 if ($this->product_type < 0) {
3989 $this->error = 'ErrorProductTypeMustBe0orMore';
3990 return -1;
3991 }
3992 if (!empty($this->fk_product) && $this->fk_product > 0) {
3993 // Check product exists
3994 $result = Product::isExistingObject('product', $this->fk_product);
3995 if ($result <= 0) {
3996 $this->error = 'ErrorProductIdDoesNotExists';
3997 return -1;
3998 }
3999 }
4000
4001 $this->db->begin();
4002
4003 // Insertion dans base de la ligne
4004 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
4005 $sql .= ' (fk_facture_fourn, fk_parent_line, label, description, ref, qty,';
4006 $sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
4007 $sql .= ' fk_product, product_type, remise_percent, fk_remise_except, pu_ht, pu_ttc,';
4008 $sql .= ' date_start, date_end, fk_code_ventilation, rang, special_code,';
4009 $sql .= ' info_bits, total_ht, tva, total_ttc, total_localtax1, total_localtax2, fk_unit';
4010 $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
4011 $sql .= ')';
4012 $sql .= " VALUES (".$this->fk_facture_fourn.",";
4013 $sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape($this->fk_parent_line)."'" : "null").",";
4014 $sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
4015 $sql .= " '".$this->db->escape($this->desc ? $this->desc : $this->description)."',";
4016 $sql .= " '".$this->db->escape($this->ref_supplier)."',";
4017 $sql .= " ".price2num($this->qty).",";
4018
4019 $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape($this->vat_src_code)."'").",";
4020 $sql .= " ".price2num($this->tva_tx).",";
4021 $sql .= " ".price2num($this->localtax1_tx).",";
4022 $sql .= " ".price2num($this->localtax2_tx).",";
4023 $sql .= " '".$this->db->escape($this->localtax1_type)."',";
4024 $sql .= " '".$this->db->escape($this->localtax2_type)."',";
4025 $sql .= ' '.((!empty($this->fk_product) && $this->fk_product > 0) ? $this->fk_product : "null").',';
4026 $sql .= " ".((int) $this->product_type).",";
4027 $sql .= " ".price2num($this->remise_percent).",";
4028 $sql .= ' '.(!empty($this->fk_remise_except) ? ((int) $this->fk_remise_except) : "null").',';
4029 $sql .= " ".price2num($this->subprice).",";
4030 $sql .= " ".(!empty($this->qty) ? price2num($this->total_ttc / $this->qty) : price2num($this->total_ttc)).",";
4031 $sql .= " ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null").",";
4032 $sql .= " ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").",";
4033 $sql .= ' '.(!empty($this->fk_code_ventilation) ? $this->fk_code_ventilation : 0).',';
4034 $sql .= ' '.((int) $this->rang).',';
4035 $sql .= ' '.((int) $this->special_code).',';
4036 $sql .= " ".((int) $this->info_bits).",";
4037 $sql .= " ".price2num($this->total_ht).",";
4038 $sql .= " ".price2num($this->total_tva).",";
4039 $sql .= " ".price2num($this->total_ttc).",";
4040 $sql .= " ".price2num($this->total_localtax1).",";
4041 $sql .= " ".price2num($this->total_localtax2);
4042 $sql .= ", ".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
4043 $sql .= ", ".(int) $this->fk_multicurrency;
4044 $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
4045 $sql .= ", ".price2num($this->multicurrency_subprice);
4046 $sql .= ", ".price2num($this->multicurrency_total_ht);
4047 $sql .= ", ".price2num($this->multicurrency_total_tva);
4048 $sql .= ", ".price2num($this->multicurrency_total_ttc);
4049 $sql .= ')';
4050
4051 $resql = $this->db->query($sql);
4052 if ($resql) {
4053 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
4054 $this->rowid = $this->id; // backward compatibility
4055
4056 if (!$error) {
4057 $result = $this->insertExtraFields();
4058 if ($result < 0) {
4059 $error++;
4060 }
4061 }
4062
4063 // Si fk_remise_except defini, on lie la remise a la facture
4064 // ce qui la flague comme "consommee".
4065 if ($this->fk_remise_except) {
4066 $discount = new DiscountAbsolute($this->db);
4067 $result = $discount->fetch($this->fk_remise_except);
4068 if ($result >= 0) {
4069 // Check if discount was found
4070 if ($result > 0) {
4071 // Check if discount not already affected to another invoice
4072 if ($discount->fk_facture_line > 0) {
4073 if (empty($noerrorifdiscountalreadylinked)) {
4074 $this->error = $langs->trans("ErrorDiscountAlreadyUsed", $discount->id);
4075 dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
4076 $this->db->rollback();
4077 return -3;
4078 }
4079 } else {
4080 $result = $discount->link_to_invoice($this->rowid, 0);
4081 if ($result < 0) {
4082 $this->error = $discount->error;
4083 dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
4084 $this->db->rollback();
4085 return -3;
4086 }
4087 }
4088 } else {
4089 $this->error = $langs->trans("ErrorADiscountThatHasBeenRemovedIsIncluded");
4090 dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
4091 $this->db->rollback();
4092 return -3;
4093 }
4094 } else {
4095 $this->error = $discount->error;
4096 dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
4097 $this->db->rollback();
4098 return -3;
4099 }
4100 }
4101
4102 if (!$error && !$notrigger) {
4103 // Call trigger
4104 $result = $this->call_trigger('LINEBILL_SUPPLIER_CREATE', $user);
4105 if ($result < 0) {
4106 $this->db->rollback();
4107 return -2;
4108 }
4109 // End call triggers
4110 }
4111
4112 $this->db->commit();
4113 return $this->id;
4114 } else {
4115 $this->error = $this->db->error();
4116 $this->db->rollback();
4117 return -2;
4118 }
4119 }
4120
4121 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4127 public function update_total()
4128 {
4129 // phpcs:enable
4130 $this->db->begin();
4131
4132 // Mise a jour ligne en base
4133 $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
4134 $sql .= " total_ht = ".price2num($this->total_ht);
4135 $sql .= ", tva= ".price2num($this->total_tva);
4136 $sql .= ", total_localtax1 = ".price2num($this->total_localtax1);
4137 $sql .= ", total_localtax2 = ".price2num($this->total_localtax2);
4138 $sql .= ", total_ttc = ".price2num($this->total_ttc);
4139 $sql .= " WHERE rowid = ".((int) $this->rowid);
4140
4141 dol_syslog("FactureFournisseurLigne.class.php::update_total", LOG_DEBUG);
4142
4143 $resql = $this->db->query($sql);
4144 if ($resql) {
4145 $this->db->commit();
4146 return 1;
4147 } else {
4148 $this->error = $this->db->error();
4149 $this->db->rollback();
4150 return -2;
4151 }
4152 }
4153}
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:124
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:1907
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:1907
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