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