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