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