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