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