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