dolibarr 23.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-2026 Alexandre Spangaro <alexandre@inovea-conseil.com>
14 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
15 * Copyright (C) 2018-2025 Frédéric France <frederic.france@free.fr>
16 * Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
17 * Copyright (C) 2023 Nick Fragoulis
18 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 3 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program. If not, see <https://www.gnu.org/licenses/>.
32 */
33
40require_once DOL_DOCUMENT_ROOT.'/core/class/commoninvoice.class.php';
41require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
42require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.ligne.class.php';
43require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
44
45if (isModEnabled('accounting')) {
46 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
47 require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
48}
49
54{
58 public $element = 'invoice_supplier';
59
63 public $table_element = 'facture_fourn';
64
68 public $table_element_line = 'facture_fourn_det';
69
73 public $class_element_line = 'SupplierInvoiceLine';
77 public $fk_element = 'fk_facture_fourn';
78
82 public $picto = 'supplier_invoice';
83
88 public $restrictiononfksoc = 1;
89
93 protected $table_ref_field = 'ref';
94
98 public $rowid;
99
103 public $ref;
104
108 public $ref_supplier;
109
114 public $libelle;
118 public $label;
119
120 //Check constants for types
121 public $type = self::TYPE_STANDARD;
122
129 public $statut;
130
136 public $status;
137
144 public $fk_statut;
145
151 public $paye;
156 public $paid;
157
162 public $author;
163
168 public $fk_user_valid;
169
175 public $datec;
176
182 public $date_echeance;
183
187 public $date_pointoftax;
188
193 public $amount = 0;
198 public $remise = 0;
199
204 public $tva;
205
206 // Warning: Do not set default value into property definition. it must stay null.
207 // For example to avoid to have substitution done when object is generic and not yet defined.
209 public $localtax1;
211 public $localtax2;
213 public $total_ht;
215 public $total_tva;
217 public $total_localtax1;
219 public $total_localtax2;
221 public $total_ttc;
222
228 public $note;
230 public $note_private;
232 public $note_public;
234 public $propalid;
235
239 public $fk_account; // default bank account
240
244 public $transport_mode_id;
245
249 public $vat_reverse_charge;
250
254 public $extraparams = array();
255
260 public $lines = array();
261
266 public $fournisseur;
267
269
272 public $fk_facture_source;
273
275 public $fac_rec;
277 public $fk_fac_rec_source;
278
279 public $fields = array(
280 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
281 'ref' => array('type' => 'varchar(255)', 'label' => 'Ref', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'showoncombobox' => 1, 'position' => 15),
282 'ref_supplier' => array('type' => 'varchar(255)', 'label' => 'RefSupplier', 'enabled' => 1, 'visible' => -1, 'position' => 20),
283 'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 25, 'index' => 1),
284 'ref_ext' => array('type' => 'varchar(255)', 'label' => 'RefExt', 'enabled' => 1, 'visible' => 0, 'position' => 30),
285 'type' => array('type' => 'smallint(6)', 'label' => 'Type', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 35),
286 'subtype' => array('type' => 'smallint(6)', 'label' => 'InvoiceSubtype', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 36),
287 'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'enabled' => 'isModEnabled("societe")', 'visible' => -1, 'notnull' => 1, 'position' => 40),
288 'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -1, 'position' => 45),
289 'datef' => array('type' => 'date', 'label' => 'Date', 'enabled' => 1, 'visible' => -1, 'position' => 50),
290 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 55),
291 'libelle' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'visible' => -1, 'position' => 60),
292 'paye' => array('type' => 'smallint(6)', 'label' => 'Paye', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 65),
293 'amount' => array('type' => 'double(24,8)', 'label' => 'Amount', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 70),
294 'remise' => array('type' => 'double(24,8)', 'label' => 'Discount', 'enabled' => 1, 'visible' => -1, 'position' => 75),
295 'close_code' => array('type' => 'varchar(16)', 'label' => 'CloseCode', 'enabled' => 1, 'visible' => -1, 'position' => 80),
296 'close_note' => array('type' => 'varchar(128)', 'label' => 'CloseNote', 'enabled' => 1, 'visible' => -1, 'position' => 85),
297 'tva' => array('type' => 'double(24,8)', 'label' => 'Tva', 'enabled' => 1, 'visible' => -1, 'position' => 90),
298 'localtax1' => array('type' => 'double(24,8)', 'label' => 'Localtax1', 'enabled' => 1, 'visible' => -1, 'position' => 95),
299 'localtax2' => array('type' => 'double(24,8)', 'label' => 'Localtax2', 'enabled' => 1, 'visible' => -1, 'position' => 100),
300 'total_ht' => array('type' => 'double(24,8)', 'label' => 'TotalHT', 'enabled' => 1, 'visible' => -1, 'position' => 105),
301 'total_tva' => array('type' => 'double(24,8)', 'label' => 'TotalVAT', 'enabled' => 1, 'visible' => -1, 'position' => 110),
302 'total_ttc' => array('type' => 'double(24,8)', 'label' => 'TotalTTC', 'enabled' => 1, 'visible' => -1, 'position' => 115),
303 'fk_user_author' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserAuthor', 'enabled' => 1, 'visible' => -1, 'position' => 125),
304 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 130),
305 'fk_user_valid' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserValidation', 'enabled' => 1, 'visible' => -1, 'position' => 135),
306 'fk_facture_source' => array('type' => 'integer', 'label' => 'Fk facture source', 'enabled' => 1, 'visible' => -1, 'position' => 140),
307 'fk_projet' => array('type' => 'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label' => 'Project', 'enabled' => "isModEnabled('project')", 'visible' => -1, 'position' => 145),
308 'fk_account' => array('type' => 'integer', 'label' => 'Account', 'enabled' => 'isModEnabled("bank")', 'visible' => -1, 'position' => 150),
309 'fk_cond_reglement' => array('type' => 'integer', 'label' => 'PaymentTerm', 'enabled' => 1, 'visible' => -1, 'position' => 155),
310 'fk_mode_reglement' => array('type' => 'integer', 'label' => 'PaymentMode', 'enabled' => 1, 'visible' => -1, 'position' => 160),
311 'date_lim_reglement' => array('type' => 'date', 'label' => 'DateLimReglement', 'enabled' => 1, 'visible' => -1, 'position' => 165),
312 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 170),
313 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 175),
314 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'ModelPdf', 'enabled' => 1, 'visible' => 0, 'position' => 180),
315 'extraparams' => array('type' => 'varchar(255)', 'label' => 'Extraparams', 'enabled' => 1, 'visible' => -1, 'position' => 190),
316 'fk_incoterms' => array('type' => 'integer', 'label' => 'IncotermCode', 'enabled' => 1, 'visible' => -1, 'position' => 195),
317 'location_incoterms' => array('type' => 'varchar(255)', 'label' => 'IncotermLocation', 'enabled' => 1, 'visible' => -1, 'position' => 200),
318 'fk_multicurrency' => array('type' => 'integer', 'label' => 'MulticurrencyId', 'enabled' => 1, 'visible' => -1, 'position' => 205),
319 'multicurrency_code' => array('type' => 'varchar(255)', 'label' => 'MulticurrencyCode', 'enabled' => 1, 'visible' => -1, 'position' => 210),
320 'multicurrency_tx' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyRate', 'enabled' => 1, 'visible' => -1, 'position' => 215),
321 'multicurrency_total_ht' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyTotalHT', 'enabled' => 1, 'visible' => -1, 'position' => 220),
322 'multicurrency_total_tva' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyTotalVAT', 'enabled' => 1, 'visible' => -1, 'position' => 225),
323 'multicurrency_total_ttc' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyTotalTTC', 'enabled' => 1, 'visible' => -1, 'position' => 230),
324 'date_pointoftax' => array('type' => 'date', 'label' => 'DatePointOfTax', 'enabled' => 'getDolGlobalString("INVOICE_POINTOFTAX_DATE")', 'visible' => -1, 'position' => 235),
325 'date_valid' => array('type' => 'date', 'label' => 'DateValidation', 'enabled' => 1, 'visible' => -1, 'position' => 240),
326 'last_main_doc' => array('type' => 'varchar(255)', 'label' => 'Last main doc', 'enabled' => 1, 'visible' => -1, 'position' => 245),
327 'fk_statut' => array('type' => 'smallint(6)', 'label' => 'Status', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 500),
328 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'position' => 900),
329 );
330
331
335 const TYPE_STANDARD = 0;
336
341
346
350 const TYPE_DEPOSIT = 3;
351
355 const STATUS_DRAFT = 0;
356
361
369 const STATUS_CLOSED = 2;
370
379
380 const CLOSECODE_DISCOUNTVAT = 'discount_vat';
381 const CLOSECODE_BADCREDIT = 'badsupplier';
382 const CLOSECODE_ABANDONED = 'abandon';
383 const CLOSECODE_REPLACED = 'replaced';
384
385
391 public function __construct($db)
392 {
393 $this->db = $db;
394
395 $this->ismultientitymanaged = 1;
396 }
397
404 public function create($user)
405 {
406 global $langs, $conf, $hookmanager;
407
408 $error = 0;
409 $now = dol_now();
410
411 // Clean parameters
412 if (isset($this->ref_supplier)) {
413 $this->ref_supplier = trim($this->ref_supplier);
414 }
415 if (empty($this->type)) {
416 $this->type = self::TYPE_STANDARD;
417 }
418 if (empty($this->date)) {
419 $this->date = $now;
420 }
421
422 // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
423 if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) {
424 list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $this->date);
425 } else {
426 $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
427 }
428 if (empty($this->fk_multicurrency)) {
429 $this->multicurrency_code = $conf->currency;
430 $this->fk_multicurrency = 0;
431 $this->multicurrency_tx = 1;
432 }
433 $this->entity = setEntity($this);
434
435 $this->db->begin();
436
437 // Defaults
438 $originaldatewhen = 0;
439 $nextdatewhen = 0;
440 $previousdaynextdatewhen = 0;
441 $_facrec = null;
442
443 // Create invoice from a template recurring invoice
444 if ($this->fac_rec > 0) {
445 $this->fk_fac_rec_source = $this->fac_rec;
446
447 require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture-rec.class.php';
448 $_facrec = new FactureFournisseurRec($this->db);
449 $result = $_facrec->fetch($this->fac_rec);
450 $result = $_facrec->fetchObjectLinked(null, '', null, '', 'OR', 1, 'sourcetype', 0); // This load $_facrec->linkedObjectsIds
451
452 // Define some dates
453 if (!empty($_facrec->frequency)) {
454 $originaldatewhen = $_facrec->date_when;
455 // date_when is read from database in the timezone of the server (jdate), so delays must be added in this timezone
456 $nextdatewhen = dol_time_plus_duree($originaldatewhen, $_facrec->frequency, $_facrec->unit_frequency, 0, 'tzserver');
457 $previousdaynextdatewhen = dol_time_plus_duree($nextdatewhen, -1, 'd', 0, 'tzserver');
458 $this->socid = $_facrec->socid;
459 }
460
461 $this->entity = $_facrec->entity; // Invoice created in same entity than template
462
463 // Fields coming from GUI
464 // @TODO Value of template should be used as default value on the form on the GUI, and we should here always use the value from GUI
465 // set by posted page with $object->xxx = ... and this section should be removed.
466 $this->fk_project = GETPOSTINT('projectid') > 0 ? (GETPOSTINT('projectid')) : $_facrec->fk_project;
467 $this->note_public = GETPOST('note_public', 'restricthtml') ? GETPOST('note_public', 'restricthtml') : $_facrec->note_public;
468 $this->note_private = GETPOST('note_private', 'restricthtml') ? GETPOST('note_private', 'restricthtml') : $_facrec->note_private;
469 $this->model_pdf = GETPOST('model', 'alpha') ? GETPOST('model', 'alpha') : $_facrec->model_pdf;
470 $this->cond_reglement_id = GETPOSTINT('cond_reglement_id') > 0 ? (GETPOSTINT('cond_reglement_id')) : $_facrec->cond_reglement_id;
471 $this->mode_reglement_id = GETPOSTINT('mode_reglement_id') > 0 ? (GETPOSTINT('mode_reglement_id')) : $_facrec->mode_reglement_id;
472 $this->fk_account = GETPOST('fk_account') > 0 ? ((int) GETPOST('fk_account')) : $_facrec->fk_account;
473
474 // Set here to have this defined for substitution into notes, should be recalculated after adding lines to get same result
475 $this->total_ht = $_facrec->total_ht;
476 $this->total_ttc = $_facrec->total_ttc;
477
478 // Fields always coming from template
479 $this->fk_incoterms = $_facrec->fk_incoterms;
480 $this->location_incoterms = $_facrec->location_incoterms;
481
482 // Clean parameters
483 if (! $this->type) {
484 $this->type = self::TYPE_STANDARD;
485 }
486 $this->note_public = trim((string) $this->note_public);
487 $this->note_private = trim((string) $this->note_private);
488 $this->note_private = dol_concatdesc($this->note_private, $langs->trans("GeneratedFromRecurringInvoice", $_facrec->title));
489
490 $this->array_options = $_facrec->array_options;
491
492 if (! $this->mode_reglement_id) {
493 $this->mode_reglement_id = 0;
494 }
495 $this->status = self::STATUS_DRAFT;
496 $this->statut = self::STATUS_DRAFT; // deprecated
497
498 $this->linked_objects = $_facrec->linkedObjectsIds;
499 // We do not add link to template invoice or next invoice will be linked to all generated invoices
500 //$this->linked_objects['facturerec'][0] = $this->fac_rec;
501
502 $forceduedate = $this->calculate_date_lim_reglement();
503
504 // For recurring invoices, update date and number of last generation of recurring template invoice, before inserting new invoice
505 if ($_facrec->frequency > 0) {
506 $this->ref_supplier = trim($this->ref_supplier . '_' . ($_facrec->nb_gen_done + 1));
507 dol_syslog("This is a recurring invoice so we set date_last_gen and next date_when");
508 if (empty($_facrec->date_when)) {
509 $_facrec->date_when = $now;
510 }
511 $next_date = $_facrec->getNextDate(); // Calculate next date
512 $result = $_facrec->setValueFrom('date_last_gen', $now, '', 0, 'date', '', $user, '');
513 //$_facrec->setValueFrom('nb_gen_done', $_facrec->nb_gen_done + 1); // Not required, +1 already included into setNextDate when second param is 1.
514 $result = $_facrec->setNextDate($next_date, 1);
515 }
516
517 // Define lang of customer
518 $outputlangs = $langs;
519 $newlang = '';
520
521 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->thirdparty->default_lang)) {
522 $newlang = $this->thirdparty->default_lang; // for proposal, order, invoice, ...
523 }
524 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && property_exists($this, 'default_lang') && isset($this->default_lang)) { // @phan-suppress-current-line PhanUndeclaredProperty
525 $newlang = $this->default_lang; // for thirdparty @phan-suppress-current-line PhanUndeclaredProperty
526 }
527 if (!empty($newlang)) {
528 $outputlangs = new Translate("", $conf);
529 $outputlangs->setDefaultLang($newlang);
530 } // Array of possible substitutions (See also file mailing-send.php that should manage same substitutions)
531 $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $this);
532 $substitutionarray['__INVOICE_PREVIOUS_MONTH__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'm', 0, 'tzserver'), '%m');
533 $substitutionarray['__INVOICE_MONTH__'] = dol_print_date($this->date, '%m');
534 $substitutionarray['__INVOICE_NEXT_MONTH__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'm', 0, 'tzserver'), '%m');
535 $substitutionarray['__INVOICE_PREVIOUS_MONTH_TEXT__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'm', 0, 'tzserver'), '%B');
536 $substitutionarray['__INVOICE_MONTH_TEXT__'] = dol_print_date($this->date, '%B');
537 $substitutionarray['__INVOICE_NEXT_MONTH_TEXT__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'm', 0, 'tzserver'), '%B');
538 $substitutionarray['__INVOICE_PREVIOUS_YEAR__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'y', 0, 'tzserver'), '%Y');
539 $substitutionarray['__INVOICE_YEAR__'] = dol_print_date($this->date, '%Y');
540 $substitutionarray['__INVOICE_NEXT_YEAR__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'y', 0, 'tzserver'), '%Y'); // Only for template invoice
541 $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_BEFORE_GEN__'] = $originaldatewhen ? dol_print_date($originaldatewhen, 'dayhour') : '';
542 $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_AFTER_GEN__'] = $nextdatewhen ? dol_print_date($nextdatewhen, 'dayhour') : '';
543 $substitutionarray['__INVOICE_PREVIOUS_DATE_NEXT_INVOICE_AFTER_GEN__'] = $previousdaynextdatewhen ? dol_print_date($previousdaynextdatewhen, 'dayhour') : '';
544 $substitutionarray['__INVOICE_COUNTER_CURRENT__'] = $_facrec->nb_gen_done;
545 $substitutionarray['__INVOICE_COUNTER_MAX__'] = $_facrec->nb_gen_max;
546
547 complete_substitutions_array($substitutionarray, $outputlangs);
548
549 $this->note_public = make_substitutions($this->note_public, $substitutionarray);
550 $this->note_private = make_substitutions($this->note_private, $substitutionarray);
551 }
552
553 // Define due date if not already defined
554 if (!empty($forceduedate)) {
555 $this->date_echeance = $forceduedate;
556 }
557
558 $sql = "INSERT INTO ".MAIN_DB_PREFIX."facture_fourn (";
559 $sql .= "ref";
560 $sql .= ", ref_supplier";
561 $sql .= ", ref_ext";
562 $sql .= ", entity";
563 $sql .= ", type";
564 $sql .= ", subtype";
565 $sql .= ", libelle";
566 $sql .= ", fk_soc";
567 $sql .= ", datec";
568 $sql .= ", datef";
569 $sql .= ", date_pointoftax";
570 $sql .= ", vat_reverse_charge";
571 $sql .= ", fk_projet";
572 $sql .= ", fk_cond_reglement";
573 $sql .= ", fk_mode_reglement";
574 $sql .= ", fk_account";
575 $sql .= ", note_private";
576 $sql .= ", note_public";
577 $sql .= ", fk_user_author";
578 $sql .= ", date_lim_reglement";
579 $sql .= ", fk_incoterms, location_incoterms";
580 $sql .= ", fk_multicurrency";
581 $sql .= ", multicurrency_code";
582 $sql .= ", multicurrency_tx";
583 $sql .= ", fk_facture_source";
584 $sql .= ", fk_fac_rec_source";
585 $sql .= ")";
586 $sql .= " VALUES (";
587 $sql .= "'(PROV)'";
588 $sql .= ", '".$this->db->escape($this->ref_supplier)."'";
589 $sql .= ", '".$this->db->escape($this->ref_ext)."'";
590 $sql .= ", ".((int) $this->entity);
591 $sql .= ", '".$this->db->escape((string) $this->type)."'";
592 $sql .= ", ".(isset($this->subtype) ? (int) $this->subtype : "null");
593 $sql .= ", '".$this->db->escape(isset($this->label) ? $this->label : (isset($this->libelle) ? $this->libelle : ''))."'";
594 $sql .= ", ".((int) $this->socid);
595 $sql .= ", '".$this->db->idate($now)."'";
596 $sql .= ", '".$this->db->idate($this->date)."'";
597 $sql .= ", ".(empty($this->date_pointoftax) ? "null" : "'".$this->db->idate($this->date_pointoftax)."'");
598 $sql .= ", ".($this->vat_reverse_charge != '' ? ((int) $this->vat_reverse_charge) : 0);
599 $sql .= ", ".($this->fk_project > 0 ? ((int) $this->fk_project) : "null");
600 $sql .= ", ".($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : "null");
601 $sql .= ", ".($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : "null");
602 $sql .= ", ".($this->fk_account > 0 ? ((int) $this->fk_account) : 'NULL');
603 $sql .= ", '".$this->db->escape($this->note_private)."'";
604 $sql .= ", '".$this->db->escape($this->note_public)."'";
605 $sql .= ", ".((int) $user->id).",";
606 $sql .= $this->date_echeance != '' ? "'".$this->db->idate($this->date_echeance)."'" : "null";
607 $sql .= ", ".(int) $this->fk_incoterms;
608 $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
609 $sql .= ", ".(int) $this->fk_multicurrency;
610 $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
611 $sql .= ", ".(float) $this->multicurrency_tx;
612 $sql .= ", ".($this->fk_facture_source ? ((int) $this->fk_facture_source) : "null");
613 $sql .= ", ".(isset($this->fk_fac_rec_source) ? $this->fk_fac_rec_source : "NULL");
614 $sql .= ")";
615
616 dol_syslog(get_class($this)."::create", LOG_DEBUG);
617 $resql = $this->db->query($sql);
618 if ($resql) {
619 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn');
620
621 // Update ref with new one
622 $this->ref = '(PROV'.$this->id.')';
623 $sql = 'UPDATE '.MAIN_DB_PREFIX."facture_fourn SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".((int) $this->id);
624
625 dol_syslog(get_class($this)."::create", LOG_DEBUG);
626 $resql = $this->db->query($sql);
627 if (!$resql) {
628 $error++;
629 }
630
631 if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) { // To use new linkedObjectsIds instead of old linked_objects
632 $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
633 }
634
635 // Add object linked
636 if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) {
637 foreach ($this->linked_objects as $origin => $tmp_origin_id) {
638 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, ...))
639 foreach ($tmp_origin_id as $origin_id) {
640 $ret = $this->add_object_linked($origin, $origin_id);
641 if (!$ret) {
642 dol_print_error($this->db);
643 $error++;
644 }
645 }
646 } else { // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
647 $origin_id = $tmp_origin_id;
648 $ret = $this->add_object_linked($origin, $origin_id);
649 if (!$ret) {
650 dol_print_error($this->db);
651 $error++;
652 }
653 }
654 }
655 }
656
657 if (!$error && empty($this->fac_rec) && count($this->lines) && is_object($this->lines[0])) { // If this->lines is array of InvoiceLines (preferred mode)
658 dol_syslog("There is ".count($this->lines)." lines that are invoice lines objects");
659 foreach ($this->lines as $i => $val) {
660 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn, special_code, fk_remise_except)';
661 $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').')';
662
663 $resql_insert = $this->db->query($sql);
664 if ($resql_insert) {
665 $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det');
666
667 $res = $this->updateline(
668 $idligne,
669 $this->lines[$i]->desc ? $this->lines[$i]->desc : $this->lines[$i]->description,
670 $this->lines[$i]->subprice,
671 $this->lines[$i]->tva_tx.($this->lines[$i]->vat_src_code ? ' ('.$this->lines[$i]->vat_src_code.')' : ''),
672 $this->lines[$i]->localtax1_tx,
673 $this->lines[$i]->localtax2_tx,
674 $this->lines[$i]->qty,
675 $this->lines[$i]->fk_product,
676 'HT',
677 (!empty($this->lines[$i]->info_bits) ? $this->lines[$i]->info_bits : ''),
678 $this->lines[$i]->product_type,
679 $this->lines[$i]->remise_percent,
680 0,
681 $this->lines[$i]->date_start,
682 $this->lines[$i]->date_end,
683 $this->lines[$i]->array_options,
684 $this->lines[$i]->fk_unit,
685 $this->lines[$i]->multicurrency_subprice,
686 $this->lines[$i]->ref_supplier
687 );
688 } else {
689 $this->error = $this->db->lasterror();
690 $this->db->rollback();
691 return -5;
692 }
693 }
694 } elseif (!$error && empty($this->fac_rec)) { // If this->lines is an array of invoice line arrays
695 dol_syslog("There is ".count($this->lines)." lines that are array lines");
696 foreach ($this->lines as $i => $val) {
697 $line = $this->lines[$i];
698
699 // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
700 //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
701 if (!is_object($line)) {
702 $line = (object) $line;
703 }
704
705 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn, special_code, fk_remise_except)';
706 $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').')';
707
708 $resql_insert = $this->db->query($sql);
709 if ($resql_insert) {
710 $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det');
711
712 $this->updateline(
713 $idligne,
714 $line->desc ? $line->desc : $line->description,
715 $line->subprice,
716 $line->tva_tx,
717 $line->localtax1_tx,
718 $line->localtax2_tx,
719 $line->qty,
720 $line->fk_product,
721 'HT',
722 (!empty($line->info_bits) ? $line->info_bits : ''),
723 $line->product_type,
724 $line->remise_percent,
725 0,
726 $line->date_start,
727 $line->date_end,
728 $line->array_options,
729 $line->fk_unit,
730 $line->multicurrency_subprice,
731 $line->ref_supplier
732 );
733 } else {
734 $this->error = $this->db->lasterror();
735 $this->db->rollback();
736 return -5;
737 }
738 }
739 }
740
741 /*
742 * Insert lines of template invoices
743 */
744 if (! $error && $this->fac_rec > 0 && $_facrec instanceof FactureFournisseurRec) {
745 foreach ($_facrec->lines as $i => $val) {
746 $product_type = $_facrec->lines[$i]->product_type;
747 if ($_facrec->lines[$i]->fk_product) {
748 $prod = new Product($this->db);
749 $res = $prod->fetch($_facrec->lines[$i]->fk_product);
750 }
751
752 // For line from template invoice, we use data from template invoice
753 /*
754 $tva_tx = get_default_tva($mysoc,$soc,$prod->id);
755 $tva_npr = get_default_npr($mysoc,$soc,$prod->id);
756 if (empty($tva_tx)) $tva_npr=0;
757 $localtax1_tx=get_localtax($tva_tx,1,$soc,$mysoc,$tva_npr);
758 $localtax2_tx=get_localtax($tva_tx,2,$soc,$mysoc,$tva_npr);
759 */
760 $tva_tx = $_facrec->lines[$i]->tva_tx . ($_facrec->lines[$i]->vat_src_code ? '(' . $_facrec->lines[$i]->vat_src_code . ')' : '');
761 $tva_npr = $_facrec->lines[$i]->info_bits;
762 if (empty($tva_tx)) {
763 $tva_npr = 0;
764 }
765 $localtax1_tx = $_facrec->lines[$i]->localtax1_tx;
766 $localtax2_tx = $_facrec->lines[$i]->localtax2_tx;
767
768 // $fk_product_fournisseur_price not used and does not exist on line
769 // $fk_product_fournisseur_price = empty($_facrec->lines[$i]->fk_product_fournisseur_price) ? null : $_facrec->lines[$i]->fk_product_fournisseur_price;
770 $buyprice = empty($_facrec->lines[$i]->buyprice) ? 0 : $_facrec->lines[$i]->buyprice;
771
772 // If buyprice not defined from template invoice, we try to guess the best value
773 if (! $buyprice && $_facrec->lines[$i]->fk_product > 0) {
774 require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php';
775 $producttmp = new ProductFournisseur($this->db);
776 $producttmp->fetch($_facrec->lines[$i]->fk_product);
777
778 // If margin module defined on costprice, we try the costprice
779 // If not defined or if module margin defined and pmp and stock module enabled, we try pmp price
780 // else we get the best supplier price
781 if (getDolGlobalString('MARGIN_TYPE') == 'costprice' && !empty($producttmp->cost_price)) {
782 $buyprice = $producttmp->cost_price;
783 } elseif (isModEnabled('stock') && (getDolGlobalString('MARGIN_TYPE') == 'costprice' || getDolGlobalString('MARGIN_TYPE') == 'pmp') && !empty($producttmp->pmp)) {
784 $buyprice = $producttmp->pmp;
785 } else {
786 if ($producttmp->find_min_price_product_fournisseur($_facrec->lines[$i]->fk_product) > 0) {
787 if ($producttmp->product_fourn_price_id > 0) {
788 $buyprice = price2num($producttmp->fourn_unitprice * (1 - $producttmp->fourn_remise_percent / 100) + $producttmp->fourn_remise, 'MU');
789 }
790 }
791 }
792 }
793
794 $result_insert = $this->addline(
795 $_facrec->lines[$i]->desc ? $_facrec->lines[$i]->desc : $_facrec->lines[$i]->description,
796 $_facrec->lines[$i]->pu_ht,
797 $tva_tx,
798 $localtax1_tx,
799 $localtax2_tx,
800 $_facrec->lines[$i]->qty,
801 $_facrec->lines[$i]->fk_product,
802 $_facrec->lines[$i]->remise_percent,
803 ($_facrec->lines[$i]->date_start == 1 && $this->date) ? $this->date : '',
804 ($_facrec->lines[$i]->date_end == 1 && $previousdaynextdatewhen) ? $previousdaynextdatewhen : '',
805 0,
806 $_facrec->lines[$i]->info_bits,
807 'HT',
808 $product_type,
809 $_facrec->lines[$i]->rang,
810 0,
811 $_facrec->lines[$i]->array_options,
812 $_facrec->lines[$i]->fk_unit,
813 0,
814 0,
815 $_facrec->lines[$i]->ref_supplier,
816 $_facrec->lines[$i]->special_code,
817 0,
818 0
819 );
820 if ($result_insert < 0) {
821 $error++;
822 $this->error = $this->db->error();
823 break;
824 }
825 }
826 }
827
828
829 // Update total price
830 $result = $this->update_price(1);
831 if ($result > 0) {
832 // Actions on extra fields
833 if (!$error) {
834 $result = $this->insertExtraFields(); // This also set $this->error or $this->errors if errors are found
835 if ($result < 0) {
836 $error++;
837 }
838 }
839
840 if (!$error) {
841 // Call trigger
842 $result = $this->call_trigger('BILL_SUPPLIER_CREATE', $user);
843 if ($result < 0) {
844 $error++;
845 }
846 // End call triggers
847 }
848
849 if (!$error) {
850 $this->db->commit();
851 return $this->id;
852 } else {
853 $this->db->rollback();
854 return -4;
855 }
856 } else {
857 $this->error = $langs->trans('FailedToUpdatePrice');
858 $this->db->rollback();
859 return -3;
860 }
861 } else {
862 if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
863 $this->error = $langs->trans('ErrorRefAlreadyExists');
864 $this->db->rollback();
865 return -1;
866 } else {
867 $this->error = $this->db->lasterror();
868 $this->db->rollback();
869 return -2;
870 }
871 }
872 }
873
882 public function fetch($id = 0, $ref = '', $ref_ext = '')
883 {
884 if (empty($id) && empty($ref) && empty($ref_ext)) {
885 return -1;
886 }
887
888 $sql = "SELECT";
889 $sql .= " t.rowid,";
890 $sql .= " t.ref,";
891 $sql .= " t.ref_supplier,";
892 $sql .= " t.ref_ext,";
893 $sql .= " t.entity,";
894 $sql .= " t.type,";
895 $sql .= " t.subtype,";
896 $sql .= " t.fk_soc,";
897 $sql .= " t.datec,";
898 $sql .= " t.datef,";
899 $sql .= " t.date_pointoftax,";
900 $sql .= " t.tms as datem,";
901 $sql .= " t.libelle as label,";
902 $sql .= " t.paye as paid,";
903 $sql .= " t.close_code,";
904 $sql .= " t.close_note,";
905 $sql .= " t.tva,";
906 $sql .= " t.localtax1,";
907 $sql .= " t.localtax2,";
908 $sql .= " t.total_ht,";
909 $sql .= " t.total_tva,";
910 $sql .= " t.total_ttc,";
911 $sql .= " t.fk_statut as status,";
912 $sql .= " t.fk_user_author,";
913 $sql .= " t.fk_user_valid,";
914 $sql .= " t.fk_facture_source,";
915 $sql .= " t.vat_reverse_charge,";
916 $sql .= " t.fk_fac_rec_source,";
917 $sql .= " t.fk_projet as fk_project,";
918 $sql .= " t.fk_cond_reglement,";
919 $sql .= " t.fk_account,";
920 $sql .= " t.fk_mode_reglement,";
921 $sql .= " t.date_lim_reglement,";
922 $sql .= " t.note_private,";
923 $sql .= " t.note_public,";
924 $sql .= " t.model_pdf,";
925 $sql .= " t.last_main_doc,";
926 $sql .= " t.import_key,";
927 $sql .= " t.extraparams,";
928 $sql .= " cr.code as cond_reglement_code, cr.libelle as cond_reglement_label, cr.libelle_facture as cond_reglement_doc,";
929 $sql .= " p.code as mode_reglement_code, p.libelle as mode_reglement_label,";
930 $sql .= ' s.nom as socnom, s.rowid as socid,';
931 $sql .= ' t.fk_incoterms, t.location_incoterms,';
932 $sql .= " i.libelle as label_incoterms,";
933 $sql .= ' t.fk_transport_mode,';
934 $sql .= ' t.fk_multicurrency, t.multicurrency_code, t.multicurrency_tx, t.multicurrency_total_ht, t.multicurrency_total_tva, t.multicurrency_total_ttc';
935 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as t';
936 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON (t.fk_soc = s.rowid)";
937 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_payment_term as cr ON t.fk_cond_reglement = cr.rowid";
938 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as p ON t.fk_mode_reglement = p.id";
939 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON t.fk_incoterms = i.rowid';
940 if ($id) {
941 $sql .= " WHERE t.rowid = ".((int) $id);
942 } else {
943 $sql .= ' WHERE t.entity IN ('.getEntity('supplier_invoice').')'; // Don't use entity if you use rowid
944 if ($ref) {
945 $sql .= " AND t.ref = '".$this->db->escape($ref)."'";
946 }
947 if ($ref_ext) {
948 $sql .= " AND t.ref_ext = '".$this->db->escape($ref_ext)."'";
949 }
950 }
951
952 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
953 $resql = $this->db->query($sql);
954 if ($resql) {
955 if ($this->db->num_rows($resql)) {
956 $obj = $this->db->fetch_object($resql);
957
958 $this->id = $obj->rowid;
959 $this->ref = $obj->ref ? $obj->ref : $obj->rowid; // We take rowid if ref is empty for backward compatibility
960
961 $this->ref_supplier = $obj->ref_supplier;
962 $this->ref_ext = $obj->ref_ext;
963 $this->entity = $obj->entity;
964 $this->type = empty($obj->type) ? self::TYPE_STANDARD : $obj->type;
965 $this->subtype = $obj->subtype;
966 $this->socid = $obj->fk_soc;
967 $this->date = $this->db->jdate($obj->datef);
968 $this->date_pointoftax = $this->db->jdate($obj->date_pointoftax);
969 $this->date_creation = $this->db->jdate($obj->datec);
970 $this->datec = $this->db->jdate($obj->datec);
971 $this->date_modification = $this->db->jdate($obj->datem);
972 $this->tms = $this->db->jdate($obj->datem);
973 $this->libelle = $obj->label; // deprecated
974 $this->label = $obj->label;
975 $this->paye = $obj->paid;
976 $this->paid = $obj->paid;
977 $this->close_code = $obj->close_code;
978 $this->close_note = $obj->close_note;
979 $this->total_localtax1 = $obj->localtax1;
980 $this->total_localtax2 = $obj->localtax2;
981 $this->total_ht = $obj->total_ht;
982 $this->total_tva = $obj->total_tva;
983 $this->total_ttc = $obj->total_ttc;
984 $this->status = $obj->status;
985 $this->statut = $obj->status; // For backward compatibility
986 $this->fk_statut = $obj->status; // For backward compatibility
987 $this->user_creation_id = $obj->fk_user_author;
988 $this->author = $obj->fk_user_author; // deprecated
989 $this->user_validation_id = $obj->fk_user_valid;
990 $this->fk_user_valid = $obj->fk_user_valid;
991 $this->fk_facture_source = $obj->fk_facture_source;
992 $this->vat_reverse_charge = empty($obj->vat_reverse_charge) ? 0 : 1;
993 $this->fk_fac_rec_source = $obj->fk_fac_rec_source;
994 $this->fk_project = $obj->fk_project;
995 $this->cond_reglement_id = $obj->fk_cond_reglement;
996 $this->cond_reglement_code = $obj->cond_reglement_code;
997 $this->cond_reglement = $obj->cond_reglement_label; // deprecated
998 $this->cond_reglement_label = $obj->cond_reglement_label;
999 $this->cond_reglement_doc = $obj->cond_reglement_doc;
1000 $this->fk_account = $obj->fk_account;
1001 $this->mode_reglement_id = $obj->fk_mode_reglement;
1002 $this->mode_reglement_code = $obj->mode_reglement_code;
1003 $this->mode_reglement = $obj->mode_reglement_label;
1004 $this->date_echeance = $this->db->jdate($obj->date_lim_reglement);
1005 $this->note = $obj->note_private; // deprecated
1006 $this->note_private = $obj->note_private;
1007 $this->note_public = $obj->note_public;
1008 $this->model_pdf = $obj->model_pdf;
1009 $this->last_main_doc = $obj->last_main_doc;
1010 $this->import_key = $obj->import_key;
1011
1012 //Incoterms
1013 $this->fk_incoterms = $obj->fk_incoterms;
1014 $this->location_incoterms = $obj->location_incoterms;
1015 $this->label_incoterms = $obj->label_incoterms;
1016 $this->transport_mode_id = $obj->fk_transport_mode;
1017
1018 // Multicurrency
1019 $this->fk_multicurrency = $obj->fk_multicurrency;
1020 $this->multicurrency_code = $obj->multicurrency_code;
1021 $this->multicurrency_tx = $obj->multicurrency_tx;
1022 $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
1023 $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
1024 $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
1025
1026 $this->extraparams = isset($obj->extraparams) ? (array) json_decode($obj->extraparams, true) : array();
1027
1028 $this->socid = $obj->socid;
1029
1030 $this->thirdparty = null; // Clear if another value was already set by fetch_thirdparty
1031
1032 // Retrieve all extrafield
1033 // fetch optionals attributes and labels
1034 $this->fetch_optionals();
1035
1036 $result = $this->fetch_lines();
1037 if ($result < 0) {
1038 $this->error = $this->db->lasterror();
1039 return -3;
1040 }
1041 } else {
1042 $this->error = 'Bill with id '.$id.' not found';
1043 dol_syslog(get_class($this).'::fetch '.$this->error);
1044 return 0;
1045 }
1046
1047 $this->db->free($resql);
1048 return 1;
1049 } else {
1050 $this->error = "Error ".$this->db->lasterror();
1051 return -1;
1052 }
1053 }
1054
1055
1056 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1062 public function fetch_lines()
1063 {
1064 // phpcs:enable
1065 $this->lines = array();
1066
1067 $sql = 'SELECT f.rowid, f.ref as ref_supplier, f.description as line_desc, f.date_start, f.date_end, f.pu_ht, f.pu_ttc, f.qty, f.remise_percent, f.vat_src_code, f.tva_tx';
1068 $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';
1069 $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, f.extraparams';
1070 $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';
1071 $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';
1072 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
1073 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
1074 $sql .= ' WHERE fk_facture_fourn='.((int) $this->id);
1075 $sql .= ' ORDER BY f.rang, f.rowid';
1076
1077 dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
1078
1079 $resql_rows = $this->db->query($sql);
1080 if ($resql_rows) {
1081 $num_rows = $this->db->num_rows($resql_rows);
1082 if ($num_rows) {
1083 $i = 0;
1084 while ($i < $num_rows) {
1085 $obj = $this->db->fetch_object($resql_rows);
1086
1087 $line = new SupplierInvoiceLine($this->db);
1088
1089 $line->id = $obj->rowid;
1090 $line->rowid = $obj->rowid;
1091
1092 $line->description = $obj->line_desc;
1093 $line->desc = $obj->line_desc;
1094 $line->date_start = $this->db->jdate($obj->date_start);
1095 $line->date_end = $this->db->jdate($obj->date_end);
1096
1097 $line->product_ref = $obj->product_ref;
1098 $line->ref = $obj->product_ref;
1099 $line->ref_supplier = $obj->ref_supplier;
1100 $line->libelle = $obj->label;
1101 $line->label = $obj->label;
1102 $line->product_barcode = $obj->product_barcode;
1103 $line->product_desc = $obj->product_desc;
1104 $line->subprice = $obj->pu_ht;
1105 $line->pu_ht = $obj->pu_ht; // deprecated
1106 $line->subprice_ttc = $obj->pu_ttc;
1107 $line->pu_ttc = $obj->pu_ttc; // deprcated
1108 $line->vat_src_code = $obj->vat_src_code;
1109 $line->tva_tx = $obj->tva_tx;
1110 $line->localtax1_tx = $obj->localtax1_tx;
1111 $line->localtax2_tx = $obj->localtax2_tx;
1112 $line->localtax1_type = $obj->localtax1_type;
1113 $line->localtax2_type = $obj->localtax2_type;
1114 $line->qty = $obj->qty;
1115 $line->remise_percent = $obj->remise_percent;
1116 $line->fk_remise_except = $obj->fk_remise_except;
1117 //$line->tva = $obj->total_tva; // deprecated
1118 $line->total_ht = $obj->total_ht;
1119 $line->total_ttc = $obj->total_ttc;
1120 $line->total_tva = $obj->total_tva;
1121 $line->total_localtax1 = $obj->total_localtax1;
1122 $line->total_localtax2 = $obj->total_localtax2;
1123 $line->fk_facture_fourn = $obj->fk_facture_fourn;
1124 $line->fk_product = $obj->fk_product;
1125 $line->product_type = $obj->product_type;
1126 $line->product_label = $obj->label;
1127 $line->info_bits = $obj->info_bits;
1128 $line->fk_parent_line = $obj->fk_parent_line;
1129 $line->special_code = $obj->special_code;
1130 $line->rang = $obj->rang;
1131 $line->fk_unit = $obj->fk_unit;
1132
1133 $line->extraparams = !empty($obj->extraparams) ? (array) json_decode($obj->extraparams, true) : array();
1134
1135 // Accountancy
1136 $line->fk_code_ventilation = $obj->fk_code_ventilation;
1137
1138 // Multicurrency
1139 $line->fk_multicurrency = $obj->fk_multicurrency;
1140 $line->multicurrency_code = $obj->multicurrency_code;
1141 $line->multicurrency_subprice = $obj->multicurrency_subprice;
1142 $line->multicurrency_total_ht = $obj->multicurrency_total_ht;
1143 $line->multicurrency_total_tva = $obj->multicurrency_total_tva;
1144 $line->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
1145
1146 // Extra fields
1147 $line->fetch_optionals();
1148
1149 $this->lines[$i] = $line;
1150
1151 $i++;
1152 }
1153 }
1154 $this->db->free($resql_rows);
1155 return 1;
1156 } else {
1157 $this->error = $this->db->error();
1158 dol_syslog(get_class($this)."::fetch_lines - No lines:{$this->error} Error:{$this->error}", LOG_DEBUG);
1159 return -3;
1160 }
1161 }
1162
1163
1171 public function update($user = null, $notrigger = 0)
1172 {
1173 global $langs;
1174 $error = 0;
1175
1176 // Clean parameters
1177 if (empty($this->type)) {
1178 $this->type = self::TYPE_STANDARD;
1179 }
1180 if (isset($this->ref)) {
1181 $this->ref = trim($this->ref);
1182 }
1183 if (isset($this->ref_supplier)) {
1184 $this->ref_supplier = trim($this->ref_supplier);
1185 }
1186 if (isset($this->ref_ext)) {
1187 $this->ref_ext = trim($this->ref_ext);
1188 }
1189 if (isset($this->entity)) {
1190 $this->entity = (int) $this->entity;
1191 }
1192 if (isset($this->type)) {
1193 $this->type = (int) $this->type;
1194 }
1195 if (isset($this->subtype)) {
1196 $this->subtype = (int) $this->subtype;
1197 }
1198 if (isset($this->socid)) {
1199 $this->socid = (int) $this->socid;
1200 }
1201 if (isset($this->label)) {
1202 $this->label = trim($this->label);
1203 }
1204 if (isset($this->paid)) {
1205 $this->paid = (int) (bool) $this->paid;
1206 $this->paye = $this->paid; // deprecated
1207 } elseif (isset($this->paye)) {
1208 $this->paid = (int) (bool) $this->paye;
1209 $this->paye = $this->paid; // deprecared
1210 }
1211 if (isset($this->close_code)) {
1212 $this->close_code = trim($this->close_code);
1213 }
1214 if (isset($this->close_note)) {
1215 $this->close_note = trim($this->close_note);
1216 }
1217 if (empty($this->total_ht)) {
1218 $this->total_ht = 0;
1219 }
1220 if (empty($this->total_tva)) {
1221 $this->total_tva = 0;
1222 }
1223 if (empty($this->total_localtax1)) {
1224 $this->total_localtax1 = 0;
1225 }
1226 if (empty($this->total_localtax2)) {
1227 $this->total_localtax2 = 0;
1228 }
1229 if (isset($this->total_ttc)) {
1230 $this->total_ttc = (float) $this->total_ttc;
1231 }
1232 if (isset($this->status)) {
1233 $this->status = (int) $this->status;
1234 $this->statut = $this->status;
1235 } elseif (isset($this->statut)) {
1236 $this->status = (int) $this->statut;
1237 $this->statut = $this->status;
1238 }
1239 if (isset($this->author)) { // TODO: user_creation_id?
1240 $this->author = (int) $this->author;
1241 }
1242 if (isset($this->fk_user_valid)) {
1243 $this->fk_user_valid = (int) $this->fk_user_valid;
1244 }
1245 if (isset($this->fk_facture_source)) {
1246 $this->fk_facture_source = (int) $this->fk_facture_source;
1247 }
1248 if (isset($this->fk_project)) {
1249 if (empty($this->fk_project)) {
1250 $this->fk_project = 0;
1251 } else {
1252 $this->fk_project = (int) $this->fk_project;
1253 }
1254 }
1255 if (isset($this->mode_reglement_id)) {
1256 $this->mode_reglement_id = (int) $this->mode_reglement_id;
1257 }
1258 if (isset($this->cond_reglement_id)) {
1259 $this->cond_reglement_id = (int) $this->cond_reglement_id;
1260 }
1261 if (isset($this->note_private)) {
1262 $this->note_private = trim($this->note_private);
1263 $this->note = $this->note_private;
1264 }
1265 if (isset($this->note_public)) {
1266 $this->note_public = trim($this->note_public);
1267 }
1268 if (isset($this->model_pdf)) {
1269 $this->model_pdf = trim($this->model_pdf);
1270 }
1271 if (isset($this->import_key)) {
1272 $this->import_key = trim($this->import_key);
1273 }
1274
1275
1276 // Check parameters
1277 // Put here code to add control on parameters values
1278
1279 if (dol_strlen((string) $this->date_modification) == 0) {
1280 $this->tms = dol_now();
1281 }
1282
1283 // Update request
1284 $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn SET";
1285 $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
1286 $sql .= " ref_supplier=".(isset($this->ref_supplier) ? "'".$this->db->escape($this->ref_supplier)."'" : "null").",";
1287 $sql .= " ref_ext=".(isset($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : "null").",";
1288 $sql .= " entity=".(isset($this->entity) ? ((int) $this->entity) : "null").",";
1289 $sql .= " type=".(isset($this->type) ? ((int) $this->type) : "null").",";
1290 $sql .= " subtype=".(isset($this->subtype) ? (int) $this->subtype : "null").",";
1291 $sql .= " fk_soc=".(isset($this->socid) ? ((int) $this->socid) : "null").",";
1292 $sql .= " datec=".(dol_strlen((string) $this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
1293 $sql .= " datef=".(dol_strlen((string) $this->date) != 0 ? "'".$this->db->idate($this->date)."'" : 'null').",";
1294 $sql .= " date_pointoftax=".(dol_strlen((string) $this->date_pointoftax) != 0 ? "'".$this->db->idate($this->date_pointoftax)."'" : 'null').",";
1295 if (dol_strlen((string) $this->date_modification) != 0) {
1296 $sql .= " tms=".(dol_strlen((string) $this->date_modification) != 0 ? "'".$this->db->idate($this->date_modification)."'" : 'null').",";
1297 } elseif (dol_strlen((string) $this->tms) != 0) { // For backward compatibility
1298 $sql .= " tms=".(dol_strlen((string) $this->tms) != 0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
1299 }
1300 $sql .= " libelle=".(isset($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
1301 $sql .= " paye=".(isset($this->paid) ? ((int) $this->paid) : "0").",";
1302 $sql .= " close_code=".(isset($this->close_code) ? "'".$this->db->escape($this->close_code)."'" : "null").",";
1303 $sql .= " close_note=".(isset($this->close_note) ? "'".$this->db->escape($this->close_note)."'" : "null").",";
1304 $sql .= " localtax1=".(isset($this->total_localtax1) ? ((float) $this->total_localtax1) : "null").",";
1305 $sql .= " localtax2=".(isset($this->total_localtax2) ? ((float) $this->total_localtax2) : "null").",";
1306 $sql .= " total_ht=".(isset($this->total_ht) ? ((float) $this->total_ht) : "null").",";
1307 $sql .= " total_tva=".(isset($this->total_tva) ? ((float) $this->total_tva) : "null").",";
1308 $sql .= " total_ttc=".(isset($this->total_ttc) ? ((float) $this->total_ttc) : "null").",";
1309 $sql .= " fk_statut=".(isset($this->status) ? ((int) $this->status) : (isset($this->statut) ? ((int) $this->statut) : "null")).",";
1310 $sql .= " fk_user_author=".(isset($this->author) ? ((int) $this->author) : "null").",";
1311 $sql .= " fk_user_valid=".(isset($this->fk_user_valid) ? ((int) $this->fk_user_valid) : "null").",";
1312 $sql .= " fk_facture_source=".($this->fk_facture_source ? ((int) $this->fk_facture_source) : "null").",";
1313 $sql .= " vat_reverse_charge = ".($this->vat_reverse_charge != '' ? ((int) $this->vat_reverse_charge) : 0).",";
1314 $sql .= " fk_projet=".(!empty($this->fk_project) ? ((int) $this->fk_project) : "null").",";
1315 $sql .= " fk_mode_reglement=".(isset($this->mode_reglement_id) ? ((int) $this->mode_reglement_id) : "null").",";
1316 $sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? ((int) $this->cond_reglement_id) : "null").",";
1317 $sql .= " date_lim_reglement=".(dol_strlen((string) $this->date_echeance) != 0 ? "'".$this->db->idate($this->date_echeance)."'" : 'null').",";
1318 $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
1319 $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
1320 $sql .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
1321 $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null");
1322 $sql .= " WHERE rowid=".((int) $this->id);
1323
1324 $this->db->begin();
1325
1326 dol_syslog(get_class($this)."::update", LOG_DEBUG);
1327 $resql = $this->db->query($sql);
1328
1329 if (!$resql) {
1330 $error++;
1331
1332 if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1333 $this->errors[] = $langs->trans('ErrorRefAlreadyExists');
1334 } else {
1335 $this->errors[] = "Error ".$this->db->lasterror();
1336 }
1337 }
1338
1339 if (!$error) {
1340 $result = $this->insertExtraFields();
1341 if ($result < 0) {
1342 $error++;
1343 }
1344 }
1345
1346 if (!$error) {
1347 if (!$notrigger) {
1348 // Call trigger
1349 $result = $this->call_trigger('BILL_SUPPLIER_MODIFY', $user);
1350 if ($result < 0) {
1351 $error++;
1352 }
1353 // End call triggers
1354 }
1355 }
1356
1357 // Commit or rollback
1358 if ($error) {
1359 foreach ($this->errors as $errmsg) {
1360 dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
1361 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1362 }
1363 $this->db->rollback();
1364 return -1 * $error;
1365 } else {
1366 $this->db->commit();
1367 return 1;
1368 }
1369 }
1370
1371 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1378 public function insert_discount($idremise)
1379 {
1380 // phpcs:enable
1381 global $conf, $langs;
1382
1383 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1384 include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
1385
1386 $this->db->begin();
1387
1388 $remise = new DiscountAbsolute($this->db);
1389 $result = $remise->fetch($idremise);
1390
1391 if ($result > 0) {
1392 if ($this->socid > 0 && $remise->fk_soc != $this->socid) { // The discount must belong to the thirdparty of the invoice
1393 $this->error = $langs->trans("ErrorDiscountNotSameCompany");
1394 $this->db->rollback();
1395 return -6;
1396 }
1397 if ($remise->fk_invoice_supplier) { // Protection against multiple submission
1398 $this->error = $langs->trans("ErrorDiscountAlreadyUsed");
1399 $this->db->rollback();
1400 return -5;
1401 }
1402
1403 $facligne = new SupplierInvoiceLine($this->db);
1404 $facligne->fk_facture_fourn = $this->id;
1405 $facligne->fk_remise_except = $remise->id;
1406 $facligne->desc = $remise->description; // Description ligne
1407 $facligne->vat_src_code = $remise->vat_src_code;
1408 $facligne->tva_tx = $remise->tva_tx;
1409 $facligne->subprice = -(float) $remise->amount_ht;
1410 $facligne->fk_product = 0; // Id produit predefini
1411 $facligne->product_type = 0;
1412 $facligne->qty = 1;
1413 $facligne->remise_percent = 0;
1414 $facligne->rang = -1;
1415 $facligne->info_bits = 2;
1416
1417 if (getDolGlobalString('MAIN_ADD_LINE_AT_POSITION')) {
1418 $facligne->rang = 1;
1419 $linecount = count($this->lines);
1420 for ($ii = 1; $ii <= $linecount; $ii++) {
1421 $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1);
1422 }
1423 }
1424
1425 // Get buy/cost price of invoice that is source of discount
1426 if ($remise->fk_invoice_supplier_source > 0) {
1427 $srcinvoice = new FactureFournisseur($this->db);
1428 $srcinvoice->fetch($remise->fk_invoice_supplier_source);
1429 $totalcostpriceofinvoice = 0;
1430 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php'; // TODO Move this into commonobject
1431 $formmargin = new FormMargin($this->db);
1432 $arraytmp = $formmargin->getMarginInfosArray($srcinvoice, false);
1433 $facligne->pa_ht = $arraytmp['pa_total'];
1434 }
1435
1436 $facligne->total_ht = -(float) $remise->amount_ht;
1437 $facligne->total_tva = -(float) $remise->amount_tva;
1438 $facligne->total_ttc = -(float) $remise->amount_ttc;
1439
1440 $facligne->multicurrency_subprice = -$remise->multicurrency_subprice;
1441 $facligne->multicurrency_total_ht = -$remise->multicurrency_total_ht;
1442 $facligne->multicurrency_total_tva = -$remise->multicurrency_total_tva;
1443 $facligne->multicurrency_total_ttc = -$remise->multicurrency_total_ttc;
1444
1445 $lineid = $facligne->insert();
1446 if ($lineid > 0) {
1447 $result = $this->update_price(1);
1448 if ($result > 0) {
1449 // Create link between discount and invoice line
1450 $result = $remise->link_to_invoice($lineid, 0);
1451 if ($result < 0) {
1452 $this->error = $remise->error;
1453 $this->db->rollback();
1454 return -4;
1455 }
1456
1457 $this->db->commit();
1458 return 1;
1459 } else {
1460 $this->error = $facligne->error;
1461 $this->db->rollback();
1462 return -1;
1463 }
1464 } else {
1465 $this->error = $facligne->error;
1466 $this->db->rollback();
1467 return -2;
1468 }
1469 } else {
1470 $this->db->rollback();
1471 return -3;
1472 }
1473 }
1474
1475
1483 public function delete(User $user, $notrigger = 0)
1484 {
1485 global $conf;
1486
1487 $rowid = $this->id;
1488
1489 dol_syslog("FactureFournisseur::delete rowid=".$rowid, LOG_DEBUG);
1490
1491 // Test to avoid invoice deletion (invoice transferred into accountancy, with payment, ...), same test as Facture::delete() does
1492 $result = $this->is_erasable();
1493 if ($result <= 0) {
1494 dol_syslog(get_class($this)."::delete refused, invoice is not erasable (code ".$result.")", LOG_DEBUG);
1495 return 0;
1496 }
1497
1498 $error = 0;
1499 $this->db->begin();
1500
1501 if (!$notrigger) {
1502 // Call trigger
1503 $result = $this->call_trigger('BILL_SUPPLIER_DELETE', $user);
1504 if ($result < 0) {
1505 $this->db->rollback();
1506 return -1;
1507 }
1508 // Fin appel triggers
1509 }
1510
1511 // Remove linked categories.
1512 $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_supplier_invoice";
1513 $sql .= " WHERE fk_supplier_invoice = ".((int) $this->id);
1514
1515 $result = $this->db->query($sql);
1516 if (!$result) {
1517 $error++;
1518 $this->error = $this->db->lasterror();
1519 $this->errors[] = $this->error;
1520 }
1521
1522 if (!$error) {
1523 // If invoice was converted into a discount not yet consumed, we remove discount
1524 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'societe_remise_except';
1525 $sql .= ' WHERE fk_invoice_supplier_source = '.((int) $rowid);
1526 $sql .= ' AND fk_invoice_supplier_line IS NULL';
1527 $resql = $this->db->query($sql);
1528
1529 // If invoice has consumned discounts
1530 $this->fetch_lines();
1531 $list_rowid_det = array();
1532 foreach ($this->lines as $key => $invoiceline) {
1533 $list_rowid_det[] = $invoiceline->id;
1534 }
1535
1536 // Consumned discounts are freed
1537 if (count($list_rowid_det)) {
1538 $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
1539 $sql .= ' SET fk_invoice_supplier = NULL, fk_invoice_supplier_line = NULL';
1540 $sql .= ' WHERE fk_invoice_supplier_line IN ('.$this->db->sanitize(implode(',', $list_rowid_det)).')';
1541
1542 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1543 if (!$this->db->query($sql)) {
1544 $error++;
1545 }
1546 }
1547 }
1548
1549 if (!$error) {
1550 $main = MAIN_DB_PREFIX.'facture_fourn_det';
1551 $ef = $main."_extrafields";
1552 $sqlef = "DELETE FROM $ef WHERE fk_object IN (SELECT rowid FROM ".$main." WHERE fk_facture_fourn = ".((int) $rowid).")";
1553 $resqlef = $this->db->query($sqlef);
1554 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det WHERE fk_facture_fourn = '.((int) $rowid);
1555 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1556 $resql = $this->db->query($sql);
1557 if ($resqlef && $resql) {
1558 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn WHERE rowid = '.((int) $rowid);
1559 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1560 $resql2 = $this->db->query($sql);
1561 if (!$resql2) {
1562 $error++;
1563 }
1564 } else {
1565 $error++;
1566 }
1567 }
1568
1569 if (!$error) {
1570 // Delete linked object
1571 $res = $this->deleteObjectLinked();
1572 if ($res < 0) {
1573 $error++;
1574 }
1575 }
1576
1577 if (!$error) {
1578 // Delete record into ECM index (Note that delete is also done when deleting files with the dol_delete_dir_recursive
1579 $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
1580 $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive
1581
1582 // We remove directory
1583 $ref = dol_sanitizeFileName($this->ref);
1584 if ($conf->fournisseur->facture->dir_output && !empty($ref)) {
1585 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1586
1587 $dir = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$ref;
1588 $file = $dir."/".$ref.".pdf";
1589 if (file_exists($file)) {
1590 if (!dol_delete_file($file, 0, 0, 0, $this)) { // For triggers
1591 $this->error = 'ErrorFailToDeleteFile';
1592 $error++;
1593 }
1594 }
1595 if (file_exists($dir)) {
1596 $res = @dol_delete_dir_recursive($dir);
1597
1598 if (!$res) {
1599 $this->error = 'ErrorFailToDeleteDir';
1600 $error++;
1601 }
1602 }
1603 }
1604 }
1605
1606 // Remove extrafields
1607 if (!$error) {
1608 $result = $this->deleteExtraFields();
1609 if ($result < 0) {
1610 $error++;
1611 dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1612 }
1613 }
1614
1615 if (!$error) {
1616 dol_syslog(get_class($this)."::delete $this->id by $user->id", LOG_DEBUG);
1617 $this->db->commit();
1618 return 1;
1619 } else {
1620 $this->error = $this->db->lasterror();
1621 $this->db->rollback();
1622 return -$error;
1623 }
1624 }
1625
1626
1627 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1638 public function set_paid($user, $close_code = '', $close_note = '')
1639 {
1640 // phpcs:enable
1641 dol_syslog(get_class($this)."::set_paid is deprecated, use setPaid instead", LOG_NOTICE);
1642 return $this->setPaid($user, $close_code, $close_note);
1643 }
1644
1653 public function setPaid($user, $close_code = '', $close_note = '')
1654 {
1655 $error = 0;
1656
1657 if ($this->paid != 1) {
1658 $this->db->begin();
1659
1660 $now = dol_now();
1661
1662 dol_syslog("FactureFournisseur::setPaid", LOG_DEBUG);
1663
1664 $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn SET';
1665 $sql .= ' fk_statut = '.self::STATUS_CLOSED;
1666 if (!$close_code) {
1667 $sql .= ', paye=1';
1668 }
1669 if ($close_code) {
1670 $sql .= ", close_code='".$this->db->escape($close_code)."'";
1671 }
1672 if ($close_note) {
1673 $sql .= ", close_note='".$this->db->escape($close_note)."'";
1674 }
1675 $sql .= ', fk_user_closing = '.((int) $user->id);
1676 $sql .= ", date_closing = '".$this->db->idate($now)."'";
1677 $sql .= ' WHERE rowid = '.((int) $this->id);
1678
1679 $resql = $this->db->query($sql);
1680 if ($resql) {
1681 // Call trigger
1682 $result = $this->call_trigger('BILL_SUPPLIER_PAYED', $user);
1683 if ($result < 0) {
1684 $error++;
1685 }
1686 // End call triggers
1687 } else {
1688 $error++;
1689 $this->error = $this->db->error();
1690 dol_print_error($this->db);
1691 }
1692
1693 if (!$error) {
1694 $this->db->commit();
1695 return 1;
1696 } else {
1697 $this->db->rollback();
1698 return -1;
1699 }
1700 } else {
1701 return 0;
1702 }
1703 }
1704
1705 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1716 public function set_unpaid($user)
1717 {
1718 // phpcs:enable
1719 dol_syslog(get_class($this)."::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE);
1720 return $this->setUnpaid($user);
1721 }
1722
1731 public function setUnpaid($user)
1732 {
1733 $error = 0;
1734
1735 $this->db->begin();
1736
1737 $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn';
1738 $sql .= ' SET paye=0, fk_statut='.self::STATUS_VALIDATED.', close_code=null, close_note=null,';
1739 $sql .= ' date_closing=null,';
1740 $sql .= ' fk_user_closing=null';
1741 $sql .= ' WHERE rowid = '.((int) $this->id);
1742
1743 dol_syslog(get_class($this)."::set_unpaid", LOG_DEBUG);
1744 $resql = $this->db->query($sql);
1745 if ($resql) {
1746 // Call trigger
1747 $result = $this->call_trigger('BILL_SUPPLIER_UNPAYED', $user);
1748 if ($result < 0) {
1749 $error++;
1750 }
1751 // End call triggers
1752 } else {
1753 $error++;
1754 $this->error = $this->db->error();
1755 dol_print_error($this->db);
1756 }
1757
1758 if (!$error) {
1759 $this->db->commit();
1760 return 1;
1761 } else {
1762 $this->db->rollback();
1763 return -1;
1764 }
1765 }
1766
1777 public function setCanceled($user, $close_code = '', $close_note = '')
1778 {
1779 dol_syslog(get_class($this)."::setCanceled rowid=".((int) $this->id), LOG_DEBUG);
1780
1781 $this->db->begin();
1782
1783 $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn SET';
1784 $sql .= ' fk_statut='.self::STATUS_ABANDONED;
1785 if ($close_code) {
1786 $sql .= ", close_code='".$this->db->escape($close_code)."'";
1787 }
1788 if ($close_note) {
1789 $sql .= ", close_note='".$this->db->escape($close_note)."'";
1790 }
1791 $sql .= " WHERE rowid = ".((int) $this->id);
1792
1793 $resql = $this->db->query($sql);
1794 if ($resql) {
1795 // Bound discounts are deducted from the invoice
1796 // as they have not been used since the invoice is abandoned.
1797 $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
1798 $sql .= ' SET fk_invoice_supplier = NULL';
1799 $sql .= ' WHERE fk_invoice_supplier = '.((int) $this->id);
1800
1801 $resql = $this->db->query($sql);
1802 if ($resql) {
1803 // Call trigger
1804 $result = $this->call_trigger('BILL_SUPPLIER_CANCEL', $user);
1805 if ($result < 0) {
1806 $this->db->rollback();
1807 return -1;
1808 }
1809 // End call triggers
1810
1811 $this->db->commit();
1812 return 1;
1813 } else {
1814 $this->error = $this->db->error()." sql=".$sql;
1815 $this->db->rollback();
1816 return -1;
1817 }
1818 } else {
1819 $this->error = $this->db->error()." sql=".$sql;
1820 $this->db->rollback();
1821 return -2;
1822 }
1823 }
1824
1834 public function validate($user, $force_number = '', $idwarehouse = 0, $notrigger = 0)
1835 {
1836 global $mysoc, $conf, $langs;
1837
1838 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1839
1840 $now = dol_now();
1841
1842 $error = 0;
1843 dol_syslog(get_class($this).'::validate user='.$user->id.', force_number='.$force_number.', idwarehouse='.$idwarehouse);
1844
1845 // Force to have object complete for checks
1846 $this->fetch_thirdparty();
1847 $this->fetch_lines();
1848
1849 // Check parameters
1850 if ($this->status > self::STATUS_DRAFT) { // This is to avoid to validate twice (avoid errors on logs and stock management)
1851 dol_syslog(get_class($this)."::validate no draft status", LOG_WARNING);
1852 return 0;
1853 }
1854 if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ', '/').'/', $this->ref_supplier)) {
1855 $langs->load("errors");
1856 $this->error = $langs->trans("ErrorFieldFormat", $langs->transnoentities("RefSupplier")).'. '.$langs->trans('RemoveString', $langs->transnoentitiesnoconv("CopyOf"));
1857 return -1;
1858 }
1859 if (count($this->lines) <= 0) {
1860 $langs->load("errors");
1861 $this->error = $langs->trans("ErrorObjectMustHaveLinesToBeValidated", $this->ref);
1862 return -1;
1863 }
1864
1865 // Check for mandatory fields in thirdparty (defined into setup)
1866 if (!empty($this->thirdparty) && is_object($this->thirdparty)) {
1867 $array_to_check = array('IDPROF1', 'IDPROF2', 'IDPROF3', 'IDPROF4', 'IDPROF5', 'IDPROF6', 'EMAIL', 'ACCOUNTANCY_CODE_SUPPLIER');
1868 foreach ($array_to_check as $key) {
1869 $keymin = strtolower($key);
1870 if ($keymin == 'accountancy_code_supplier') {
1871 $keymin = 'code_compta_fournisseur';
1872 }
1873 if (!property_exists($this->thirdparty, $keymin)) {
1874 continue;
1875 }
1876 $vallabel = $this->thirdparty->$keymin;
1877
1878 $i = (int) preg_replace('/[^0-9]/', '', $key);
1879 if ($i > 0) {
1880 if ($this->thirdparty->isACompany()) {
1881 // Check for mandatory prof id (but only if country is other than ours)
1882 if ($mysoc->country_id > 0 && $this->thirdparty->country_id == $mysoc->country_id) {
1883 $idprof_mandatory = 'SOCIETE_'.$key.'_INVOICE_MANDATORY';
1884 if (!$vallabel && getDolGlobalString($idprof_mandatory)) {
1885 $langs->load("errors");
1886 $this->error = $langs->trans('ErrorProdIdIsMandatory', $langs->transcountry('ProfId'.$i, $this->thirdparty->country_code)).' ('.$langs->trans("ForbiddenBySetupRules").') ['.$langs->trans('Company').' : '.$this->thirdparty->name.']';
1887 dol_syslog(__METHOD__.' '.$this->error, LOG_ERR);
1888 return -1;
1889 }
1890 }
1891 }
1892 } else {
1893 if ($key == 'EMAIL') {
1894 // Check for mandatory
1895 if (getDolGlobalString('SOCIETE_EMAIL_INVOICE_MANDATORY') && !isValidEmail($this->thirdparty->email)) {
1896 $langs->load("errors");
1897 $this->error = $langs->trans("ErrorBadEMail", $this->thirdparty->email).' ('.$langs->trans("ForbiddenBySetupRules").') ['.$langs->trans('Company').' : '.$this->thirdparty->name.']';
1898 dol_syslog(__METHOD__.' '.$this->error, LOG_ERR);
1899 return -1;
1900 }
1901 } elseif ($key == 'ACCOUNTANCY_CODE_SUPPLIER') {
1902 // Check for mandatory
1903 if (getDolGlobalString('SOCIETE_ACCOUNTANCY_CODE_SUPPLIER_INVOICE_MANDATORY') && empty($this->thirdparty->code_compta_fournisseur)) {
1904 $langs->load("errors");
1905 $this->error = $langs->trans("ErrorAccountancyCodeSupplierIsMandatory", $this->thirdparty->name).' ('.$langs->trans("ForbiddenBySetupRules").')';
1906 dol_syslog(__METHOD__.' '.$this->error, LOG_ERR);
1907 return -1;
1908 }
1909 }
1910 }
1911 }
1912 }
1913
1914 $this->db->begin();
1915
1916 // Define new ref
1917 if ($force_number) {
1918 $num = $force_number;
1919 } elseif (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
1920 $num = $this->getNextNumRef($this->thirdparty);
1921 } else {
1922 $num = (string) $this->ref;
1923 }
1924 $this->newref = dol_sanitizeFileName($num);
1925
1926 $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
1927 $sql .= " SET ref='".$this->db->escape($num)."', fk_statut = 1, fk_user_valid = ".((int) $user->id).", date_valid = '".$this->db->idate($now)."'";
1928 $sql .= " WHERE rowid = ".((int) $this->id);
1929
1930 dol_syslog(get_class($this)."::validate", LOG_DEBUG);
1931 $resql = $this->db->query($sql);
1932 if ($resql) {
1933 // Si on incrémente le produit principal et ses composants à la validation de facture fournisseur
1934 if (isModEnabled('stock') && getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_BILL')) {
1935 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1936 $langs->load("agenda");
1937
1938 $cpt = count($this->lines);
1939 for ($i = 0; $i < $cpt; $i++) {
1940 if ($this->lines[$i]->fk_product > 0) {
1941 $mouvP = new MouvementStock($this->db);
1942 $mouvP->origin = &$this;
1943 $mouvP->setOrigin($this->element, $this->id);
1944 // We increase stock for product
1945 $up_ht_disc = $this->lines[$i]->subprice;
1946 if (!empty($this->lines[$i]->remise_percent) && !getDolGlobalString('STOCK_EXCLUDE_DISCOUNT_FOR_PMP')) {
1947 $up_ht_disc = price2num($up_ht_disc * (100 - $this->lines[$i]->remise_percent) / 100, 'MU');
1948 }
1950 $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1951 } else {
1952 $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num));
1953 }
1954 if ($result < 0) {
1955 $this->setErrorsFromObject($mouvP);
1956 return -2;
1957 }
1958 }
1959 }
1960 }
1961
1962 // Triggers call
1963 if (empty($notrigger)) {
1964 // Call trigger
1965 $result = $this->call_trigger('BILL_SUPPLIER_VALIDATE', $user);
1966 if ($result < 0) {
1967 $error++;
1968 }
1969 // End call triggers
1970 }
1971
1972 if (!$error) {
1973 $this->oldref = $this->ref;
1974
1975 // Rename directory if dir was a temporary ref
1976 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
1977 // Now we rename also files into index
1978 $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)."'";
1979 $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;
1980 $resql = $this->db->query($sql);
1981 if (!$resql) {
1982 $error++;
1983 $this->error = $this->db->lasterror();
1984 }
1985 $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)."'";
1986 $sql .= " WHERE filepath = 'fournisseur/facture/".get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1987 $resql = $this->db->query($sql);
1988 if (!$resql) {
1989 $error++;
1990 $this->error = $this->db->lasterror();
1991 }
1992
1993 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1994 $oldref = dol_sanitizeFileName($this->ref);
1995 $dirsource = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$oldref;
1996 $dirdest = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier').$this->newref;
1997 if (!$error && file_exists($dirsource)) {
1998 dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest);
1999
2000 if (@rename($dirsource, $dirdest)) {
2001 dol_syslog("Rename ok");
2002 // Rename docs starting with $oldref with $this->newref
2003 $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, '/'));
2004 foreach ($listoffiles as $fileentry) {
2005 $dirsource = $fileentry['name'];
2006 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $this->newref, $dirsource);
2007 $dirsource = $fileentry['path'].'/'.$dirsource;
2008 $dirdest = $fileentry['path'].'/'.$dirdest;
2009 @rename($dirsource, $dirdest);
2010 }
2011 }
2012 }
2013 }
2014 }
2015
2016 // Set new ref and define current status
2017 if (!$error) {
2018 $this->ref = $this->newref;
2019 $this->statut = self::STATUS_VALIDATED;
2021 //$this->date_validation=$now; this is stored into log table
2022 }
2023
2024 if (!$error) {
2025 $this->db->commit();
2026 return 1;
2027 } else {
2028 $this->db->rollback();
2029 return -1;
2030 }
2031 } else {
2032 $this->error = $this->db->error();
2033 $this->db->rollback();
2034 return -1;
2035 }
2036 }
2037
2046 public function setDraft($user, $idwarehouse = -1, $notrigger = 0)
2047 {
2048 // phpcs:enable
2049 global $conf, $langs;
2050
2051 $error = 0;
2052
2053 if ($this->status == self::STATUS_DRAFT) {
2054 dol_syslog(__METHOD__." already draft status", LOG_WARNING);
2055 return 0;
2056 }
2057
2058 dol_syslog(__METHOD__, LOG_DEBUG);
2059
2060 $this->db->begin();
2061
2062 $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
2063 $sql .= " SET fk_statut = ".self::STATUS_DRAFT;
2064 $sql .= " WHERE rowid = ".((int) $this->id);
2065
2066 $result = $this->db->query($sql);
2067 if ($result) {
2068 $this->oldcopy = clone $this;
2069
2070 // Si on incremente le produit principal et ses composants a la validation de facture fournisseur, on decremente
2071 if ($result >= 0 && isModEnabled('stock') && getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_BILL')) {
2072 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
2073 $langs->load("agenda");
2074
2075 $cpt = count($this->lines);
2076 for ($i = 0; $i < $cpt; $i++) {
2077 if ($this->lines[$i]->fk_product > 0) {
2078 $mouvP = new MouvementStock($this->db);
2079 $mouvP->origin = &$this;
2080 $mouvP->setOrigin($this->element, $this->id);
2081 // We increase stock for product
2083 $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->transnoentitiesnoconv("InvoiceBackToDraftInDolibarr", $this->ref));
2084 } else {
2085 $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->transnoentitiesnoconv("InvoiceBackToDraftInDolibarr", $this->ref));
2086 }
2087 if ($result < 0) {
2088 $error++;
2089 $this->setErrorsFromObject($mouvP);
2090 dol_syslog(__METHOD__." stock movement failed for line ".$i.": ".$mouvP->error, LOG_ERR);
2091 break;
2092 }
2093 }
2094 }
2095 }
2096 // Triggers call
2097 if (!$error && empty($notrigger)) {
2098 // Call trigger
2099 $result = $this->call_trigger('BILL_SUPPLIER_UNVALIDATE', $user);
2100 if ($result < 0) {
2101 $error++;
2102 }
2103 // End call triggers
2104 }
2105 if ($error == 0) {
2106 $this->db->commit();
2107 return 1;
2108 } else {
2109 $this->db->rollback();
2110 return -1;
2111 }
2112 } else {
2113 $this->error = $this->db->error();
2114 $this->db->rollback();
2115 return -1;
2116 }
2117 }
2118
2119
2153 public function addline($desc, $pu, $txtva, $txlocaltax1, $txlocaltax2, $qty, $fk_product = 0, $remise_percent = 0, $date_start = 0, $date_end = 0, $fk_code_ventilation = 0, $info_bits = 0, $price_base_type = 'HT', $type = 0, $rang = -1, $notrigger = 0, $array_options = [], $fk_unit = null, $origin_id = 0, $pu_devise = 0, $ref_supplier = '', $special_code = 0, $fk_parent_line = 0, $fk_remise_except = 0)
2154 {
2155 global $langs, $mysoc;
2156
2157 dol_syslog(get_class($this)."::addline $desc,$pu,$qty,$txtva,$fk_product,$remise_percent,$date_start,$date_end,$fk_code_ventilation,$info_bits,$price_base_type,$type,$fk_unit,fk_remise_except=$fk_remise_except", LOG_DEBUG);
2158 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2159
2160 if ($this->status == self::STATUS_DRAFT) {
2161 // Clean parameters
2162 if (empty($remise_percent)) {
2163 $remise_percent = 0;
2164 }
2165 if (empty($qty)) {
2166 $qty = 0;
2167 }
2168 if (empty($info_bits)) {
2169 $info_bits = 0;
2170 }
2171 if (empty($rang)) {
2172 $rang = 0;
2173 }
2174 if (empty($fk_code_ventilation)) {
2175 $fk_code_ventilation = 0;
2176 }
2177 if (empty($txtva)) {
2178 $txtva = 0;
2179 }
2180 if (empty($txlocaltax1)) {
2181 $txlocaltax1 = 0;
2182 }
2183 if (empty($txlocaltax2)) {
2184 $txlocaltax2 = 0;
2185 }
2186
2187 $remise_percent = price2num($remise_percent);
2188 $qty = price2num($qty);
2189 $pu = price2num($pu);
2190 if (!preg_match('/\‍((.*)\‍)/', (string) $txtva)) {
2191 $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
2192 }
2193 $txlocaltax1 = price2num($txlocaltax1);
2194 $txlocaltax2 = price2num($txlocaltax2);
2195
2196 if ($date_start && $date_end && $date_start > $date_end) {
2197 $langs->load("errors");
2198 $this->error = $langs->trans('ErrorStartDateGreaterEnd');
2199 return -1;
2200 }
2201
2202 $this->db->begin();
2203
2204 if ($fk_product > 0) {
2205 if (getDolGlobalInt('SUPPLIER_INVOICE_WITH_PREDEFINED_PRICES_ONLY') == 1) { // Not the common case
2206 // Check quantity is enough
2207 dol_syslog(get_class($this)."::addline we check supplier prices fk_product=".$fk_product." qty=".$qty." ref_supplier=".$ref_supplier);
2208 $prod = new ProductFournisseur($this->db);
2209 if ($prod->fetch($fk_product) > 0) {
2210 $product_type = $prod->type;
2211 $label = $prod->label;
2212 $fk_prod_fourn_price = 0;
2213
2214 // We use 'none' instead of $ref_supplier, because $ref_supplier may not exists anymore. So we will take the first supplier price ok.
2215 // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
2216 $result = $prod->get_buyprice($fk_prod_fourn_price, (float) $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
2217 if ($result > 0) {
2218 if (empty($pu)) {
2219 $pu = $prod->fourn_pu; // Unit price supplier price set by get_buyprice
2220 }
2221 $ref_supplier = $prod->ref_supplier; // Ref supplier price set by get_buyprice
2222 // is remise percent not keyed but present for the product we add it
2223 if ($remise_percent == 0 && $prod->remise_percent != 0) {
2224 $remise_percent = $prod->remise_percent;
2225 }
2226 }
2227 if ($result == 0) { // If result == 0, we failed to found the supplier reference price
2228 $langs->load("errors");
2229 $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
2230 $this->db->rollback();
2231 dol_syslog(get_class($this)."::addline we did not found supplier price, so we can't guess unit price");
2232 //$pu = $prod->fourn_pu; // We do not overwrite unit price
2233 //$ref = $prod->ref_fourn; // We do not overwrite ref supplier price
2234 return -1;
2235 }
2236 if ($result == -1) {
2237 $langs->load("errors");
2238 $this->error = "Ref ".$prod->ref." ".$langs->trans("ErrorQtyTooLowForThisSupplier");
2239 $this->db->rollback();
2240 dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_DEBUG);
2241 return -1;
2242 }
2243 if ($result < -1) {
2244 $this->error = $prod->error;
2245 $this->db->rollback();
2246 dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_ERR);
2247 return -1;
2248 }
2249 } else {
2250 $this->error = $prod->error;
2251 $this->db->rollback();
2252 return -1;
2253 }
2254 }
2255 } else {
2256 $product_type = $type;
2257 }
2258
2259 if (isModEnabled("multicurrency") && $pu_devise > 0) {
2260 $pu = 0;
2261 }
2262
2263 $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $mysoc, $this->thirdparty);
2264
2265 // Clean vat code
2266 $reg = array();
2267 $vat_src_code = '';
2268 if (preg_match('/\‍((.*)\‍)/', $txtva, $reg)) {
2269 $vat_src_code = $reg[1];
2270 $txtva = preg_replace('/\s*\‍(.*\‍)/', '', $txtva); // Remove code into vatrate.
2271 }
2272
2273 // Calcul du total TTC et de la TVA pour la ligne a partir de
2274 // qty, pu, remise_percent et txtva
2275 // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2276 // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2277
2278 $tabprice = calcul_price_total((float) $qty, $pu, $remise_percent, $txtva, (float) $txlocaltax1, (float) $txlocaltax2, 0, $price_base_type, $info_bits, $type, $this->thirdparty, $localtaxes_type, 100, $this->multicurrency_tx, $pu_devise);
2279 $total_ht = $tabprice[0];
2280 $total_tva = $tabprice[1];
2281 $total_ttc = $tabprice[2];
2282 $total_localtax1 = $tabprice[9];
2283 $total_localtax2 = $tabprice[10];
2284 $pu_ht = $tabprice[3];
2285
2286 // MultiCurrency
2287 $multicurrency_total_ht = $tabprice[16];
2288 $multicurrency_total_tva = $tabprice[17];
2289 $multicurrency_total_ttc = $tabprice[18];
2290 $pu_ht_devise = $tabprice[19];
2291
2292 // Check parameters
2293 if ($type < 0) {
2294 return -1;
2295 }
2296
2297 if ($rang < 0) {
2298 $rangmax = $this->line_max();
2299 $rang = $rangmax + 1;
2300 }
2301
2302 // The -abs() forcing on credit note lines is relaxed only when both FACTURE_ENABLE_NEGATIVE_LINES and
2303 // INVOICE_KEEP_DISCOUNT_LINES_AS_IN_ORIGIN are enabled, the gate of the customer side from 23.0 on.
2304 $apply_abs_price_on_credit_note = false;
2305 if ($this->type == self::TYPE_CREDIT_NOTE && !(getDolGlobalInt('FACTURE_ENABLE_NEGATIVE_LINES') && getDolGlobalInt('INVOICE_KEEP_DISCOUNT_LINES_AS_IN_ORIGIN'))) {
2306 $apply_abs_price_on_credit_note = true;
2307 }
2308
2309 // Insert line
2310 $supplierinvoiceline = new SupplierInvoiceLine($this->db);
2311
2312 $supplierinvoiceline->context = $this->context;
2313
2314 $supplierinvoiceline->fk_facture_fourn = $this->id;
2315 //$supplierinvoiceline->label=$label; // deprecated
2316 $supplierinvoiceline->desc = $desc;
2317 $supplierinvoiceline->ref_supplier = $ref_supplier;
2318
2319 $supplierinvoiceline->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs((float) $qty) : (float) $qty); // For credit note, quantity is always positive and unit price negative
2320 $supplierinvoiceline->subprice = ($apply_abs_price_on_credit_note ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise
2321
2322 $supplierinvoiceline->vat_src_code = $vat_src_code;
2323 $supplierinvoiceline->tva_tx = $txtva;
2324 $supplierinvoiceline->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
2325 $supplierinvoiceline->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
2326 $supplierinvoiceline->localtax1_type = empty($localtaxes_type[0]) ? 0 : $localtaxes_type[0];
2327 $supplierinvoiceline->localtax2_type = empty($localtaxes_type[2]) ? 0 : $localtaxes_type[2];
2328
2329 $supplierinvoiceline->total_ht = (($apply_abs_price_on_credit_note || $qty < 0) ? -abs((float) $total_ht) : (float) $total_ht); // For credit note and if qty is negative, total is negative
2330 $supplierinvoiceline->total_tva = (($apply_abs_price_on_credit_note || $qty < 0) ? -abs((float) $total_tva) : (float) $total_tva); // For credit note and if qty is negative, total is negative
2331 $supplierinvoiceline->total_localtax1 = (($apply_abs_price_on_credit_note || $qty < 0) ? -abs((float) $total_localtax1) : (float) $total_localtax1); // For credit note and if qty is negative, total is negative
2332 $supplierinvoiceline->total_localtax2 = (($apply_abs_price_on_credit_note || $qty < 0) ? -abs((float) $total_localtax2) : (float) $total_localtax2); // For credit note and if qty is negative, total is negative
2333 $supplierinvoiceline->total_ttc = (($apply_abs_price_on_credit_note || $qty < 0) ? -abs((float) $total_ttc) : (float) $total_ttc); // For credit note and if qty is negative, total is negative
2334
2335 $supplierinvoiceline->fk_product = $fk_product;
2336 $supplierinvoiceline->product_type = $type;
2337 $supplierinvoiceline->remise_percent = $remise_percent;
2338 $supplierinvoiceline->date_start = $date_start;
2339 $supplierinvoiceline->date_end = $date_end;
2340 $supplierinvoiceline->fk_code_ventilation = $fk_code_ventilation;
2341 $supplierinvoiceline->rang = $rang;
2342 $supplierinvoiceline->info_bits = $info_bits;
2343 $supplierinvoiceline->fk_remise_except = $fk_remise_except;
2344
2345
2346 $supplierinvoiceline->special_code = (int) $special_code;
2347 $supplierinvoiceline->fk_parent_line = $fk_parent_line;
2348 $supplierinvoiceline->origin = $this->origin;
2349 $supplierinvoiceline->origin_id = $origin_id;
2350 $supplierinvoiceline->fk_unit = $fk_unit;
2351
2352 // Multicurrency
2353 $supplierinvoiceline->fk_multicurrency = $this->fk_multicurrency;
2354 $supplierinvoiceline->multicurrency_code = $this->multicurrency_code;
2355 $supplierinvoiceline->multicurrency_subprice = ($apply_abs_price_on_credit_note ? -abs((float) $pu_ht_devise) : (float) $pu_ht_devise); // For credit note, unit price always negative, always positive otherwise
2356
2357 $supplierinvoiceline->multicurrency_total_ht = (($apply_abs_price_on_credit_note || $qty < 0) ? -abs((float) $multicurrency_total_ht) : (float) $multicurrency_total_ht); // For credit note and if qty is negative, total is negative
2358 $supplierinvoiceline->multicurrency_total_tva = (($apply_abs_price_on_credit_note || $qty < 0) ? -abs((float) $multicurrency_total_tva) : (float) $multicurrency_total_tva); // For credit note and if qty is negative, total is negative
2359 $supplierinvoiceline->multicurrency_total_ttc = (($apply_abs_price_on_credit_note || $qty < 0) ? -abs((float) $multicurrency_total_ttc) : (float) $multicurrency_total_ttc); // For credit note and if qty is negative, total is negative
2360
2361 if (is_array($array_options) && count($array_options) > 0) {
2362 $supplierinvoiceline->array_options = $array_options;
2363 }
2364
2365 $result = $supplierinvoiceline->insert($notrigger);
2366 if ($result > 0) {
2367 // Update denormalized fields at the order level
2368 $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.
2369
2370 if ($result > 0) {
2371 if (!isset($this->context['createfromclone'])) {
2372 if (!empty($fk_parent_line)) {
2373 // Always reorder if child line
2374 $this->line_order(true, 'DESC');
2375 } elseif ($rang > 0 && $rang <= count($this->lines)) {
2376 // Update all rank of all other lines starting from the same $ranktouse
2377 $linecount = count($this->lines);
2378 for ($ii = $rang; $ii <= $linecount; $ii++) {
2379 $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1);
2380 }
2381 }
2382
2383 $this->lines[] = $supplierinvoiceline;
2384 }
2385
2386 $this->db->commit();
2387 return $supplierinvoiceline->id;
2388 } else {
2389 $this->error = $this->db->error();
2390 $this->db->rollback();
2391 return -1;
2392 }
2393 } else {
2394 $this->error = $supplierinvoiceline->error;
2395 $this->errors = $supplierinvoiceline->errors;
2396 $this->db->rollback();
2397 return -2;
2398 }
2399 } else {
2400 return 0;
2401 }
2402 }
2403
2429 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 = 0, $date_start = '', $date_end = '', $array_options = [], $fk_unit = null, $pu_devise = 0, $ref_supplier = '', $rang = 0)
2430 {
2431 global $mysoc, $langs;
2432
2433 if (!$this->isLineOfObject($id)) {
2434 $this->error = 'ErrorLineIDDoesNotMatchWithObjectID';
2435 return -1;
2436 }
2437
2438 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);
2439 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2440
2441 $pu = price2num($pu);
2442 $qty = price2num($qty);
2443 $remise_percent = (float) price2num($remise_percent);
2444 $pu_devise = price2num($pu_devise);
2445
2446 // Check parameters
2447 //if (! is_numeric($pu) || ! is_numeric($qty)) return -1;
2448 if ($type < 0) {
2449 return -1;
2450 }
2451
2452 if ($date_start && $date_end && $date_start > $date_end) {
2453 $langs->load("errors");
2454 $this->error = $langs->trans('ErrorStartDateGreaterEnd');
2455 return -1;
2456 }
2457
2458 // Clean parameters
2459 if (empty($vatrate)) {
2460 $vatrate = 0;
2461 }
2462 if (empty($txlocaltax1)) {
2463 $txlocaltax1 = 0;
2464 }
2465 if (empty($txlocaltax2)) {
2466 $txlocaltax2 = 0;
2467 }
2468
2469 $txlocaltax1 = (float) price2num($txlocaltax1);
2470 $txlocaltax2 = (float) price2num($txlocaltax2);
2471
2472 // Calcul du total TTC et de la TVA pour la ligne a partir de
2473 // qty, pu, remise_percent et txtva
2474 // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2475 // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2476
2477 $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $mysoc, $this->thirdparty);
2478
2479 $reg = array();
2480
2481 // Clean vat code
2482 $vat_src_code = '';
2483 if (preg_match('/\‍((.*)\‍)/', (string) $vatrate, $reg)) {
2484 $vat_src_code = $reg[1];
2485 $vatrate = preg_replace('/\s*\‍(.*\‍)/', '', (string) $vatrate); // Remove code into vatrate.
2486 }
2487
2488 $tabprice = calcul_price_total((float) $qty, (float) $pu, $remise_percent, $vatrate, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $this->thirdparty, $localtaxes_type, 100, $this->multicurrency_tx, (float) $pu_devise);
2489 $total_ht = $tabprice[0];
2490 $total_tva = $tabprice[1];
2491 $total_ttc = $tabprice[2];
2492 $pu_ht = $tabprice[3];
2493 $pu_tva = $tabprice[4];
2494 $pu_ttc = $tabprice[5];
2495 $total_localtax1 = $tabprice[9];
2496 $total_localtax2 = $tabprice[10];
2497
2498 // MultiCurrency
2499 $multicurrency_total_ht = $tabprice[16];
2500 $multicurrency_total_tva = $tabprice[17];
2501 $multicurrency_total_ttc = $tabprice[18];
2502 $pu_ht_devise = $tabprice[19];
2503
2504 if (empty($info_bits)) {
2505 $info_bits = 0;
2506 }
2507
2508 // Fetch current line from the database and then clone the object and set it in $oldline property
2509 $line = new SupplierInvoiceLine($this->db);
2510 $line->fetch($id);
2511 $line->fetch_optionals();
2512
2513 $staticline = clone $line;
2514
2515 if ($idproduct) {
2516 $product = new Product($this->db);
2517 $result = $product->fetch($idproduct);
2518 $product_type = $product->type;
2519 } else {
2520 $idproduct = $staticline->fk_product;
2521 $product_type = $type;
2522 }
2523
2524 $line->oldline = $staticline;
2525 $line->context = $this->context;
2526
2527 // The -abs() forcing on credit note lines is relaxed only when both FACTURE_ENABLE_NEGATIVE_LINES and
2528 // INVOICE_KEEP_DISCOUNT_LINES_AS_IN_ORIGIN are enabled, the gate of the customer side from 23.0 on.
2529 $apply_abs_price_on_credit_note = false;
2530 if ($this->type == self::TYPE_CREDIT_NOTE && !(getDolGlobalInt('FACTURE_ENABLE_NEGATIVE_LINES') && getDolGlobalInt('INVOICE_KEEP_DISCOUNT_LINES_AS_IN_ORIGIN'))) {
2531 $apply_abs_price_on_credit_note = true;
2532 }
2533
2534 $line->description = $desc;
2535 $line->desc = $desc;
2536
2537 $line->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs((float) $qty) : (float) $qty); // For credit note, quantity is always positive and unit price negative
2538
2539 $line->subprice = ($apply_abs_price_on_credit_note ? -abs((float) $pu_ht) : (float) $pu_ht); // For credit note, unit price always negative, always positive otherwise
2540 $line->subprice_ttc = ($apply_abs_price_on_credit_note ? -abs((float) $pu_ttc) : (float) $pu_ttc); // For credit note, unit price always negative, always positive otherwise
2541 $line->pu_ht = $line->subprice; // deprecated
2542 $line->pu_ttc = $line->subprice_ttc; // deprecated
2543
2544 $line->remise_percent = $remise_percent;
2545 $line->ref_supplier = $ref_supplier;
2546
2547 $line->date_start = $date_start;
2548 $line->date_end = $date_end;
2549
2550 $line->vat_src_code = $vat_src_code;
2551 $line->tva_tx = $vatrate;
2552 $line->localtax1_tx = $txlocaltax1;
2553 $line->localtax2_tx = $txlocaltax2;
2554 $line->localtax1_type = empty($localtaxes_type[0]) ? 0 : $localtaxes_type[0];
2555 $line->localtax2_type = empty($localtaxes_type[2]) ? 0 : $localtaxes_type[2];
2556
2557 $line->total_ht = (($apply_abs_price_on_credit_note || $qty < 0) ?-abs((float) $total_ht) : (float) $total_ht);
2558 $line->total_tva = (($apply_abs_price_on_credit_note || $qty < 0) ?-abs((float) $total_tva) : (float) $total_tva);
2559 $line->total_localtax1 = (float) $total_localtax1;
2560 $line->total_localtax2 = (float) $total_localtax2;
2561 $line->total_ttc = (($apply_abs_price_on_credit_note || $qty < 0) ?-abs((float) $total_ttc) : (float) $total_ttc);
2562
2563 $line->fk_product = $idproduct;
2564 $line->product_type = $product_type;
2565 $line->info_bits = $info_bits;
2566 $line->fk_unit = $fk_unit;
2567 $line->rang = $rang;
2568
2569 if (is_array($array_options) && count($array_options) > 0) {
2570 // We replace values in this->line->array_options only for entries defined into $array_options
2571 foreach ($array_options as $key => $value) {
2572 $line->array_options[$key] = $array_options[$key];
2573 }
2574 }
2575
2576 // Multicurrency
2577 $line->multicurrency_subprice = (float) $pu_ht_devise;
2578 $line->multicurrency_total_ht = (float) $multicurrency_total_ht;
2579 $line->multicurrency_total_tva = (float) $multicurrency_total_tva;
2580 $line->multicurrency_total_ttc = (float) $multicurrency_total_ttc;
2581
2582 $res = $line->update($notrigger);
2583
2584 if ($res < 1) {
2585 $this->setErrorsFromObject($line);
2586 } else {
2587 // Update total price into invoice record
2588 $res = $this->update_price(1, 'auto', 0, $this->thirdparty);
2589 }
2590
2591 return $res;
2592 }
2593
2601 public function deleteLine($rowid, $notrigger = 0)
2602 {
2603 if (!$rowid) {
2604 $rowid = $this->id;
2605 }
2606
2607 $line = new SupplierInvoiceLine($this->db);
2608
2609 if ($line->fetch($rowid) < 1) {
2610 return -1;
2611 }
2612 if ($this->id > 0 && (int) $line->fk_facture_fourn !== (int) $this->id) {
2613 $this->error = 'ErrorLineIDDoesNotMatchWithObjectID';
2614 return -1;
2615 }
2616
2617 $this->db->begin();
2618
2619 // Free the discount linked to a line of invoice
2620 $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
2621 $sql .= ' SET fk_invoice_supplier_line = NULL';
2622 $sql .= ' WHERE fk_invoice_supplier_line = '.((int) $rowid);
2623
2624 dol_syslog(get_class($this)."::deleteline", LOG_DEBUG);
2625 $result = $this->db->query($sql);
2626 if (!$result) {
2627 $this->error = $this->db->error();
2628 $this->db->rollback();
2629 return -2;
2630 }
2631
2632 $res = $line->delete($notrigger);
2633
2634 if ($res < 1) {
2635 $this->errors[] = $line->error;
2636 $this->db->rollback();
2637 return -3;
2638 } else {
2639 $res = $this->update_price(1);
2640
2641 if ($res > 0) {
2642 $this->db->commit();
2643 return 1;
2644 } else {
2645 $this->db->rollback();
2646 $this->error = $this->db->lasterror();
2647 return -4;
2648 }
2649 }
2650 }
2651
2652
2659 public function info($id)
2660 {
2661 $sql = 'SELECT c.rowid, datec, tms as datem, ';
2662 $sql .= ' fk_user_author, fk_user_modif, fk_user_valid';
2663 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as c';
2664 $sql .= ' WHERE c.rowid = '.((int) $id);
2665
2666 $result = $this->db->query($sql);
2667 if ($result) {
2668 if ($this->db->num_rows($result)) {
2669 $obj = $this->db->fetch_object($result);
2670
2671 $this->id = $obj->rowid;
2672
2673 $this->user_creation_id = $obj->fk_user_author;
2674 $this->user_validation_id = $obj->fk_user_valid;
2675 $this->user_modification_id = $obj->fk_user_modif;
2676 $this->date_creation = $this->db->jdate($obj->datec);
2677 $this->date_modification = $this->db->jdate($obj->datem);
2678 //$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)
2679 }
2680 $this->db->free($result);
2681 } else {
2682 dol_print_error($this->db);
2683 }
2684 }
2685
2686 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2695 public function list_replacable_supplier_invoices($socid = 0)
2696 {
2697 // phpcs:enable
2698 global $conf;
2699
2700 $return = array();
2701
2702 $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut,";
2703 $sql .= " ff.rowid as rowidnext";
2704 $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2705 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2706 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture_fourn as ff ON f.rowid = ff.fk_facture_source";
2707 $sql .= " WHERE (f.fk_statut = ".self::STATUS_VALIDATED." OR (f.fk_statut = ".self::STATUS_ABANDONED." AND f.close_code = '".self::CLOSECODE_ABANDONED."'))";
2708 $sql .= " AND f.entity = ".$conf->entity;
2709 $sql .= " AND f.paye = 0"; // Not closed completely
2710 $sql .= " AND pf.fk_paiementfourn IS NULL"; // No payment already done
2711 $sql .= " AND ff.fk_statut IS NULL"; // Return true (is null) if it is not a replacing invoice (we can't replace a replacing invoice)
2712 if ($socid > 0) {
2713 $sql .= " AND f.fk_soc = ".((int) $socid);
2714 }
2715 $sql .= " ORDER BY f.ref";
2716
2717 dol_syslog(get_class($this)."::list_replacable_supplier_invoices", LOG_DEBUG);
2718 $resql = $this->db->query($sql);
2719 if ($resql) {
2720 while ($obj = $this->db->fetch_object($resql)) {
2721 $return[$obj->rowid] = array(
2722 'id' => $obj->rowid,
2723 'ref' => $obj->ref,
2724 'status' => $obj->fk_statut
2725 );
2726 }
2727 //print_r($return);
2728 return $return;
2729 } else {
2730 $this->error = $this->db->error();
2731 return -1;
2732 }
2733 }
2734
2735 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2744 public function list_qualified_avoir_supplier_invoices($socid = 0)
2745 {
2746 // phpcs:enable
2747 global $conf;
2748
2749 $return = array();
2750
2751 $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.subtype, f.paye as paid, pf.fk_paiementfourn";
2752 $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2753 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
2754 $sql .= " WHERE f.entity = ".$conf->entity;
2755 $sql .= " AND f.fk_statut in (".self::STATUS_VALIDATED.",".self::STATUS_CLOSED.")";
2756 $sql .= " AND NOT EXISTS (SELECT rowid from ".MAIN_DB_PREFIX."facture_fourn as ff WHERE f.rowid = ff.fk_facture_source";
2757 $sql .= " AND ff.type=".self::TYPE_REPLACEMENT.")";
2758 $sql .= " AND f.type != ".self::TYPE_CREDIT_NOTE; // Type non 2 si facture non avoir
2759 if ($socid > 0) {
2760 $sql .= " AND f.fk_soc = ".((int) $socid);
2761 }
2762 $sql .= " ORDER BY f.ref";
2763
2764 dol_syslog(get_class($this)."::list_qualified_avoir_supplier_invoices", LOG_DEBUG);
2765 $resql = $this->db->query($sql);
2766 if ($resql) {
2767 while ($obj = $this->db->fetch_object($resql)) {
2768 $qualified = 0;
2769 if ($obj->fk_statut == self::STATUS_VALIDATED) {
2770 $qualified = 1;
2771 }
2772 if ($obj->fk_statut == self::STATUS_CLOSED) {
2773 $qualified = 1;
2774 }
2775 if ($qualified) {
2776 $paymentornot = ($obj->fk_paiementfourn ? 1 : 0);
2777 $return[$obj->rowid] = array('ref' => (string) $obj->ref, 'status' => (int) $obj->fk_statut, 'type' => (int) $obj->type, 'paid' => (int) $obj->paid, 'paye' => (int) $obj->paid, 'paymentornot' => (int) $paymentornot);
2778 }
2779 }
2780
2781 return $return;
2782 } else {
2783 $this->error = $this->db->error();
2784 return -1;
2785 }
2786 }
2787
2788 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2795 public function load_board($user)
2796 {
2797 // phpcs:enable
2798 global $conf, $langs;
2799
2800 $sql = 'SELECT ff.rowid, ff.date_lim_reglement as datefin, ff.fk_statut as status, ff.total_ht, ff.total_ttc';
2801 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as ff';
2802 if (empty($user->socid) && !$user->hasRight("societe", "client", "voir")) {
2803 $sql .= " JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ff.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
2804 }
2805 $sql .= ' WHERE ff.paye = 0';
2806 $sql .= " AND ff.fk_statut IN (".self::STATUS_VALIDATED.")";
2807 $sql .= " AND ff.entity = ".$conf->entity;
2808 if ($user->socid) {
2809 $sql .= ' AND ff.fk_soc = '.((int) $user->socid);
2810 }
2811
2812 $resql = $this->db->query($sql);
2813 if ($resql) {
2814 $langs->load("bills");
2815 $now = dol_now();
2816
2817 $response = new WorkboardResponse();
2818 $response->warning_delay = $conf->facture->fournisseur->warning_delay / 60 / 60 / 24;
2819 $response->label = $langs->trans("SupplierBillsToPay");
2820 $response->labelShort = $langs->trans("StatusToPay");
2821
2822 $response->url = DOL_URL_ROOT.'/fourn/facture/list.php?search_status=1&mainmenu=billing&leftmenu=suppliers_bills';
2823 $response->img = img_object($langs->trans("Bills"), "bill");
2824
2825 $facturestatic = new FactureFournisseur($this->db);
2826
2827 while ($obj = $this->db->fetch_object($resql)) {
2828 $facturestatic->date_echeance = $this->db->jdate($obj->datefin);
2829 $facturestatic->statut = $obj->status; // For backward compatibility
2830 $facturestatic->status = $obj->status;
2831
2832 $response->nbtodo++;
2833 $response->total += $obj->total_ht;
2834
2835 if ($facturestatic->hasDelay()) {
2836 $response->nbtodolate++;
2837 $response->url_late = DOL_URL_ROOT.'/fourn/facture/list.php?search_option=late&mainmenu=billing&leftmenu=suppliers_bills';
2838 }
2839 }
2840
2841 $this->db->free($resql);
2842 return $response;
2843 } else {
2844 dol_print_error($this->db);
2845 $this->error = $this->db->error();
2846 return -1;
2847 }
2848 }
2849
2857 public function getTooltipContentArray($params)
2858 {
2859 global $conf, $langs, $mysoc;
2860
2861 $langs->load('bills');
2862
2863 $datas = [];
2864 $moretitle = $params['moretitle'] ?? '';
2865
2866 $picto = $this->picto;
2867 if ($this->type == self::TYPE_REPLACEMENT) {
2868 $picto .= 'r'; // Replacement invoice
2869 }
2870 if ($this->type == self::TYPE_CREDIT_NOTE) {
2871 $picto .= 'a'; // Credit note
2872 }
2873 if ($this->type == self::TYPE_DEPOSIT) {
2874 $picto .= 'd'; // Deposit invoice
2875 }
2876
2877 $datas['picto'] = img_picto('', $picto).' <u class="paddingrightonly">'.$langs->trans("SupplierInvoice").'</u>';
2878 if ($this->type == self::TYPE_REPLACEMENT) {
2879 $datas['picto'] .= '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("InvoiceReplacement").'</u>';
2880 } elseif ($this->type == self::TYPE_CREDIT_NOTE) {
2881 $datas['picto'] .= '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("CreditNote").'</u>';
2882 } elseif ($this->type == self::TYPE_DEPOSIT) {
2883 $datas['picto'] .= '<u class="paddingrightonly">'.$langs->transnoentitiesnoconv("Deposit").'</u>';
2884 }
2885 if (isset($this->status)) {
2886 $alreadypaid = -1;
2887 if (isset($this->totalpaid)) {
2888 $alreadypaid = $this->totalpaid;
2889 }
2890
2891 $datas['picto'] .= ' '.$this->getLibStatut(5, $alreadypaid);
2892 }
2893 if ($moretitle) {
2894 $datas['picto'] .= ' - '.$moretitle;
2895 }
2896 if (!empty($this->ref)) {
2897 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
2898 }
2899 if (!empty($this->ref_supplier)) {
2900 $datas['refsupplier'] = '<br><b>'.$langs->trans('RefSupplier').':</b> '.$this->ref_supplier;
2901 }
2902 if (!empty($this->label)) {
2903 $datas['label'] = '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
2904 }
2905 if (!empty($this->date)) {
2906 $datas['date'] = '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
2907 }
2908 if (!empty($this->date_echeance)) {
2909 $datas['date_echeance'] = '<br><b>'.$langs->trans('DateDue').':</b> '.dol_print_date($this->date_echeance, 'day');
2910 }
2911 if (!empty($this->total_ht)) {
2912 $datas['amountht'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
2913 }
2914 if (!empty($this->total_tva)) {
2915 $datas['totaltva'] = '<br><b>'.$langs->trans('AmountVAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
2916 }
2917 if (!empty($this->total_localtax1) && $this->total_localtax1 != 0) {
2918 // We keep test != 0 because $this->total_localtax1 can be '0.00000000'
2919 $datas['amountlt1'] = '<br><b>'.$langs->transcountry('AmountLT1', $mysoc->country_code).':</b> '.price($this->total_localtax1, 0, $langs, 0, -1, -1, $conf->currency);
2920 }
2921 if (!empty($this->total_localtax2) && $this->total_localtax2 != 0) {
2922 $datas['amountlt2'] = '<br><b>'.$langs->transcountry('AmountLT2', $mysoc->country_code).':</b> '.price($this->total_localtax2, 0, $langs, 0, -1, -1, $conf->currency);
2923 }
2924 if (!empty($this->revenuestamp)) {
2925 $datas['amountrevenustamp'] = '<br><b>'.$langs->trans('RevenueStamp').':</b> '.price($this->revenuestamp, 0, $langs, 0, -1, -1, $conf->currency);
2926 }
2927 if (!empty($this->total_ttc)) {
2928 $datas['totalttc'] = '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
2929 }
2930 return $datas;
2931 }
2932
2946 public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
2947 {
2948 global $langs, $conf, $user, $hookmanager;
2949
2950 $result = '';
2951
2952 if ($option == 'withdraw') {
2953 $url = DOL_URL_ROOT.'/compta/facture/prelevement.php?facid='.$this->id.'&type=bank-transfer';
2954 } elseif ($option == 'document') {
2955 $url = DOL_URL_ROOT.'/fourn/facture/document.php?facid='.$this->id;
2956 } else {
2957 $url = DOL_URL_ROOT.'/fourn/facture/card.php?facid='.$this->id;
2958 }
2959
2960 if ($short) {
2961 return $url;
2962 }
2963
2964 if ($option !== 'nolink') {
2965 // Add param to save lastsearch_values or not
2966 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
2967 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
2968 $add_save_lastsearch_values = 1;
2969 }
2970 if ($add_save_lastsearch_values) {
2971 $url .= '&save_lastsearch_values=1';
2972 }
2973 }
2974
2975 $picto = $this->picto;
2976 if ($this->type == self::TYPE_REPLACEMENT) {
2977 $picto .= 'r'; // Replacement invoice
2978 }
2979 if ($this->type == self::TYPE_CREDIT_NOTE) {
2980 $picto .= 'a'; // Credit note
2981 }
2982 if ($this->type == self::TYPE_DEPOSIT) {
2983 $picto .= 'd'; // Deposit invoice
2984 }
2985
2986 $params = [
2987 'id' => $this->id,
2988 'objecttype' => $this->element,
2989 'option' => $option,
2990 'moretitle' => $moretitle,
2991 ];
2992 $classfortooltip = 'classfortooltip';
2993 $dataparams = '';
2994 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
2995 $classfortooltip = 'classforajaxtooltip';
2996 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
2997 $label = '';
2998 } else {
2999 $label = implode($this->getTooltipContentArray($params));
3000 }
3001
3002 $ref = $this->ref;
3003 if (empty($ref)) {
3004 $ref = $this->id;
3005 }
3006
3007 $linkclose = '';
3008 if (empty($notooltip)) {
3009 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
3010 $label = $langs->trans("ShowSupplierInvoice");
3011 $linkclose .= ' alt="'.dolPrintHTMLForAttribute($label).'"';
3012 }
3013 $linkclose .= ($label ? ' title="'.dolPrintHTMLForAttribute($label).'"' : ' title="tocomplete"');
3014 $linkclose .= $dataparams.' class="'.$classfortooltip.'"';
3015 }
3016
3017 $linkstart = '<a href="'.$url.'"';
3018 $linkstart .= $linkclose.'>';
3019 $linkend = '</a>';
3020
3021 $result .= $linkstart;
3022 if ($withpicto) {
3023 $result .= img_object(($notooltip ? '' : $label), ($picto ? $picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'"'), 0, 0, $notooltip ? 0 : 1);
3024 }
3025 if ($withpicto != 2) {
3026 $result .= ($max ? dol_trunc($ref, $max) : $ref);
3027 }
3028 $result .= $linkend;
3029
3030 if ($addlinktonotes) {
3031 $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
3032 if ($txttoshow) {
3033 $notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
3034 $result .= ' <span class="note inline-block">';
3035 $result .= '<a href="'.DOL_URL_ROOT.'/fourn/facture/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
3036 $result .= img_picto('', 'note');
3037 $result .= '</a>';
3038 $result .= '</span>';
3039 }
3040 }
3041 global $action;
3042 $hookmanager->initHooks(array($this->element . 'dao'));
3043 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
3044 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3045 if ($reshook > 0) {
3046 $result = $hookmanager->resPrint;
3047 } else {
3048 $result .= $hookmanager->resPrint;
3049 }
3050 return $result;
3051 }
3052
3063 public function setCategories($categories)
3064 {
3065 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
3066 return parent::setCategoriesCommon($categories, Categorie::TYPE_SUPPLIER_INVOICE);
3067 }
3068
3077 public function getNextNumRef($soc, $mode = 'next')
3078 {
3079 global $db, $langs, $conf;
3080 $langs->load("orders");
3081
3082 // Clean parameters (if not defined or using deprecated value)
3083 if (!getDolGlobalString('INVOICE_SUPPLIER_ADDON_NUMBER')) {
3084 $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER = 'mod_facture_fournisseur_cactus';
3085 }
3086
3087 $mybool = false;
3088
3089 $file = getDolGlobalString('INVOICE_SUPPLIER_ADDON_NUMBER') . ".php";
3090 $classname = getDolGlobalString('INVOICE_SUPPLIER_ADDON_NUMBER');
3091
3092 // Include file with class
3093 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
3094
3095 foreach ($dirmodels as $reldir) {
3096 $dir = dol_buildpath($reldir."core/modules/supplier_invoice/");
3097
3098 // Load file with numbering class (if found)
3099 $mybool = ((bool) @include_once $dir.$file) || $mybool;
3100 }
3101
3102 if (!$mybool) {
3103 dol_print_error(null, "Failed to include file ".$file);
3104 return '';
3105 }
3106
3107 $obj = new $classname();
3108 '@phan-var-force ModeleNumRefSuppliersInvoices $obj';
3109 $numref = "";
3110 $numref = $obj->getNextValue($soc, $this, $mode);
3111
3112 if ($numref != "") {
3113 return $numref;
3114 } else {
3115 $this->error = $obj->error;
3116 return -1;
3117 }
3118 }
3119
3120
3129 public function initAsSpecimen($option = '')
3130 {
3131 global $langs, $conf;
3132 include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
3133
3134 $now = dol_now();
3135
3136 // Load array of products prodids
3137 $num_prods = 0;
3138 $prodids = array();
3139
3140 $sql = "SELECT rowid";
3141 $sql .= " FROM ".MAIN_DB_PREFIX."product";
3142 $sql .= " WHERE entity IN (".getEntity('product').")";
3143 $sql .= $this->db->plimit(100);
3144
3145 $resql = $this->db->query($sql);
3146 if ($resql) {
3147 $num_prods = $this->db->num_rows($resql);
3148 $i = 0;
3149 while ($i < $num_prods) {
3150 $i++;
3151 $row = $this->db->fetch_row($resql);
3152 $prodids[$i] = $row[0];
3153 }
3154 }
3155
3156 // Initialise parameters
3157 $this->id = 0;
3158 $this->ref = 'SPECIMEN';
3159 $this->ref_supplier = 'SUPPLIER_REF_SPECIMEN';
3160 $this->specimen = 1;
3161 $this->socid = 1;
3162 $this->date = $now;
3163 $this->date_lim_reglement = $this->date + 3600 * 24 * 30;
3164 $this->cond_reglement_code = 'RECEP';
3165 $this->mode_reglement_code = 'CHQ';
3166
3167 $this->note_public = 'This is a comment (public)';
3168 $this->note_private = 'This is a comment (private)';
3169
3170 $this->multicurrency_tx = 1;
3171 $this->multicurrency_code = $conf->currency;
3172
3173 $xnbp = 0;
3174 if (empty($option) || $option != 'nolines') {
3175 // Lines
3176 $nbp = min(1000, GETPOSTINT('nblines') ? GETPOSTINT('nblines') : 5); // We can force the nb of lines to test from command line (but not more than 1000)
3177 while ($xnbp < $nbp) {
3178 $line = new SupplierInvoiceLine($this->db);
3179 $line->desc = $langs->trans("Description")." ".$xnbp;
3180 $line->qty = 1;
3181 $line->subprice = 100;
3182 $line->price = 100;
3183 $line->tva_tx = 19.6;
3184 $line->localtax1_tx = 0;
3185 $line->localtax2_tx = 0;
3186 if ($xnbp == 2) {
3187 $line->total_ht = 50;
3188 $line->total_ttc = 59.8;
3189 $line->total_tva = 9.8;
3190 $line->remise_percent = 50;
3191 } else {
3192 $line->total_ht = 100;
3193 $line->total_ttc = 119.6;
3194 $line->total_tva = 19.6;
3195 $line->remise_percent = 0;
3196 }
3197
3198 if ($num_prods > 0) {
3199 $prodid = mt_rand(1, $num_prods);
3200 $line->fk_product = $prodids[$prodid];
3201 }
3202 $line->product_type = 0;
3203
3204 $this->lines[$xnbp] = $line;
3205
3206 $this->total_ht += $line->total_ht;
3207 $this->total_tva += $line->total_tva;
3208 $this->total_ttc += $line->total_ttc;
3209
3210 $xnbp++;
3211 }
3212 }
3213
3214 $this->total_ht = $xnbp * 100;
3215 $this->total_tva = $xnbp * 19.6;
3216 $this->total_ttc = $xnbp * 119.6;
3217
3218 return 1;
3219 }
3220
3226 public function loadStateBoard()
3227 {
3228 global $conf, $user;
3229
3230 $this->nb = array();
3231
3232 $clause = "WHERE";
3233
3234 $sql = "SELECT count(f.rowid) as nb";
3235 $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
3236 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
3237 if (empty($user->socid) && !$user->hasRight("societe", "client", "voir")) {
3238 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
3239 $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3240 $clause = "AND";
3241 }
3242 $sql .= " ".$clause." f.entity = ".((int) $conf->entity);
3243
3244 $resql = $this->db->query($sql);
3245 if ($resql) {
3246 while ($obj = $this->db->fetch_object($resql)) {
3247 $this->nb["supplier_invoices"] = $obj->nb;
3248 }
3249 $this->db->free($resql);
3250 return 1;
3251 } else {
3252 dol_print_error($this->db);
3253 $this->error = $this->db->error();
3254 return -1;
3255 }
3256 }
3257
3266 public function createFromClone(User $user, $fromid, $invertdetail = 0)
3267 {
3268 global $conf, $langs;
3269
3270 $error = 0;
3271
3272 $object = new FactureFournisseur($this->db);
3273
3274 $this->db->begin();
3275
3276 // Load source object
3277 $object->fetch($fromid);
3278 $object->id = 0;
3279 $object->statut = self::STATUS_DRAFT; // For backward compatibility
3280 $object->status = self::STATUS_DRAFT;
3281
3282 $object->fetch_thirdparty(); // We need it to recalculate VAT localtaxes according to main sale taxes and vendor
3283
3284 // Clear fields
3285 $object->ref_supplier = (empty($this->ref_supplier) ? $langs->trans("CopyOf").' '.$object->ref_supplier : $this->ref_supplier);
3286 $object->author = $user->id; // FIXME? user_validation_id is replacement for author
3287 $object->user_validation_id = 0; // FIXME? user_validation_id is replacement for author
3288 $object->fk_facture_source = 0;
3289 $object->date_creation = '';
3290 $object->date_validation = '';
3291 $object->date = (empty($this->date) ? dol_now() : $this->date);
3292 $object->ref_client = '';
3293 $object->close_code = '';
3294 $object->close_note = '';
3295 if (getDolGlobalInt('MAIN_DONT_KEEP_NOTE_ON_CLONING') == 1) {
3296 $object->note_private = '';
3297 $object->note_public = '';
3298 }
3299
3300 $object->date_echeance = $object->calculate_date_lim_reglement();
3301
3302 // Loop on each line of new invoice
3303 foreach ($object->lines as $i => $line) {
3304 if (isset($object->lines[$i]->info_bits) && ($object->lines[$i]->info_bits & 0x02) == 0x02) { // We do not clone line of discounts
3305 unset($object->lines[$i]);
3306 }
3307 }
3308
3309 // Create clone
3310 $object->context['createfromclone'] = 'createfromclone';
3311 $result = $object->create($user);
3312
3313 // Other options
3314 if ($result < 0) {
3315 $this->error = $object->error;
3316 $this->errors = $object->errors;
3317 $error++;
3318 }
3319
3320 if (!$error) {
3321 }
3322
3323 unset($object->context['createfromclone']);
3324
3325 // End
3326 if (!$error) {
3327 $this->db->commit();
3328 return $object->id;
3329 } else {
3330 $this->db->rollback();
3331 return -1;
3332 }
3333 }
3334
3346 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
3347 {
3348 global $langs;
3349
3350 $langs->load("suppliers");
3351 $outputlangs->load("products");
3352
3353 // Set the model on the model name to use
3354 if (empty($modele)) {
3355 if (getDolGlobalString('INVOICE_SUPPLIER_ADDON_PDF')) {
3356 $modele = getDolGlobalString('INVOICE_SUPPLIER_ADDON_PDF');
3357 } else {
3358 $modele = ''; // No default value. For supplier invoice, we allow to disable all PDF generation
3359 }
3360 } elseif ($modele == 'auto') {
3361 $modele = 'canelle';
3362 }
3363
3364 if (empty($modele)) {
3365 return 0;
3366 } else {
3367 $modelpath = "core/modules/supplier_invoice/doc/";
3368
3369 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
3370 }
3371 }
3372
3377 public function getRights()
3378 {
3379 global $user;
3380
3381 return $user->hasRight("fournisseur", "facture");
3382 }
3383
3392 public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
3393 {
3394 $tables = array(
3395 'facture_fourn'
3396 );
3397
3398 return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
3399 }
3400
3409 public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
3410 {
3411 $tables = array(
3412 'facture_fourn_det'
3413 );
3414
3415 return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
3416 }
3417
3423 public function hasDelay()
3424 {
3425 global $conf;
3426
3427 $now = dol_now();
3428
3429 if (!$this->date_echeance) {
3430 return false;
3431 }
3432
3433 $status = isset($this->status) ? $this->status : $this->statut;
3434
3435 return ($status == self::STATUS_VALIDATED) && ($this->date_echeance < ($now - $conf->facture->fournisseur->warning_delay));
3436 }
3437
3443 public function isCreditNoteUsed()
3444 {
3445 $isUsed = false;
3446
3447 $sql = "SELECT fk_invoice_supplier FROM ".MAIN_DB_PREFIX."societe_remise_except WHERE fk_invoice_supplier_source = ".((int) $this->id);
3448 $resql = $this->db->query($sql);
3449 if (!empty($resql)) {
3450 $obj = $this->db->fetch_object($resql);
3451 if (!empty($obj->fk_invoice_supplier)) {
3452 $isUsed = true;
3453 }
3454 }
3455
3456 return $isUsed;
3457 }
3465 public function getKanbanView($option = '', $arraydata = null)
3466 {
3467 global $langs;
3468
3469 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
3470
3471 $picto = $this->picto;
3472 if ($this->type == self::TYPE_REPLACEMENT) {
3473 $picto .= 'r'; // Replacement invoice
3474 }
3475 if ($this->type == self::TYPE_CREDIT_NOTE) {
3476 $picto .= 'a'; // Credit note
3477 }
3478 if ($this->type == self::TYPE_DEPOSIT) {
3479 $picto .= 'd'; // Deposit invoice
3480 }
3481
3482 $return = '<div class="box-flex-item box-flex-grow-zero">';
3483 $return .= '<div class="info-box info-box-sm">';
3484 $return .= '<span class="info-box-icon bg-infobox-action">';
3485 $return .= img_picto('', $picto);
3486 $return .= '</span>';
3487 $return .= '<div class="info-box-content">';
3488 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->getNomUrl(1) . '</span>';
3489 if ($selected >= 0) {
3490 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
3491 }
3492 if (!empty($arraydata['thirdparty'])) {
3493 $return .= '<br><span class="info-box-label">'.$arraydata['thirdparty'].'</span>';
3494 }
3495 if (!empty($this->date)) {
3496 $return .= '<br><span class="info-box-label">'.dol_print_date($this->date, 'day').'</span>';
3497 }
3498 if (!empty($this->total_ht)) {
3499 $return .= ' &nbsp; <span class="info-box-label amount" title="'.dol_escape_htmltag($langs->trans("AmountHT")).'">'.price($this->total_ht);
3500 $return .= ' '.$langs->trans("HT");
3501 $return .= '</span>';
3502 }
3503 $alreadypaid = (empty($arraydata['alreadypaid']) ? 0 : $arraydata['alreadypaid']);
3504 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3, $alreadypaid).'</div>';
3505
3506 $return .= '</div>';
3507 $return .= '</div>';
3508 $return .= '</div>';
3509
3510 return $return;
3511 }
3512
3519 public function setVATReverseCharge($vatreversecharge)
3520 {
3521 if (!$this->table_element) {
3522 dol_syslog(get_class($this)."::setVATReverseCharge was called on object with property table_element not defined", LOG_ERR);
3523 return -1;
3524 }
3525
3526 dol_syslog(get_class($this).'::setVATReverseCharge('.$vatreversecharge.')');
3527
3528 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3529 $sql .= " SET vat_reverse_charge = ".((int) $vatreversecharge);
3530 $sql .= " WHERE rowid=".((int) $this->id);
3531
3532 if ($this->db->query($sql)) {
3533 $this->vat_reverse_charge = ($vatreversecharge == 0) ? 0 : 1;
3534 return 1;
3535 } else {
3536 dol_syslog(get_class($this).'::setVATReverseCharge Error ', LOG_DEBUG);
3537 $this->error = $this->db->error();
3538 return 0;
3539 }
3540 }
3541
3553 public function sendEmailsRemindersOnSupplierInvoiceDueDate($nbdays = 0, $paymentmode = 'all', $template = '', $datetouse = 'duedate', $forcerecipient = '')
3554 {
3555 global $conf, $langs, $user;
3556
3557 $this->output = '';
3558 $this->error = '';
3559 $nbMailSend = 0;
3560
3561 $error = 0;
3562 $errorsMsg = array();
3563
3564 $langs->load('bills');
3565
3566 if (!isModEnabled(!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') ? 'fournisseur' : 'supplier_invoice')) { // Should not happen. If module disabled, cron job should not be visible.
3567 $this->output .= $langs->trans('ModuleNotEnabled', $langs->transnoentitiesnoconv('Suppliers'));
3568 return 0;
3569 }
3570 if (!in_array($datetouse, array('duedate', 'invoicedate'))) {
3571 $this->output .= 'Bad value for parameter datetouse. Must be "duedate" or "invoicedate"';
3572 return 0;
3573 }
3574
3575 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3576 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
3577 require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
3578 $formmail = new FormMail($this->db);
3579
3580 $now = dol_now();
3581 $tmpidate = dol_get_first_hour(dol_time_plus_duree($now, $nbdays, 'd'), 'gmt');
3582
3583 $tmpinvoice = new FactureFournisseur($this->db);
3584
3585 dol_syslog(__METHOD__." start", LOG_INFO);
3586
3587 // Select all action comm reminder
3588 $sql = "SELECT rowid as id FROM ".MAIN_DB_PREFIX."facture_fourn as f";
3589 if (!empty($paymentmode) && $paymentmode != 'all') {
3590 $sql .= ", ".MAIN_DB_PREFIX."c_paiement as cp";
3591 }
3592 $sql .= " WHERE f.paye = 0"; // Only unpaid
3593 $sql .= " AND f.fk_statut = ".self::STATUS_VALIDATED; // Only validated status
3594 if ($datetouse == 'invoicedate') {
3595 $sql .= " AND f.datef = '".$this->db->idate($tmpidate, 'gmt')."'";
3596 } else {
3597 $sql .= " AND f.date_lim_reglement = '".$this->db->idate($tmpidate, 'gmt')."'";
3598 }
3599 $sql .= " AND f.entity IN (".getEntity('supplier_invoice', 0).")"; // One batch process only one company (no sharing)
3600 if (!empty($paymentmode) && $paymentmode != 'all') {
3601 $sql .= " AND f.fk_mode_reglement = cp.id AND cp.code = '".$this->db->escape($paymentmode)."'";
3602 }
3603 // TODO Add a filter to check there is no payment started yet
3604 if ($datetouse == 'invoicedate') {
3605 $sql .= $this->db->order("datef", "ASC");
3606 } else {
3607 $sql .= $this->db->order("date_lim_reglement", "ASC");
3608 }
3609
3610 $resql = $this->db->query($sql);
3611
3612 $stmpidate = dol_print_date($tmpidate, 'day', 'gmt');
3613 if ($datetouse == 'invoicedate') {
3614 $this->output .= $langs->transnoentitiesnoconv("SearchValidatedSupplierInvoicesWithDate", $stmpidate);
3615 } else {
3616 $this->output .= $langs->transnoentitiesnoconv("SearchUnpaidSupplierInvoicesWithDueDate", $stmpidate);
3617 }
3618 if (!empty($paymentmode) && $paymentmode != 'all') {
3619 $this->output .= ' ('.$langs->transnoentitiesnoconv("PaymentMode").' '.$paymentmode.')';
3620 }
3621 $this->output .= '<br>';
3622
3623 if ($resql) {
3624 while ($obj = $this->db->fetch_object($resql)) {
3625 if (!$error) {
3626 // Load event
3627 $res = $tmpinvoice->fetch($obj->id);
3628 if ($res > 0) {
3629 $tmpinvoice->fetch_thirdparty();
3630
3631 $outputlangs = new Translate('', $conf);
3632 if ($tmpinvoice->thirdparty->default_lang) {
3633 $outputlangs->setDefaultLang($tmpinvoice->thirdparty->default_lang);
3634 $outputlangs->loadLangs(array("main", "suppliers"));
3635 } else {
3636 $outputlangs = $langs;
3637 }
3638
3639 // Select email template according to language of recipient
3640 $templateId = 0;
3641 $templateLabel = '';
3642 if (empty($template) || $template == 'EmailTemplateCode') {
3643 $templateLabel = '(SendingReminderEmailOnUnpaidSupplierInvoice)';
3644 } else {
3645 if (is_numeric($template)) {
3646 $templateId = $template;
3647 } else {
3648 $templateLabel = $template;
3649 }
3650 }
3651
3652 $arraymessage = $formmail->getEMailTemplate($this->db, 'invoice_supplier_send', $user, $outputlangs, $templateId, 1, $templateLabel);
3653 if (is_numeric($arraymessage) && $arraymessage <= 0) {
3654 $langs->load("errors");
3655 $this->output .= $langs->trans('ErrorFailedToFindEmailTemplate', $template);
3656 return 0;
3657 }
3658
3659 // PREPARE EMAIL
3660 $errormesg = '';
3661
3662 // Make substitution in email content
3663 $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $tmpinvoice);
3664
3665 complete_substitutions_array($substitutionarray, $outputlangs, $tmpinvoice);
3666
3667 // Topic
3668 $sendTopic = make_substitutions(empty($arraymessage->topic) ? $outputlangs->transnoentitiesnoconv('InformationMessage') : $arraymessage->topic, $substitutionarray, $outputlangs, 1);
3669
3670 // Content
3671 $content = $outputlangs->transnoentitiesnoconv($arraymessage->content);
3672
3673 $sendContent = make_substitutions($content, $substitutionarray, $outputlangs, 1);
3674
3675 // Recipient
3676 $to = array();
3677 if ($forcerecipient) { // If a recipient was forced
3678 $to = array($forcerecipient);
3679 } else {
3680 $res = $tmpinvoice->fetch_thirdparty();
3681 $recipient = $tmpinvoice->thirdparty;
3682 if ($res > 0) {
3683 $tmparraycontact = $tmpinvoice->liste_contact(-1, 'internal', 0, 'SALESREPFOLL');
3684 if (is_array($tmparraycontact) && count($tmparraycontact) > 0) {
3685 foreach ($tmparraycontact as $data_email) {
3686 if (!empty($data_email['email'])) {
3687 $to[] = $data_email['email'];
3688 }
3689 }
3690 }
3691 if (empty($to) && !empty($recipient->email)) {
3692 $to[] = $recipient->email;
3693 }
3694 if (empty($to)) {
3695 $errormesg = "Failed to send remind to thirdparty id=".$tmpinvoice->socid.". No email defined for supplier invoice or customer.";
3696 $error++;
3697 }
3698 } else {
3699 $errormesg = "Failed to load recipient with thirdparty id=".$tmpinvoice->socid;
3700 $error++;
3701 }
3702 }
3703
3704 // Sender
3705 $from = getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
3706 if (!empty($arraymessage->email_from)) { // If a sender is defined into template, we use it in priority
3707 $from = (string) $arraymessage->email_from;
3708 }
3709 if (empty($from)) {
3710 $errormesg = "Failed to get sender into global setup MAIN_MAIL_EMAIL_FROM";
3711 $error++;
3712 }
3713
3714 if (!$error && !empty($to)) {
3715 $this->db->begin();
3716
3717 $to = implode(',', $to);
3718 if (!empty($arraymessage->email_to)) { // If a recipient is defined into template, we add it
3719 $to = $to.','.$arraymessage->email_to;
3720 }
3721
3722 // Errors Recipient
3723 $errors_to = getDolGlobalString('MAIN_MAIL_ERRORS_TO');
3724
3725 $trackid = 'inv'.$tmpinvoice->id;
3726 $sendcontext = 'standard';
3727
3728 $email_tocc = '';
3729 if (!empty($arraymessage->email_tocc)) { // If a CC is defined into template, we use it
3730 $email_tocc = (string) $arraymessage->email_tocc;
3731 }
3732
3733 $email_tobcc = '';
3734 if (!empty($arraymessage->email_tobcc)) { // If a BCC is defined into template, we use it
3735 $email_tobcc = (string) $arraymessage->email_tobcc;
3736 }
3737
3738 // Mail Creation
3739 $cMailFile = new CMailFile($sendTopic, $to, $from, $sendContent, array(), array(), array(), $email_tocc, $email_tobcc, 0, 1, $errors_to, '', $trackid, '', $sendcontext, '');
3740
3741 // Sending Mail
3742 if ($cMailFile->sendfile()) {
3743 $nbMailSend++;
3744
3745 // Add a line into event table
3746 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
3747
3748 // Insert record of emails sent
3749 $actioncomm = new ActionComm($this->db);
3750
3751 $actioncomm->type_code = 'AC_OTH_AUTO'; // Event insert into agenda automatically
3752 $actioncomm->socid = $tmpinvoice->thirdparty->id; // To link to a company
3753 $actioncomm->contact_id = 0;
3754
3755 $actioncomm->code = 'AC_EMAIL';
3756 $actioncomm->label = 'sendEmailsRemindersOnInvoiceDueDateOK (nbdays='.$nbdays.' paymentmode='.$paymentmode.' template='.$template.' datetouse='.$datetouse.' forcerecipient='.$forcerecipient.')';
3757 $actioncomm->note_private = $sendContent;
3758 $actioncomm->fk_project = $tmpinvoice->fk_project;
3759 $actioncomm->datep = dol_now();
3760 $actioncomm->datef = $actioncomm->datep;
3761 $actioncomm->percentage = -1; // Not applicable
3762 $actioncomm->authorid = $user->id; // User saving action
3763 $actioncomm->userownerid = $user->id; // Owner of action
3764 // Fields when action is an email (content should be added into note)
3765 $actioncomm->email_msgid = $cMailFile->msgid;
3766 $actioncomm->email_subject = $sendTopic;
3767 $actioncomm->email_from = $from;
3768 $actioncomm->email_sender = '';
3769 $actioncomm->email_to = $to;
3770 //$actioncomm->email_tocc = $sendtocc;
3771 //$actioncomm->email_tobcc = $sendtobcc;
3772 //$actioncomm->email_subject = $subject;
3773 $actioncomm->errors_to = $errors_to;
3774
3775 $actioncomm->elementtype = 'invoice_supplier';
3776 $actioncomm->elementid = $tmpinvoice->id;
3777 $actioncomm->fk_element = $tmpinvoice->id;
3778
3779 //$actioncomm->extraparams = $extraparams;
3780
3781 $actioncomm->create($user);
3782 } else {
3783 $errormesg = $cMailFile->error.' : '.$to;
3784 $error++;
3785
3786 // Add a line into event table
3787 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
3788
3789 // Insert record of emails sent
3790 $actioncomm = new ActionComm($this->db);
3791
3792 $actioncomm->type_code = 'AC_OTH_AUTO'; // Event insert into agenda automatically
3793 $actioncomm->socid = $tmpinvoice->thirdparty->id; // To link to a company
3794 $actioncomm->contact_id = 0;
3795
3796 $actioncomm->code = 'AC_EMAIL';
3797 $actioncomm->label = 'sendEmailsRemindersOnInvoiceDueDateKO';
3798 $actioncomm->note_private = $errormesg;
3799 $actioncomm->fk_project = $tmpinvoice->fk_project;
3800 $actioncomm->datep = dol_now();
3801 $actioncomm->datef = $actioncomm->datep;
3802 $actioncomm->percentage = -1; // Not applicable
3803 $actioncomm->authorid = $user->id; // User saving action
3804 $actioncomm->userownerid = $user->id; // Owner of action
3805 // Fields when action is an email (content should be added into note)
3806 $actioncomm->email_msgid = $cMailFile->msgid;
3807 $actioncomm->email_from = $from;
3808 $actioncomm->email_sender = '';
3809 $actioncomm->email_to = $to;
3810 //$actioncomm->email_tocc = $sendtocc;
3811 //$actioncomm->email_tobcc = $sendtobcc;
3812 //$actioncomm->email_subject = $subject;
3813 $actioncomm->errors_to = $errors_to;
3814
3815 //$actioncomm->extraparams = $extraparams;
3816
3817 $actioncomm->create($user);
3818 }
3819
3820 $this->db->commit(); // We always commit
3821 }
3822
3823 if ($errormesg) {
3824 $errorsMsg[] = $errormesg;
3825 }
3826 } else {
3827 $errorsMsg[] = 'Failed to fetch record invoice with ID = '.$obj->id;
3828 $error++;
3829 }
3830 }
3831 }
3832 } else {
3833 $error++;
3834 }
3835
3836 if (!$error) {
3837 $this->output .= 'Nb of emails sent : '.$nbMailSend;
3838
3839 dol_syslog(__METHOD__." end - ".$this->output, LOG_INFO);
3840
3841 return 0;
3842 } else {
3843 $this->error = 'Nb of emails sent : '.$nbMailSend.', '.(empty($errorsMsg) ? $error : implode(', ', $errorsMsg));
3844
3845 dol_syslog(__METHOD__." end - ".$this->error, LOG_INFO);
3846
3847 return $error;
3848 }
3849 }
3850}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
$object ref
Definition info.php:90
Class to manage agenda events (actions)
Class to send emails (with attachments or not) Usage: $mailfile = new CMailFile($subject,...
Superclass for invoice classes.
calculate_date_lim_reglement($cond_reglement=0)
Returns an invoice payment deadline based on the invoice settlement conditions and billing date.
is_erasable()
Return if an invoice can be deleted Rule is: If invoice is draft and has a temporary ref -> yes (1) I...
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.
update_price($exclspec=0, $roundingadjust='auto', $nodatabaseupdate=0, $seller=null)
Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
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.
setErrorsFromObject($object)
setErrorsFromObject
isLineOfObject($lineid)
Check that a line belongs to this object, using $this->table_element_line and $this->fk_element.
updateRangOfLine($rowid, $rang)
Update position of line (rang)
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.
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...
deleteLine($rowid, $notrigger=0)
Delete a detail line from database.
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...
fetch($id=0, $ref='', $ref_ext='')
Load object in memory from database.
setCategories($categories)
Sets object to given categories.
addline($desc, $pu, $txtva, $txlocaltax1, $txlocaltax2, $qty, $fk_product=0, $remise_percent=0, $date_start=0, $date_end=0, $fk_code_ventilation=0, $info_bits=0, $price_base_type='HT', $type=0, $rang=-1, $notrigger=0, $array_options=[], $fk_unit=null, $origin_id=0, $pu_devise=0, $ref_supplier='', $special_code=0, $fk_parent_line=0, $fk_remise_except=0)
Adds an invoice line (associated with no predefined product/service) The parameters are already suppo...
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 clickable link of object (with eventually picto)
load_board($user)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
getNomUrl($withpicto=0, $option='', $max=0, $short=0, $moretitle='', $notooltip=0, $save_lastsearch_value=-1, $addlinktonotes=0)
Return clickable name (with optional picto)
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.
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...
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=0, $date_start='', $date_end='', $array_options=[], $fk_unit=null, $pu_devise=0, $ref_supplier='', $rang=0)
Update a line detail in the database.
sendEmailsRemindersOnSupplierInvoiceDueDate($nbdays=0, $paymentmode='all', $template='', $datetouse='duedate', $forcerecipient='')
Send reminders by emails for supplier invoices validated that are due.
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.
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.
loadStateBoard()
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
const STATUS_CLOSED
Classified paid.
setVATReverseCharge($vatreversecharge)
Change the option VAT reverse charge.
Class to manage invoice templates.
Class permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
Class permettant la generation de composants html autre Only common components are here.
Class to manage stock movements.
static getIdAndTxFromCode($dbs, $code, $date_document=0)
Get id and rate of currency from code.
static getIdFromCode($dbs, $code)
Get id of currency from code.
Class to manage predefined suppliers products.
Class to manage products or services.
Class to manage line invoices.
Class to manage translations.
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:171
global $mysoc
dol_get_first_hour($date, $gm='tzserver')
Return GMT time for first hour of a given GMT date (it removes hours, min and second part)
Definition date.lib.php:678
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0, $tz='')
Add a delay to a date.
Definition date.lib.php:128
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_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0, $level=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_dir_list($utf8_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:64
dol_now($mode='gmt')
Return date for now.
setEntity($currentobject)
Set entity id to use when to create an object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
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 '.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
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.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
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_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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.
isValidEmail($address, $acceptsupervisorkey=0, $acceptuserkey=0)
Return true if email syntax is ok.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
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...
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller=null, $localtaxes_array=[], $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code='')
Calculate totals (net, vat, ...) of a line.
Definition price.lib.php:90
if(getDolGlobalString( 'TAKEPOS_SHOW_CUSTOMER')) print $langs trans('Date')." left Label right Qty right Price right TotalHT right TotalTTC right right right right right right right right right centpercent right TotalHT right n right VAT right n right TotalVAT right n No sujeto a RE IRPF right TotalLT1 right n right TotalLT2 right n right TotalTTC right n takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency right TotalTTC takeposcustomercurrency right takeposcustomercurrency n right PaymentTypeShortLIQ right SELECT p pos_change as p datep as date
Definition receipt.php:469
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:132