dolibarr 21.0.0-alpha
expensereport.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2011 Dimitri Mouillard <dmouillard@teclib.com>
3 * Copyright (C) 2015 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2015 Alexandre Spangaro <aspangaro@open-dsi.fr>
5 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
6 * Copyright (c) 2018-2024 Frédéric France <frederic.france@free.fr>
7 * Copyright (C) 2016-2020 Ferran Marcet <fmarcet@2byte.es>
8 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
9 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 */
24
30require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
31require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
32require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport_ik.class.php';
33require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport_rule.class.php';
34
35
40{
44 public $element = 'expensereport';
45
49 public $table_element = 'expensereport';
50
54 public $table_element_line = 'expensereport_det';
55
59 public $fk_element = 'fk_expensereport';
60
64 public $picto = 'trip';
65
69 public $lines = array();
70
74 public $line;
75
79 public $date_debut;
80
84 public $date_fin;
85
89 public $date_approbation;
90
94 public $fk_user;
95
99 public $user_approve_id;
100
106 public $status;
107
114 public $fk_statut;
115
119 public $fk_c_paiement;
120
124 public $modepaymentid;
125
126 public $paid;
127
128 // Paiement
132 public $user_paid_infos;
133
137 public $user_author_infos;
138
142 public $user_validator_infos;
143
144 public $rule_warning_message;
145
146 // ACTIONS
147
148 // Create
152 public $date_create;
153
157 public $fk_user_creat;
158
162 public $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
163
164 // Update
168 public $date_modif;
169
173 public $fk_user_modif;
174
175 // Refus
179 public $date_refuse;
180
184 public $detail_refuse;
185
189 public $fk_user_refuse;
190
191 // Annulation
195 public $date_cancel;
196
200 public $detail_cancel;
201
205 public $fk_user_cancel;
206
210 public $fk_user_validator;
211
218 public $datevalid;
219
224 public $date_valid;
225
229 public $fk_user_valid;
230
234 public $user_valid_infos;
235
236 // Approve
240 public $date_approve;
241
245 public $fk_user_approve;
246
247 public $localtax1; // for backward compatibility (real field should be total_localtax1 defined into CommonObject)
248 public $localtax2; // for backward compatibility (real field should be total_localtax2 defined into CommonObject)
249
253 const STATUS_DRAFT = 0;
254
259
264
269
273 const STATUS_CLOSED = 6;
274
278 const STATUS_REFUSED = 99;
279
280 public $fields = array(
281 'rowid' => array('type' => 'integer', 'label' => 'ID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
282 'ref' => array('type' => 'varchar(50)', 'label' => 'Ref', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'showoncombobox' => 1, 'position' => 15),
283 'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 20),
284 'ref_number_int' => array('type' => 'integer', 'label' => 'Ref number int', 'enabled' => 1, 'visible' => -1, 'position' => 25),
285 'ref_ext' => array('type' => 'integer', 'label' => 'Ref ext', 'enabled' => 1, 'visible' => -1, 'position' => 30),
286 'total_ht' => array('type' => 'double(24,8)', 'label' => 'Total ht', 'enabled' => 1, 'visible' => -1, 'position' => 35),
287 'total_tva' => array('type' => 'double(24,8)', 'label' => 'Total tva', 'enabled' => 1, 'visible' => -1, 'position' => 40),
288 'localtax1' => array('type' => 'double(24,8)', 'label' => 'Localtax1', 'enabled' => 1, 'visible' => -1, 'position' => 45),
289 'localtax2' => array('type' => 'double(24,8)', 'label' => 'Localtax2', 'enabled' => 1, 'visible' => -1, 'position' => 50),
290 'total_ttc' => array('type' => 'double(24,8)', 'label' => 'Total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 55),
291 'date_debut' => array('type' => 'date', 'label' => 'Date debut', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 60),
292 'date_fin' => array('type' => 'date', 'label' => 'Date fin', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 65),
293 'date_valid' => array('type' => 'datetime', 'label' => 'Date valid', 'enabled' => 1, 'visible' => -1, 'position' => 75),
294 'date_approve' => array('type' => 'datetime', 'label' => 'Date approve', 'enabled' => 1, 'visible' => -1, 'position' => 80),
295 'date_refuse' => array('type' => 'datetime', 'label' => 'Date refuse', 'enabled' => 1, 'visible' => -1, 'position' => 85),
296 'date_cancel' => array('type' => 'datetime', 'label' => 'Date cancel', 'enabled' => 1, 'visible' => -1, 'position' => 90),
297 'fk_user_author' => array('type' => 'integer', 'label' => 'Fk user author', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 100),
298 'fk_user_modif' => array('type' => 'integer', 'label' => 'Fk user modif', 'enabled' => 1, 'visible' => -1, 'position' => 105),
299 'fk_user_valid' => array('type' => 'integer', 'label' => 'Fk user valid', 'enabled' => 1, 'visible' => -1, 'position' => 110),
300 'fk_user_validator' => array('type' => 'integer', 'label' => 'Fk user validator', 'enabled' => 1, 'visible' => -1, 'position' => 115),
301 'fk_user_approve' => array('type' => 'integer', 'label' => 'Fk user approve', 'enabled' => 1, 'visible' => -1, 'position' => 120),
302 'fk_user_refuse' => array('type' => 'integer', 'label' => 'Fk user refuse', 'enabled' => 1, 'visible' => -1, 'position' => 125),
303 'fk_user_cancel' => array('type' => 'integer', 'label' => 'Fk user cancel', 'enabled' => 1, 'visible' => -1, 'position' => 130),
304 'fk_c_paiement' => array('type' => 'integer', 'label' => 'Fk c paiement', 'enabled' => 1, 'visible' => -1, 'position' => 140),
305 'paid' => array('type' => 'integer', 'label' => 'Paid', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 145),
306 'note_public' => array('type' => 'html', 'label' => 'Note public', 'enabled' => 1, 'visible' => 0, 'position' => 150),
307 'note_private' => array('type' => 'html', 'label' => 'Note private', 'enabled' => 1, 'visible' => 0, 'position' => 155),
308 'detail_refuse' => array('type' => 'varchar(255)', 'label' => 'Detail refuse', 'enabled' => 1, 'visible' => -1, 'position' => 160),
309 'detail_cancel' => array('type' => 'varchar(255)', 'label' => 'Detail cancel', 'enabled' => 1, 'visible' => -1, 'position' => 165),
310 'integration_compta' => array('type' => 'integer', 'label' => 'Integration compta', 'enabled' => 1, 'visible' => -1, 'position' => 170),
311 'fk_bank_account' => array('type' => 'integer', 'label' => 'Fk bank account', 'enabled' => 1, 'visible' => -1, 'position' => 175),
312 'fk_multicurrency' => array('type' => 'integer', 'label' => 'Fk multicurrency', 'enabled' => 1, 'visible' => -1, 'position' => 185),
313 'multicurrency_code' => array('type' => 'varchar(255)', 'label' => 'Multicurrency code', 'enabled' => 1, 'visible' => -1, 'position' => 190),
314 'multicurrency_tx' => array('type' => 'double(24,8)', 'label' => 'Multicurrency tx', 'enabled' => 1, 'visible' => -1, 'position' => 195),
315 'multicurrency_total_ht' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ht', 'enabled' => 1, 'visible' => -1, 'position' => 200),
316 'multicurrency_total_tva' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total tva', 'enabled' => 1, 'visible' => -1, 'position' => 205),
317 'multicurrency_total_ttc' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 210),
318 'extraparams' => array('type' => 'varchar(255)', 'label' => 'Extraparams', 'enabled' => 1, 'visible' => -1, 'position' => 220),
319 'date_create' => array('type' => 'datetime', 'label' => 'Date create', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 300),
320 'tms' => array('type' => 'timestamp', 'label' => 'Tms', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 305),
321 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -1, 'position' => 1000),
322 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'visible' => 0, 'position' => 1010),
323 'fk_statut' => array('type' => 'integer', 'label' => 'Fk statut', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 500),
324 );
325
331 public function __construct($db)
332 {
333 $this->db = $db;
334 $this->total_ht = 0;
335 $this->total_ttc = 0;
336 $this->total_tva = 0;
337 $this->total_localtax1 = 0;
338 $this->total_localtax2 = 0;
339 $this->localtax1 = 0; // For backward compatibility
340 $this->localtax2 = 0; // For backward compatibility
341 $this->modepaymentid = 0;
342
343 // List of language codes for status
344 $this->labelStatusShort = array(0 => 'Draft', 2 => 'Validated', 4 => 'Canceled', 5 => 'Approved', 6 => 'Paid', 99 => 'Refused');
345 $this->labelStatus = array(0 => 'Draft', 2 => 'ValidatedWaitingApproval', 4 => 'Canceled', 5 => 'Approved', 6 => 'Paid', 99 => 'Refused');
346 }
347
355 public function create($user, $notrigger = 0)
356 {
357 global $conf, $langs;
358
359 $now = dol_now();
360
361 $error = 0;
362
363 // Check parameters
364 if (empty($this->date_debut) || empty($this->date_fin)) {
365 $this->error = $langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Date'));
366 return -1;
367 }
368
369 $fuserid = $this->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
370 if (empty($fuserid)) {
371 $fuserid = $user->id;
372 }
373
374 $this->db->begin();
375
376 $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
377 $sql .= "ref";
378 $sql .= ",total_ht";
379 $sql .= ",total_ttc";
380 $sql .= ",total_tva";
381 $sql .= ",date_debut";
382 $sql .= ",date_fin";
383 $sql .= ",date_create";
384 $sql .= ",fk_user_creat";
385 $sql .= ",fk_user_author";
386 $sql .= ",fk_user_validator";
387 $sql .= ",fk_user_approve";
388 $sql .= ",fk_user_modif";
389 $sql .= ",fk_statut";
390 $sql .= ",fk_c_paiement";
391 $sql .= ",paid";
392 $sql .= ",note_public";
393 $sql .= ",note_private";
394 $sql .= ",entity";
395 $sql .= ") VALUES(";
396 $sql .= "'(PROV)'";
397 $sql .= ", ".price2num($this->total_ht, 'MT');
398 $sql .= ", ".price2num($this->total_ttc, 'MT');
399 $sql .= ", ".price2num($this->total_tva, 'MT');
400 $sql .= ", '".$this->db->idate($this->date_debut)."'";
401 $sql .= ", '".$this->db->idate($this->date_fin)."'";
402 $sql .= ", '".$this->db->idate($now)."'";
403 $sql .= ", ".((int) $user->id);
404 $sql .= ", ".((int) $fuserid);
405 $sql .= ", ".($this->fk_user_validator > 0 ? ((int) $this->fk_user_validator) : "null");
406 $sql .= ", ".($this->fk_user_approve > 0 ? ((int) $this->fk_user_approve) : "null");
407 $sql .= ", ".($this->fk_user_modif > 0 ? ((int) $this->fk_user_modif) : "null");
408 $sql .= ", ".($this->fk_statut > 1 ? ((int) $this->fk_statut) : 0);
409 $sql .= ", ".($this->modepaymentid ? ((int) $this->modepaymentid) : "null");
410 $sql .= ", 0";
411 $sql .= ", ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : "null");
412 $sql .= ", ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "null");
413 $sql .= ", ".((int) $conf->entity);
414 $sql .= ")";
415
416 $result = $this->db->query($sql);
417 if ($result) {
418 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
419 $this->ref = '(PROV'.$this->id.')';
420
421 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".((int) $this->id);
422 $resql = $this->db->query($sql);
423 if (!$resql) {
424 $this->error = $this->db->lasterror();
425 $error++;
426 }
427
428 if (!$error) {
429 if (is_array($this->lines) && count($this->lines) > 0) {
430 foreach ($this->lines as $line) {
431 // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
432 //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
433 if (!is_object($line)) {
434 $line = (object) $line;
435 $newndfline = new ExpenseReportLine($this->db);
436 $newndfline->fk_expensereport = $line->fk_expensereport;
437 $newndfline->fk_c_type_fees = $line->fk_c_type_fees;
438 $newndfline->fk_project = $line->fk_project;
439 $newndfline->vatrate = $line->vatrate;
440 $newndfline->vat_src_code = $line->vat_src_code;
441 $newndfline->localtax1_tx = $line->localtax1_tx;
442 $newndfline->localtax2_tx = $line->localtax2_tx;
443 $newndfline->localtax1_type = $line->localtax1_type;
444 $newndfline->localtax2_type = $line->localtax2_type;
445 $newndfline->comments = $line->comments;
446 $newndfline->qty = $line->qty;
447 $newndfline->value_unit = $line->value_unit;
448 $newndfline->total_ht = $line->total_ht;
449 $newndfline->total_ttc = $line->total_ttc;
450 $newndfline->total_tva = $line->total_tva;
451 $newndfline->total_localtax1 = $line->total_localtax1;
452 $newndfline->total_localtax2 = $line->total_localtax2;
453 $newndfline->date = $line->date;
454 $newndfline->rule_warning_message = $line->rule_warning_message;
455 $newndfline->fk_c_exp_tax_cat = $line->fk_c_exp_tax_cat;
456 $newndfline->fk_ecm_files = $line->fk_ecm_files;
457 } else {
458 $newndfline = $line;
459 }
460 //$newndfline=new ExpenseReportLine($this->db);
461 $newndfline->fk_expensereport = $this->id;
462 $result = $newndfline->insert();
463 if ($result < 0) {
464 $this->error = $newndfline->error;
465 $this->errors = $newndfline->errors;
466 $error++;
467 break;
468 }
469 }
470 }
471 }
472
473 if (!$error) {
474 $result = $this->insertExtraFields();
475 if ($result < 0) {
476 $error++;
477 }
478 }
479
480 if (!$error) {
481 $result = $this->update_price(1);
482 if ($result > 0) {
483 if (!$notrigger) {
484 // Call trigger
485 $result = $this->call_trigger('EXPENSE_REPORT_CREATE', $user);
486
487 if ($result < 0) {
488 $error++;
489 }
490 // End call triggers
491 }
492
493 if (empty($error)) {
494 $this->db->commit();
495 return $this->id;
496 } else {
497 $this->db->rollback();
498 return -4;
499 }
500 } else {
501 $this->db->rollback();
502 return -3;
503 }
504 } else {
505 dol_syslog(get_class($this)."::create error ".$this->error, LOG_ERR);
506 $this->db->rollback();
507 return -2;
508 }
509 } else {
510 $this->error = $this->db->lasterror()." sql=".$sql;
511 $this->db->rollback();
512 return -1;
513 }
514 }
515
523 public function createFromClone(User $user, $fk_user_author)
524 {
525 global $hookmanager;
526
527 $error = 0;
528
529 if (empty($fk_user_author)) {
530 $fk_user_author = $user->id;
531 }
532
533 $this->db->begin();
534
535 // get extrafields so they will be clone
536 //foreach($this->lines as $line)
537 //$line->fetch_optionals();
538
539 // Load source object
540 $objFrom = clone $this;
541
542 $this->id = 0;
543 $this->ref = '';
544 $this->status = 0;
545 $this->fk_statut = 0; // deprecated
546
547 // Clear fields
548 $this->fk_user_creat = $user->id;
549 $this->fk_user_author = $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
550 $this->fk_user_valid = 0;
551 $this->date_create = '';
552 $this->date_creation = '';
553 $this->date_validation = '';
554
555 // Remove link on lines to a joined file
556 if (is_array($this->lines) && count($this->lines) > 0) {
557 foreach ($this->lines as $key => $line) {
558 $this->lines[$key]->fk_ecm_files = 0;
559 }
560 }
561
562 // Create clone
563 $this->context['createfromclone'] = 'createfromclone';
564 $result = $this->create($user);
565 if ($result < 0) {
566 $error++;
567 }
568
569 if (!$error) {
570 // Hook of thirdparty module
571 if (is_object($hookmanager)) {
572 $parameters = array('objFrom' => $objFrom);
573 $action = '';
574 $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
575 if ($reshook < 0) {
576 $this->setErrorsFromObject($hookmanager);
577 $error++;
578 }
579 }
580 }
581
582 unset($this->context['createfromclone']);
583
584 // End
585 if (!$error) {
586 $this->db->commit();
587 return $this->id;
588 } else {
589 $this->db->rollback();
590 return -1;
591 }
592 }
593
594
603 public function update($user, $notrigger = 0, $userofexpensereport = null)
604 {
605 global $langs;
606
607 $error = 0;
608 $this->db->begin();
609
610 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
611 $sql .= " total_ht = ".$this->total_ht;
612 $sql .= " , total_ttc = ".$this->total_ttc;
613 $sql .= " , total_tva = ".$this->total_tva;
614 $sql .= " , date_debut = '".$this->db->idate($this->date_debut)."'";
615 $sql .= " , date_fin = '".$this->db->idate($this->date_fin)."'";
616 if ($userofexpensereport && is_object($userofexpensereport)) {
617 $sql .= " , fk_user_author = ".($userofexpensereport->id > 0 ? $userofexpensereport->id : "null"); // Note fk_user_author is not the 'author' but the guy the expense report is for.
618 }
619 $sql .= " , fk_user_validator = ".($this->fk_user_validator > 0 ? $this->fk_user_validator : "null");
620 $sql .= " , fk_user_valid = ".($this->fk_user_valid > 0 ? $this->fk_user_valid : "null");
621 $sql .= " , fk_user_approve = ".($this->fk_user_approve > 0 ? $this->fk_user_approve : "null");
622 $sql .= " , fk_user_modif = ".$user->id;
623 $sql .= " , fk_statut = ".($this->fk_statut >= 0 ? $this->fk_statut : '0');
624 $sql .= " , fk_c_paiement = ".($this->fk_c_paiement > 0 ? $this->fk_c_paiement : "null");
625 $sql .= " , note_public = ".(!empty($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "''");
626 $sql .= " , note_private = ".(!empty($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "''");
627 $sql .= " , detail_refuse = ".(!empty($this->detail_refuse) ? "'".$this->db->escape($this->detail_refuse)."'" : "''");
628 $sql .= " WHERE rowid = ".((int) $this->id);
629
630 dol_syslog(get_class($this)."::update", LOG_DEBUG);
631 $result = $this->db->query($sql);
632 if ($result) {
633 if (!$notrigger) {
634 // Call trigger
635 $result = $this->call_trigger('EXPENSE_REPORT_MODIFY', $user);
636
637 if ($result < 0) {
638 $error++;
639 }
640 // End call triggers
641 }
642
643 if (empty($error)) {
644 $this->db->commit();
645 return 1;
646 } else {
647 $this->db->rollback();
648 $this->error = $this->db->error();
649 return -2;
650 }
651 } else {
652 $this->db->rollback();
653 $this->error = $this->db->error();
654 return -1;
655 }
656 }
657
665 public function fetch($id, $ref = '')
666 {
667 $sql = "SELECT d.rowid, d.entity, d.ref, d.note_public, d.note_private,"; // DEFAULT
668 $sql .= " d.detail_refuse, d.detail_cancel, d.fk_user_refuse, d.fk_user_cancel,"; // ACTIONS
669 $sql .= " d.date_refuse, d.date_cancel,"; // ACTIONS
670 $sql .= " d.total_ht, d.total_ttc, d.total_tva,";
671 $sql .= " d.localtax1 as total_localtax1, d.localtax2 as total_localtax2,";
672 $sql .= " d.date_debut, d.date_fin, d.date_create, d.tms as date_modif, d.date_valid, d.date_approve,"; // DATES (datetime)
673 $sql .= " d.fk_user_creat, d.fk_user_author, d.fk_user_modif, d.fk_user_validator,";
674 $sql .= " d.fk_user_valid, d.fk_user_approve,";
675 $sql .= " d.fk_statut as status, d.fk_c_paiement, d.paid";
676 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as d";
677 if ($ref) {
678 $sql .= " WHERE d.ref = '".$this->db->escape($ref)."'";
679 } else {
680 $sql .= " WHERE d.rowid = ".((int) $id);
681 }
682 //$sql.= $restrict;
683
684 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
685 $resql = $this->db->query($sql);
686 if ($resql) {
687 $obj = $this->db->fetch_object($resql);
688 if ($obj) {
689 $this->id = $obj->rowid;
690 $this->ref = $obj->ref;
691
692 $this->entity = $obj->entity;
693
694 $this->total_ht = $obj->total_ht;
695 $this->total_tva = $obj->total_tva;
696 $this->total_ttc = $obj->total_ttc;
697 $this->localtax1 = $obj->total_localtax1; // For backward compatibility
698 $this->localtax2 = $obj->total_localtax2; // For backward compatibility
699 $this->total_localtax1 = $obj->total_localtax1;
700 $this->total_localtax2 = $obj->total_localtax2;
701
702 $this->note_public = $obj->note_public;
703 $this->note_private = $obj->note_private;
704 $this->detail_refuse = $obj->detail_refuse;
705 $this->detail_cancel = $obj->detail_cancel;
706
707 $this->date_debut = $this->db->jdate($obj->date_debut);
708 $this->date_fin = $this->db->jdate($obj->date_fin);
709 $this->date_valid = $this->db->jdate($obj->date_valid);
710 $this->date_approve = $this->db->jdate($obj->date_approve);
711 $this->date_create = $this->db->jdate($obj->date_create);
712 $this->date_modif = $this->db->jdate($obj->date_modif);
713 $this->date_refuse = $this->db->jdate($obj->date_refuse);
714 $this->date_cancel = $this->db->jdate($obj->date_cancel);
715
716 $this->fk_user_creat = $obj->fk_user_creat;
717 $this->fk_user_author = $obj->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
718 $this->fk_user_modif = $obj->fk_user_modif;
719 $this->fk_user_validator = $obj->fk_user_validator;
720 $this->fk_user_valid = $obj->fk_user_valid;
721 $this->fk_user_refuse = $obj->fk_user_refuse;
722 $this->fk_user_cancel = $obj->fk_user_cancel;
723 $this->fk_user_approve = $obj->fk_user_approve;
724
725 $user_author = new User($this->db);
726 if ($this->fk_user_author > 0) {
727 $user_author->fetch($this->fk_user_author);
728 }
729
730 $this->user_author_infos = dolGetFirstLastname($user_author->firstname, $user_author->lastname);
731
732 $user_approver = new User($this->db);
733 if ($this->fk_user_approve > 0) {
734 $user_approver->fetch($this->fk_user_approve);
735 } elseif ($this->fk_user_validator > 0) {
736 $user_approver->fetch($this->fk_user_validator); // For backward compatibility
737 }
738 $this->user_validator_infos = dolGetFirstLastname($user_approver->firstname, $user_approver->lastname);
739
740 $this->fk_statut = $obj->status; // deprecated
741 $this->status = $obj->status;
742 $this->fk_c_paiement = $obj->fk_c_paiement;
743 $this->paid = $obj->paid;
744
745 if ($this->status == self::STATUS_APPROVED || $this->status == self::STATUS_CLOSED) {
746 $user_valid = new User($this->db);
747 if ($this->fk_user_valid > 0) {
748 $user_valid->fetch($this->fk_user_valid);
749 }
750 $this->user_valid_infos = dolGetFirstLastname($user_valid->firstname, $user_valid->lastname);
751 }
752
753 $this->fetch_optionals();
754
755 $result = $this->fetch_lines();
756
757 return $result;
758 } else {
759 return 0;
760 }
761 } else {
762 $this->error = $this->db->lasterror();
763 return -1;
764 }
765 }
766
767 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
778 public function set_paid($id, $fuser, $notrigger = 0)
779 {
780 // phpcs:enable
781 dol_syslog(get_class($this)."::set_paid is deprecated, use setPaid instead", LOG_NOTICE);
782 return $this->setPaid($id, $fuser, $notrigger);
783 }
784
793 public function setPaid($id, $fuser, $notrigger = 0)
794 {
795 $error = 0;
796 $this->db->begin();
797
798 $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport";
799 $sql .= " SET fk_statut = ".self::STATUS_CLOSED.", paid=1";
800 $sql .= " WHERE rowid = ".((int) $id)." AND fk_statut = ".self::STATUS_APPROVED;
801
802 dol_syslog(get_class($this)."::setPaid", LOG_DEBUG);
803 $resql = $this->db->query($sql);
804 if ($resql) {
805 if ($this->db->affected_rows($resql)) {
806 if (!$notrigger) {
807 // Call trigger
808 $result = $this->call_trigger('EXPENSE_REPORT_PAID', $fuser);
809
810 if ($result < 0) {
811 $error++;
812 }
813 // End call triggers
814 }
815
816 if (empty($error)) {
817 $this->db->commit();
818 return 1;
819 } else {
820 $this->db->rollback();
821 $this->error = $this->db->error();
822 return -2;
823 }
824 } else {
825 $this->db->commit();
826 return 0;
827 }
828 } else {
829 $this->db->rollback();
830 dol_print_error($this->db);
831 return -1;
832 }
833 }
834
841 public function getLibStatut($mode = 0)
842 {
843 return $this->LibStatut($this->status, $mode);
844 }
845
846 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
854 public function LibStatut($status, $mode = 0)
855 {
856 // phpcs:enable
857 global $langs;
858
859 $labelStatus = $langs->transnoentitiesnoconv($this->labelStatus[$status]);
860 $labelStatusShort = $langs->transnoentitiesnoconv($this->labelStatusShort[$status]);
861
862 $statuslogo = array(0 => 'status0', 2 => 'status1', 4 => 'status6', 5 => 'status4', 6 => 'status6', 99 => 'status5');
863
864 $statusType = $statuslogo[$status];
865
866 return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
867 }
868
869
876 public function info($id)
877 {
878 global $conf;
879
880 $sql = "SELECT f.rowid,";
881 $sql .= " f.date_create as datec,";
882 $sql .= " f.tms as date_modification,";
883 $sql .= " f.date_valid as datev,";
884 $sql .= " f.date_approve as datea,";
885 $sql .= " f.fk_user_creat as fk_user_creation,";
886 $sql .= " f.fk_user_author as fk_user_author,";
887 $sql .= " f.fk_user_modif as fk_user_modification,";
888 $sql .= " f.fk_user_valid,";
889 $sql .= " f.fk_user_approve";
890 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as f";
891 $sql .= " WHERE f.rowid = ".((int) $id);
892 $sql .= " AND f.entity = ".$conf->entity;
893
894
895
896 $resql = $this->db->query($sql);
897 if ($resql) {
898 if ($this->db->num_rows($resql)) {
899 $obj = $this->db->fetch_object($resql);
900
901 $this->id = $obj->rowid;
902
903 $this->date_creation = $this->db->jdate($obj->datec);
904 $this->date_modification = $this->db->jdate($obj->date_modification);
905 $this->date_validation = $this->db->jdate($obj->datev);
906 $this->date_approbation = $this->db->jdate($obj->datea);
907
908 $this->user_creation_id = $obj->fk_user_author;
909 $this->user_creation_id = $obj->fk_user_creation;
910 $this->user_validation_id = $obj->fk_user_valid;
911 $this->user_modification_id = $obj->fk_user_modification;
912 $this->user_approve_id = $obj->fk_user_approve;
913 }
914 $this->db->free($resql);
915 } else {
916 dol_print_error($this->db);
917 }
918 }
919
920
921
929 public function initAsSpecimen()
930 {
931 global $user, $langs;
932
933 $now = dol_now();
934
935 // Initialise parameters
936 $this->id = 0;
937 $this->ref = 'SPECIMEN';
938 $this->specimen = 1;
939 $this->entity = 1;
940 $this->date_create = $now;
941 $this->date_debut = $now;
942 $this->date_fin = $now;
943 $this->date_valid = $now;
944 $this->date_approve = $now;
945
946 $type_fees_id = 2; // TF_TRIP
947
948 $this->status = 5;
949
950 $this->fk_user_author = $user->id;
951 $this->fk_user_validator = $user->id;
952 $this->fk_user_valid = $user->id;
953 $this->fk_user_approve = $user->id;
954
955 $this->note_private = 'Private note';
956 $this->note_public = 'SPECIMEN';
957 $nbp = 5;
958 $xnbp = 0;
959 while ($xnbp < $nbp) {
960 $line = new ExpenseReportLine($this->db);
961 $line->comments = $langs->trans("Comment")." ".$xnbp;
962 $line->date = ($now - 3600 * (1 + $xnbp));
963 $line->total_ht = 100;
964 $line->total_tva = 20;
965 $line->total_ttc = 120;
966 $line->qty = 1;
967 $line->vatrate = 20;
968 $line->value_unit = 120;
969 $line->fk_expensereport = 0;
970 $line->type_fees_code = 'TRA';
971 $line->fk_c_type_fees = $type_fees_id;
972
973 $line->projet_ref = 'ABC';
974
975 $this->lines[$xnbp] = $line;
976 $xnbp++;
977
978 $this->total_ht += $line->total_ht;
979 $this->total_tva += $line->total_tva;
980 $this->total_ttc += $line->total_ttc;
981 }
982
983 return 1;
984 }
985
986 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
994 public function fetch_line_by_project($projectid, $user)
995 {
996 // phpcs:enable
997 global $langs;
998
999 $langs->load('trips');
1000
1001 if ($user->hasRight('expensereport', 'lire')) {
1002 $sql = "SELECT de.fk_expensereport, de.date, de.comments, de.total_ht, de.total_ttc";
1003 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport_det as de";
1004 $sql .= " WHERE de.fk_projet = ".((int) $projectid);
1005
1006 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1007 $result = $this->db->query($sql);
1008 if ($result) {
1009 $num = $this->db->num_rows($result);
1010 $i = 0;
1011 $total_HT = 0;
1012 $total_TTC = 0;
1013
1014 while ($i < $num) {
1015 $objp = $this->db->fetch_object($result);
1016
1017 $sql2 = "SELECT d.rowid, d.fk_user_author, d.ref, d.fk_statut as status";
1018 $sql2 .= " FROM ".MAIN_DB_PREFIX."expensereport as d";
1019 $sql2 .= " WHERE d.rowid = ".((int) $objp->fk_expensereport);
1020
1021 $result2 = $this->db->query($sql2);
1022 $obj = $this->db->fetch_object($result2);
1023
1024 $objp->fk_user_author = $obj->fk_user_author;
1025 $objp->ref = $obj->ref;
1026 $objp->fk_c_expensereport_status = $obj->status;
1027 $objp->rowid = $obj->rowid;
1028
1029 $total_HT += $objp->total_ht;
1030 $total_TTC += $objp->total_ttc;
1031 $author = new User($this->db);
1032 $author->fetch($objp->fk_user_author);
1033
1034 print '<tr>';
1035 print '<td><a href="'.DOL_URL_ROOT.'/expensereport/card.php?id='.$objp->rowid.'">'.$objp->ref_num.'</a></td>';
1036 print '<td class="center">'.dol_print_date($objp->date, 'day').'</td>';
1037 print '<td>'.$author->getNomUrl(1).'</td>';
1038 print '<td>'.$objp->comments.'</td>';
1039 print '<td class="right">'.price($objp->total_ht).'</td>';
1040 print '<td class="right">'.price($objp->total_ttc).'</td>';
1041 print '<td class="right">';
1042
1043 switch ($objp->fk_c_expensereport_status) {
1044 case 4:
1045 print img_picto($langs->trans('StatusOrderCanceled'), 'statut5');
1046 break;
1047 case 1:
1048 print $langs->trans('Draft').' '.img_picto($langs->trans('Draft'), 'statut0');
1049 break;
1050 case 2:
1051 print $langs->trans('TripForValid').' '.img_picto($langs->trans('TripForValid'), 'statut3');
1052 break;
1053 case 5:
1054 print $langs->trans('TripForPaid').' '.img_picto($langs->trans('TripForPaid'), 'statut3');
1055 break;
1056 case 6:
1057 print $langs->trans('TripPaid').' '.img_picto($langs->trans('TripPaid'), 'statut4');
1058 break;
1059 }
1060 /*
1061 if ($status==4) return img_picto($langs->trans('StatusOrderCanceled'),'statut5');
1062 if ($status==1) return img_picto($langs->trans('StatusOrderDraft'),'statut0');
1063 if ($status==2) return img_picto($langs->trans('StatusOrderValidated'),'statut1');
1064 if ($status==2) return img_picto($langs->trans('StatusOrderOnProcess'),'statut3');
1065 if ($status==5) return img_picto($langs->trans('StatusOrderToBill'),'statut4');
1066 if ($status==6) return img_picto($langs->trans('StatusOrderOnProcess'),'statut6');
1067 */
1068 print '</td>';
1069 print '</tr>';
1070
1071 $i++;
1072 }
1073
1074 print '<tr class="liste_total"><td colspan="4">'.$langs->trans("Number").': '.$i.'</td>';
1075 print '<td class="right" width="100">'.$langs->trans("TotalHT").' : '.price($total_HT).'</td>';
1076 print '<td class="right" width="100">'.$langs->trans("TotalTTC").' : '.price($total_TTC).'</td>';
1077 print '<td>&nbsp;</td>';
1078 print '</tr>';
1079 } else {
1080 $this->error = $this->db->lasterror();
1081 return -1;
1082 }
1083 }
1084
1085 return 0;
1086 }
1087
1088 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1094 public function fetch_lines()
1095 {
1096 // phpcs:enable
1097 $this->lines = array();
1098
1099 $sql = ' SELECT de.rowid, de.comments, de.qty, de.value_unit, de.date, de.rang,';
1100 $sql .= " de.".$this->fk_element.", de.fk_c_type_fees, de.fk_c_exp_tax_cat, de.fk_projet as fk_project,";
1101 $sql .= ' de.tva_tx, de.vat_src_code,';
1102 $sql .= ' de.localtax1_tx, de.localtax2_tx, de.localtax1_type, de.localtax2_type,';
1103 $sql .= ' de.fk_ecm_files,';
1104 $sql .= ' de.total_ht, de.total_tva, de.total_ttc,';
1105 $sql .= ' de.total_localtax1, de.total_localtax2, de.rule_warning_message,';
1106 $sql .= ' ctf.code as code_type_fees, ctf.label as label_type_fees, ctf.accountancy_code as accountancy_code_type_fees,';
1107 $sql .= ' p.ref as ref_projet, p.title as title_projet';
1108 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as de';
1109 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_type_fees as ctf ON de.fk_c_type_fees = ctf.id';
1110 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as p ON de.fk_projet = p.rowid';
1111 $sql .= " WHERE de.".$this->fk_element." = ".((int) $this->id);
1112 if (getDolGlobalString('EXPENSEREPORT_LINES_SORTED_BY_ROWID')) {
1113 $sql .= ' ORDER BY de.rang ASC, de.rowid ASC';
1114 } else {
1115 $sql .= ' ORDER BY de.rang ASC, de.date ASC';
1116 }
1117
1118 $resql = $this->db->query($sql);
1119 if ($resql) {
1120 $num = $this->db->num_rows($resql);
1121 $i = 0;
1122 while ($i < $num) {
1123 $objp = $this->db->fetch_object($resql);
1124
1125 $deplig = new ExpenseReportLine($this->db);
1126
1127 $deplig->rowid = $objp->rowid;
1128 $deplig->id = $objp->rowid;
1129 $deplig->comments = $objp->comments;
1130 $deplig->qty = $objp->qty;
1131 $deplig->value_unit = $objp->value_unit;
1132 $deplig->date = $objp->date;
1133 $deplig->dates = $this->db->jdate($objp->date);
1134
1135 $deplig->fk_expensereport = $objp->fk_expensereport;
1136 $deplig->fk_c_type_fees = $objp->fk_c_type_fees;
1137 $deplig->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
1138 $deplig->fk_projet = $objp->fk_project; // deprecated
1139 $deplig->fk_project = $objp->fk_project;
1140 $deplig->fk_ecm_files = $objp->fk_ecm_files;
1141
1142 $deplig->total_ht = $objp->total_ht;
1143 $deplig->total_tva = $objp->total_tva;
1144 $deplig->total_ttc = $objp->total_ttc;
1145 $deplig->total_localtax1 = $objp->total_localtax1;
1146 $deplig->total_localtax2 = $objp->total_localtax2;
1147
1148 $deplig->type_fees_code = empty($objp->code_type_fees) ? 'TF_OTHER' : $objp->code_type_fees;
1149 $deplig->type_fees_libelle = $objp->label_type_fees;
1150 $deplig->type_fees_accountancy_code = $objp->accountancy_code_type_fees;
1151
1152 $deplig->tva_tx = $objp->tva_tx;
1153 $deplig->vatrate = $objp->tva_tx;
1154 $deplig->vat_src_code = $objp->vat_src_code;
1155 $deplig->localtax1_tx = $objp->localtax1_tx;
1156 $deplig->localtax2_tx = $objp->localtax2_tx;
1157 $deplig->localtax1_type = $objp->localtax1_type;
1158 $deplig->localtax2_type = $objp->localtax2_type;
1159
1160 $deplig->projet_ref = $objp->ref_projet;
1161 $deplig->projet_title = $objp->title_projet;
1162
1163 $deplig->rule_warning_message = $objp->rule_warning_message;
1164
1165 $deplig->rang = $objp->rang;
1166
1167 $this->lines[$i] = $deplig;
1168
1169 $i++;
1170 }
1171 $this->db->free($resql);
1172 return 1;
1173 } else {
1174 $this->error = $this->db->lasterror();
1175 dol_syslog(get_class($this)."::fetch_lines: Error ".$this->error, LOG_ERR);
1176 return -3;
1177 }
1178 }
1179
1180
1188 public function delete(User $user = null, $notrigger = 0)
1189 {
1190 global $conf;
1191 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1192
1193 $error = 0;
1194
1195 $this->db->begin();
1196
1197 if (!$notrigger) {
1198 // Call trigger
1199 $result = $this->call_trigger('EXPENSE_REPORT_DELETE', $user);
1200 if ($result < 0) {
1201 $error++;
1202 }
1203 // End call triggers
1204 }
1205
1206 // Delete extrafields of lines and lines
1207 if (!$error && !empty($this->table_element_line)) {
1208 $tabletodelete = $this->table_element_line;
1209 //$sqlef = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete."_extrafields WHERE fk_object IN (SELECT rowid FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id).")";
1210 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id);
1211 if (!$this->db->query($sql)) {
1212 $error++;
1213 $this->error = $this->db->lasterror();
1214 $this->errors[] = $this->error;
1215 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1216 }
1217 }
1218
1219 if (!$error) {
1220 // Delete linked object
1221 $res = $this->deleteObjectLinked();
1222 if ($res < 0) {
1223 $error++;
1224 }
1225 }
1226
1227 if (!$error) {
1228 // Delete linked contacts
1229 $res = $this->delete_linked_contact();
1230 if ($res < 0) {
1231 $error++;
1232 }
1233 }
1234
1235 // Removed extrafields of object
1236 if (!$error) {
1237 $result = $this->deleteExtraFields();
1238 if ($result < 0) {
1239 $error++;
1240 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1241 }
1242 }
1243
1244 // Delete main record
1245 if (!$error) {
1246 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".((int) $this->id);
1247 $res = $this->db->query($sql);
1248 if (!$res) {
1249 $error++;
1250 $this->error = $this->db->lasterror();
1251 $this->errors[] = $this->error;
1252 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1253 }
1254 }
1255
1256 // Delete record into ECM index and physically
1257 if (!$error) {
1258 $res = $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
1259 $res = $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive
1260 if (!$res) {
1261 $error++;
1262 }
1263 }
1264
1265 if (!$error) {
1266 // We remove directory
1267 $ref = dol_sanitizeFileName($this->ref);
1268 if ($conf->expensereport->multidir_output[$this->entity] && !empty($this->ref)) {
1269 $dir = $conf->expensereport->multidir_output[$this->entity]."/".$ref;
1270 $file = $dir."/".$ref.".pdf";
1271 if (file_exists($file)) {
1272 dol_delete_preview($this);
1273
1274 if (!dol_delete_file($file, 0, 0, 0, $this)) {
1275 $this->error = 'ErrorFailToDeleteFile';
1276 $this->errors[] = $this->error;
1277 $this->db->rollback();
1278 return 0;
1279 }
1280 }
1281 if (file_exists($dir)) {
1282 $res = @dol_delete_dir_recursive($dir);
1283 if (!$res) {
1284 $this->error = 'ErrorFailToDeleteDir';
1285 $this->errors[] = $this->error;
1286 $this->db->rollback();
1287 return 0;
1288 }
1289 }
1290 }
1291 }
1292
1293 if (!$error) {
1294 dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
1295 $this->db->commit();
1296 return 1;
1297 } else {
1298 $this->db->rollback();
1299 return -1;
1300 }
1301 }
1302
1310 public function setValidate($fuser, $notrigger = 0)
1311 {
1312 global $conf, $langs, $user;
1313
1314 $error = 0;
1315 $now = dol_now();
1316
1317 // Protection
1318 if ($this->status == self::STATUS_VALIDATED) {
1319 dol_syslog(get_class($this)."::valid action abandoned: already validated", LOG_WARNING);
1320 return 0;
1321 }
1322
1323 $this->date_valid = $now; // Required for the getNextNum later.
1324
1325 // Define new ref
1326 if (!$error && (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
1327 $num = $this->getNextNumRef();
1328 } else {
1329 $num = $this->ref;
1330 }
1331 if (empty($num) || $num < 0) {
1332 return -1;
1333 }
1334
1335 $this->newref = dol_sanitizeFileName($num);
1336
1337 $this->db->begin();
1338
1339 // Validate
1340 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1341 $sql .= " SET ref = '".$this->db->escape($num)."',";
1342 $sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
1343 $sql .= " date_valid = '".$this->db->idate($this->date_valid)."',";
1344 $sql .= " fk_user_valid = ".((int) $user->id);
1345 $sql .= " WHERE rowid = ".((int) $this->id);
1346
1347 $resql = $this->db->query($sql);
1348 if ($resql) {
1349 if (!$error && !$notrigger) {
1350 // Call trigger
1351 $result = $this->call_trigger('EXPENSE_REPORT_VALIDATE', $fuser);
1352 if ($result < 0) {
1353 $error++;
1354 }
1355 // End call triggers
1356 }
1357
1358 if (!$error) {
1359 $this->oldref = $this->ref;
1360
1361 // Rename directory if dir was a temporary ref
1362 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
1363 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1364
1365 // Now we rename also files into index
1366 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'expensereport/".$this->db->escape($this->newref)."'";
1367 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'expensereport/".$this->db->escape($this->ref)."' AND entity = ".((int) $this->entity);
1368 $resql = $this->db->query($sql);
1369 if (!$resql) {
1370 $error++;
1371 $this->error = $this->db->lasterror();
1372 }
1373 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'expensereport/".$this->db->escape($this->newref)."'";
1374 $sql .= " WHERE filepath = 'expensereport/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1375 $resql = $this->db->query($sql);
1376 if (!$resql) {
1377 $error++;
1378 $this->error = $this->db->lasterror();
1379 }
1380
1381 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1382 $oldref = dol_sanitizeFileName($this->ref);
1383 $newref = dol_sanitizeFileName($num);
1384 $dirsource = $conf->expensereport->multidir_output[$this->entity].'/'.$oldref;
1385 $dirdest = $conf->expensereport->multidir_output[$this->entity].'/'.$newref;
1386 if (!$error && file_exists($dirsource)) {
1387 dol_syslog(get_class($this)."::setValidate() rename dir ".$dirsource." into ".$dirdest);
1388
1389 if (@rename($dirsource, $dirdest)) {
1390 dol_syslog("Rename ok");
1391 // Rename docs starting with $oldref with $newref
1392 $listoffiles = dol_dir_list($dirdest, 'files', 1, '^'.preg_quote($oldref, '/'));
1393 foreach ($listoffiles as $fileentry) {
1394 $dirsource = $fileentry['name'];
1395 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1396 $dirsource = $fileentry['path'].'/'.$dirsource;
1397 $dirdest = $fileentry['path'].'/'.$dirdest;
1398 @rename($dirsource, $dirdest);
1399 }
1400 }
1401 }
1402 }
1403 }
1404
1405 // Set new ref and current status
1406 if (!$error) {
1407 $this->ref = $num;
1409 }
1410
1411 if (empty($error)) {
1412 $this->db->commit();
1413 return 1;
1414 } else {
1415 $this->db->rollback();
1416 $this->error = $this->db->error();
1417 return -2;
1418 }
1419 } else {
1420 $this->db->rollback();
1421 $this->error = $this->db->lasterror();
1422 return -1;
1423 }
1424 }
1425
1426 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1433 public function set_save_from_refuse($fuser)
1434 {
1435 // phpcs:enable
1436 // Sélection de la date de début de la NDF
1437 $sql = 'SELECT date_debut';
1438 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
1439 $sql .= " WHERE rowid = ".((int) $this->id);
1440
1441 $result = $this->db->query($sql);
1442
1443 $objp = $this->db->fetch_object($result);
1444
1445 $this->date_debut = $this->db->jdate($objp->date_debut);
1446
1447 if ($this->status != self::STATUS_VALIDATED) {
1448 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1449 $sql .= " SET fk_statut = ".self::STATUS_VALIDATED;
1450 $sql .= " WHERE rowid = ".((int) $this->id);
1451
1452 dol_syslog(get_class($this)."::set_save_from_refuse", LOG_DEBUG);
1453
1454 if ($this->db->query($sql)) {
1455 return 1;
1456 } else {
1457 $this->error = $this->db->lasterror();
1458 return -1;
1459 }
1460 } else {
1461 dol_syslog(get_class($this)."::set_save_from_refuse expensereport already with save status", LOG_WARNING);
1462 }
1463
1464 return 0;
1465 }
1466
1474 public function setApproved($fuser, $notrigger = 0)
1475 {
1476 $now = dol_now();
1477 $error = 0;
1478
1479 // date approval
1480 $this->date_approve = $now;
1481 if ($this->status != self::STATUS_APPROVED) {
1482 $this->db->begin();
1483
1484 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1485 $sql .= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = ".self::STATUS_APPROVED.", fk_user_approve = ".((int) $fuser->id).",";
1486 $sql .= " date_approve='".$this->db->idate($this->date_approve)."'";
1487 $sql .= " WHERE rowid = ".((int) $this->id);
1488 if ($this->db->query($sql)) {
1489 if (!$notrigger) {
1490 // Call trigger
1491 $result = $this->call_trigger('EXPENSE_REPORT_APPROVE', $fuser);
1492
1493 if ($result < 0) {
1494 $error++;
1495 }
1496 // End call triggers
1497 }
1498
1499 if (empty($error)) {
1500 $this->db->commit();
1501 return 1;
1502 } else {
1503 $this->db->rollback();
1504 $this->error = $this->db->error();
1505 return -2;
1506 }
1507 } else {
1508 $this->db->rollback();
1509 $this->error = $this->db->lasterror();
1510 return -1;
1511 }
1512 } else {
1513 dol_syslog(get_class($this)."::setApproved expensereport already with approve status", LOG_WARNING);
1514 }
1515
1516 return 0;
1517 }
1518
1527 public function setDeny($fuser, $details, $notrigger = 0)
1528 {
1529 $now = dol_now();
1530 $error = 0;
1531
1532 // date de refus
1533 if ($this->status != self::STATUS_REFUSED) {
1534 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1535 $sql .= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = ".self::STATUS_REFUSED.", fk_user_refuse = ".((int) $fuser->id).",";
1536 $sql .= " date_refuse='".$this->db->idate($now)."',";
1537 $sql .= " detail_refuse='".$this->db->escape($details)."',";
1538 $sql .= " fk_user_approve = NULL";
1539 $sql .= " WHERE rowid = ".((int) $this->id);
1540 if ($this->db->query($sql)) {
1541 $this->fk_statut = 99; // deprecated
1542 $this->status = 99;
1543 $this->fk_user_refuse = $fuser->id;
1544 $this->detail_refuse = $details;
1545 $this->date_refuse = $now;
1546
1547 if (!$notrigger) {
1548 // Call trigger
1549 $result = $this->call_trigger('EXPENSE_REPORT_DENY', $fuser);
1550
1551 if ($result < 0) {
1552 $error++;
1553 }
1554 // End call triggers
1555 }
1556
1557 if (empty($error)) {
1558 $this->db->commit();
1559 return 1;
1560 } else {
1561 $this->db->rollback();
1562 $this->error = $this->db->error();
1563 return -2;
1564 }
1565 } else {
1566 $this->db->rollback();
1567 $this->error = $this->db->lasterror();
1568 return -1;
1569 }
1570 } else {
1571 dol_syslog(get_class($this)."::setDeny expensereport already with refuse status", LOG_WARNING);
1572 }
1573
1574 return 0;
1575 }
1576
1577 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1587 public function set_unpaid($fuser, $notrigger = 0)
1588 {
1589 // phpcs:enable
1590 dol_syslog(get_class($this)."::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE);
1591 return $this->setUnpaid($fuser, $notrigger);
1592 }
1593
1601 public function setUnpaid($fuser, $notrigger = 0)
1602 {
1603 $error = 0;
1604
1605 if ($this->paid) {
1606 $this->db->begin();
1607
1608 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1609 $sql .= " SET paid = 0, fk_statut = ".self::STATUS_APPROVED;
1610 $sql .= " WHERE rowid = ".((int) $this->id);
1611
1612 dol_syslog(get_class($this)."::set_unpaid", LOG_DEBUG);
1613
1614 if ($this->db->query($sql)) {
1615 if (!$notrigger) {
1616 // Call trigger
1617 $result = $this->call_trigger('EXPENSE_REPORT_UNPAID', $fuser);
1618
1619 if ($result < 0) {
1620 $error++;
1621 }
1622 // End call triggers
1623 }
1624
1625 if (empty($error)) {
1626 $this->db->commit();
1627 return 1;
1628 } else {
1629 $this->db->rollback();
1630 $this->error = $this->db->error();
1631 return -2;
1632 }
1633 } else {
1634 $this->db->rollback();
1635 $this->error = $this->db->error();
1636 return -1;
1637 }
1638 } else {
1639 dol_syslog(get_class($this)."::set_unpaid expensereport already with unpaid status", LOG_WARNING);
1640 }
1641
1642 return 0;
1643 }
1644
1645 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1654 public function set_cancel($fuser, $detail, $notrigger = 0)
1655 {
1656 // phpcs:enable
1657 $error = 0;
1658 $this->date_cancel = $this->db->idate(dol_now());
1659 if ($this->status != self::STATUS_CANCELED) {
1660 $this->db->begin();
1661
1662 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1663 $sql .= " SET fk_statut = ".self::STATUS_CANCELED.", fk_user_cancel = ".((int) $fuser->id);
1664 $sql .= ", date_cancel='".$this->db->idate($this->date_cancel)."'";
1665 $sql .= ", detail_cancel='".$this->db->escape($detail)."'";
1666 $sql .= " WHERE rowid = ".((int) $this->id);
1667
1668 dol_syslog(get_class($this)."::set_cancel", LOG_DEBUG);
1669
1670 if ($this->db->query($sql)) {
1671 if (!$notrigger) {
1672 // Call trigger
1673 $result = $this->call_trigger('EXPENSE_REPORT_CANCEL', $fuser);
1674
1675 if ($result < 0) {
1676 $error++;
1677 }
1678 // End call triggers
1679 }
1680
1681 if (empty($error)) {
1682 $this->db->commit();
1683 return 1;
1684 } else {
1685 $this->db->rollback();
1686 $this->error = $this->db->error();
1687 return -2;
1688 }
1689 } else {
1690 $this->db->rollback();
1691 $this->error = $this->db->error();
1692 return -1;
1693 }
1694 } else {
1695 dol_syslog(get_class($this)."::set_cancel expensereport already with cancel status", LOG_WARNING);
1696 }
1697 return 0;
1698 }
1699
1705 public function getNextNumRef()
1706 {
1707 global $langs, $conf;
1708 $langs->load("trips");
1709
1710 if (getDolGlobalString('EXPENSEREPORT_ADDON')) {
1711 $mybool = false;
1712
1713 $file = getDolGlobalString('EXPENSEREPORT_ADDON') . ".php";
1714 $classname = getDolGlobalString('EXPENSEREPORT_ADDON');
1715
1716 // Include file with class
1717 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1718 foreach ($dirmodels as $reldir) {
1719 $dir = dol_buildpath($reldir."core/modules/expensereport/");
1720
1721 // Load file with numbering class (if found)
1722 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1723 }
1724
1725 if (!$mybool) {
1726 dol_print_error(null, "Failed to include file ".$file);
1727 return '';
1728 }
1729
1730 $obj = new $classname();
1731 $numref = $obj->getNextValue($this);
1732
1733 if ($numref != "") {
1734 return $numref;
1735 } else {
1736 $this->error = $obj->error;
1737 $this->errors = $obj->errors;
1738 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1739 return -1;
1740 }
1741 } else {
1742 $this->error = "Error_EXPENSEREPORT_ADDON_NotDefined";
1743 return -2;
1744 }
1745 }
1746
1754 public function getTooltipContentArray($params)
1755 {
1756 global $conf, $langs;
1757
1758 $langs->load('trips');
1759
1760 $nofetch = !empty($params['nofetch']);
1761 $moretitle = $params['moretitle'] ?? '';
1762
1763 $datas = array();
1764 $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("ExpenseReport").'</u>';
1765 if (isset($this->status)) {
1766 $datas['picto'] .= ' '.$this->getLibStatut(5);
1767 }
1768 if ($moretitle) {
1769 $datas['picto'] .= ' - '.$moretitle;
1770 }
1771 if (!empty($this->ref)) {
1772 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1773 }
1774 if (!empty($this->total_ht)) {
1775 $datas['total_ht'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
1776 }
1777 if (!empty($this->total_tva)) {
1778 $datas['total_tva'] = '<br><b>'.$langs->trans('VAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
1779 }
1780 if (!empty($this->total_ttc)) {
1781 $datas['total_ttc'] = '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
1782 }
1783
1784 return $datas;
1785 }
1786
1799 public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1)
1800 {
1801 global $langs, $hookmanager;
1802
1803 $result = '';
1804
1805 $url = DOL_URL_ROOT.'/expensereport/card.php?id='.$this->id;
1806
1807 if ($short) {
1808 return $url;
1809 }
1810
1811 $params = [
1812 'id' => $this->id,
1813 'objecttype' => $this->element,
1814 'option' => $option,
1815 'moretitle' => $moretitle,
1816 'nofetch' => 1,
1817 ];
1818 $classfortooltip = 'classfortooltip';
1819 $dataparams = '';
1820 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1821 $classfortooltip = 'classforajaxtooltip';
1822 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1823 $label = '';
1824 } else {
1825 $label = implode($this->getTooltipContentArray($params));
1826 }
1827
1828 if ($option != 'nolink') {
1829 // Add param to save lastsearch_values or not
1830 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1831 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1832 $add_save_lastsearch_values = 1;
1833 }
1834 if ($add_save_lastsearch_values) {
1835 $url .= '&save_lastsearch_values=1';
1836 }
1837 }
1838
1839 $ref = $this->ref;
1840 if (empty($ref)) {
1841 $ref = $this->id;
1842 }
1843
1844 $linkclose = '';
1845 if (empty($notooltip)) {
1846 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1847 $label = $langs->trans("ShowExpenseReport");
1848 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1849 }
1850 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1851 $linkclose .= $dataparams.' class="'.$classfortooltip.'"';
1852 }
1853
1854 $linkstart = '<a href="'.$url.'"';
1855 $linkstart .= $linkclose.'>';
1856 $linkend = '</a>';
1857
1858 $result .= $linkstart;
1859 if ($withpicto) {
1860 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'"'), 0, 0, $notooltip ? 0 : 1);
1861 }
1862 if ($withpicto != 2) {
1863 $result .= ($max ? dol_trunc($ref, $max) : $ref);
1864 }
1865 $result .= $linkend;
1866
1867 global $action;
1868 $hookmanager->initHooks(array($this->element . 'dao'));
1869 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1870 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1871 if ($reshook > 0) {
1872 $result = $hookmanager->resPrint;
1873 } else {
1874 $result .= $hookmanager->resPrint;
1875 }
1876 return $result;
1877 }
1878
1879 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1887 public function update_totaux_add($ligne_total_ht, $ligne_total_tva)
1888 {
1889 // phpcs:enable
1890 $this->total_ht += (float) $ligne_total_ht;
1891 $this->total_tva += (float) $ligne_total_tva;
1892 $this->total_ttc += $this->total_tva;
1893
1894 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
1895 $sql .= " total_ht = ".$this->total_ht;
1896 $sql .= " , total_ttc = ".$this->total_ttc;
1897 $sql .= " , total_tva = ".$this->total_tva;
1898 $sql .= " WHERE rowid = ".((int) $this->id);
1899
1900 $result = $this->db->query($sql);
1901 if ($result) {
1902 return 1;
1903 } else {
1904 $this->error = $this->db->error();
1905 return -1;
1906 }
1907 }
1908
1924 public function addline($qty = 0, $up = 0, $fk_c_type_fees = 0, $vatrate = 0, $date = '', $comments = '', $fk_project = 0, $fk_c_exp_tax_cat = 0, $type = 0, $fk_ecm_files = 0)
1925 {
1926 global $langs, $mysoc;
1927
1928 dol_syslog(get_class($this)."::addline qty=$qty, up=$up, fk_c_type_fees=$fk_c_type_fees, vatrate=$vatrate, date=$date, fk_project=$fk_project, type=$type, comments=$comments", LOG_DEBUG);
1929
1930 if ($this->status == self::STATUS_DRAFT) {
1931 if (empty($qty)) {
1932 $qty = 0;
1933 }
1934 if (empty($fk_c_type_fees) || $fk_c_type_fees < 0) {
1935 $fk_c_type_fees = 0;
1936 }
1937 if (empty($fk_c_exp_tax_cat) || $fk_c_exp_tax_cat < 0) {
1938 $fk_c_exp_tax_cat = 0;
1939 }
1940 if (empty($vatrate) || $vatrate < 0) {
1941 $vatrate = 0;
1942 }
1943 if (empty($date)) {
1944 $date = '';
1945 }
1946 if (empty($fk_project)) {
1947 $fk_project = 0;
1948 }
1949
1950 $qty = (float) price2num($qty);
1951 if (!preg_match('/\s*\‍((.*)\‍)/', $vatrate)) {
1952 $vatrate = price2num($vatrate); // $txtva can have format '5.0 (XXX)' or '5'
1953 }
1954 $up = price2num($up);
1955
1956 $this->db->begin();
1957
1958 $this->line = new ExpenseReportLine($this->db);
1959
1960 // We don't know seller and buyer for expense reports
1961 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
1962 $seller->tva_assuj = 1; // Most seller uses vat
1963 $buyer = new Societe($this->db);
1964
1965 $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller);
1966
1967 $vat_src_code = '';
1968 $reg = array();
1969 if (preg_match('/\s*\‍((.*)\‍)/', $vatrate, $reg)) {
1970 $vat_src_code = $reg[1];
1971 $vatrate = preg_replace('/\s*\‍(.*\‍)/', '', $vatrate); // Remove code into vatrate.
1972 }
1973 $vatrate = preg_replace('/\*/', '', $vatrate);
1974
1975 $tmp = calcul_price_total($qty, $up, 0, (float) price2num($vatrate), -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
1976
1977 $this->line->value_unit = $up;
1978
1979 $this->line->vat_src_code = $vat_src_code;
1980 $this->line->vatrate = price2num($vatrate);
1981 $this->line->localtax1_tx = $localtaxes_type[1];
1982 $this->line->localtax2_tx = $localtaxes_type[3];
1983 $this->line->localtax1_type = $localtaxes_type[0];
1984 $this->line->localtax2_type = $localtaxes_type[2];
1985
1986 $this->line->total_ttc = $tmp[2];
1987 $this->line->total_ht = $tmp[0];
1988 $this->line->total_tva = $tmp[1];
1989 $this->line->total_localtax1 = $tmp[9];
1990 $this->line->total_localtax2 = $tmp[10];
1991
1992 $this->line->fk_expensereport = $this->id;
1993 $this->line->qty = $qty;
1994 $this->line->date = $date;
1995 $this->line->fk_c_type_fees = $fk_c_type_fees;
1996 $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
1997 $this->line->comments = $comments;
1998 $this->line->fk_projet = $fk_project; // deprecated
1999 $this->line->fk_project = $fk_project;
2000
2001 $this->line->fk_ecm_files = $fk_ecm_files;
2002
2003 $this->applyOffset();
2004 $this->checkRules($type, $seller);
2005
2006 $result = $this->line->insert(0, true);
2007 if ($result > 0) {
2008 $result = $this->update_price(1); // This method is designed to add line from user input so total calculation must be done using 'auto' mode.
2009 if ($result > 0) {
2010 $this->db->commit();
2011 return $this->line->id;
2012 } else {
2013 $this->db->rollback();
2014 return -1;
2015 }
2016 } else {
2017 $this->error = $this->line->error;
2018 dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
2019 $this->db->rollback();
2020 return -2;
2021 }
2022 } else {
2023 dol_syslog(get_class($this)."::addline status of expense report must be Draft to allow use of ->addline()", LOG_ERR);
2024 $this->error = 'ErrorExpenseNotDraft';
2025 return -3;
2026 }
2027 }
2028
2036 public function checkRules($type = 0, $seller = '')
2037 {
2038 global $conf, $db, $langs, $mysoc;
2039
2040 $langs->load('trips');
2041
2042 // We don't know seller and buyer for expense reports
2043 if (!is_object($seller)) {
2044 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
2045 $seller->tva_assuj = 1; // Most seller uses vat
2046 }
2047
2048 $expensereportrule = new ExpenseReportRule($db);
2049 $rulestocheck = $expensereportrule->getAllRule($this->line->fk_c_type_fees, $this->line->date, $this->fk_user_author);
2050
2051 $violation = 0;
2052 $rule_warning_message_tab = array();
2053
2054 $current_total_ttc = $this->line->total_ttc;
2055 $new_current_total_ttc = $this->line->total_ttc;
2056
2057 // check if one is violated
2058 foreach ($rulestocheck as $rule) {
2059 if (in_array($rule->code_expense_rules_type, array('EX_DAY', 'EX_MON', 'EX_YEA'))) {
2060 $amount_to_test = $this->line->getExpAmount($rule, $this->fk_user_author, $rule->code_expense_rules_type);
2061 } else {
2062 $amount_to_test = $current_total_ttc; // EX_EXP
2063 }
2064
2065 $amount_to_test = $amount_to_test - $current_total_ttc + $new_current_total_ttc; // if amount as been modified by a previous rule
2066
2067 if ($amount_to_test > $rule->amount) {
2068 $violation++;
2069
2070 if ($rule->restrictive) {
2071 $this->error = 'ExpenseReportConstraintViolationError';
2072 $this->errors[] = $this->error;
2073
2074 $new_current_total_ttc -= $amount_to_test - $rule->amount; // ex, entered 16€, limit 12€, subtracts 4€;
2075 $rule_warning_message_tab[] = $langs->trans('ExpenseReportConstraintViolationError', $rule->id, price($amount_to_test, 0, $langs, 1, -1, -1, $conf->currency), price($rule->amount, 0, $langs, 1, -1, -1, $conf->currency));
2076 } else {
2077 $this->error = 'ExpenseReportConstraintViolationWarning';
2078 $this->errors[] = $this->error;
2079
2080 $rule_warning_message_tab[] = $langs->trans('ExpenseReportConstraintViolationWarning', $rule->id, price($amount_to_test, 0, $langs, 1, -1, -1, $conf->currency), price($rule->amount, 0, $langs, 1, -1, -1, $conf->currency));
2081 }
2082
2083 // No break, we should test if another rule is violated
2084 }
2085 }
2086
2087 $this->line->rule_warning_message = implode('\n', $rule_warning_message_tab);
2088
2089 if ($violation > 0) {
2090 $tmp = calcul_price_total($this->line->qty, $new_current_total_ttc / $this->line->qty, 0, $this->line->vatrate, 0, 0, 0, 'TTC', 0, $type, $seller);
2091
2092 $this->line->value_unit = $tmp[5];
2093 $this->line->total_ttc = $tmp[2];
2094 $this->line->total_ht = $tmp[0];
2095 $this->line->total_tva = $tmp[1];
2096 $this->line->total_localtax1 = $tmp[9];
2097 $this->line->total_localtax2 = $tmp[10];
2098
2099 return false;
2100 } else {
2101 return true;
2102 }
2103 }
2104
2112 public function applyOffset($type = 0, $seller = '')
2113 {
2114 global $mysoc;
2115
2116 if (!getDolGlobalString('MAIN_USE_EXPENSE_IK')) {
2117 return false;
2118 }
2119
2120 $userauthor = new User($this->db);
2121 if ($userauthor->fetch($this->fk_user_author) <= 0) {
2122 $this->error = 'ErrorCantFetchUser';
2123 $this->errors[] = 'ErrorCantFetchUser';
2124 return false;
2125 }
2126
2127 // We don't know seller and buyer for expense reports
2128 if (!is_object($seller)) {
2129 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
2130 $seller->tva_assuj = 1; // Most seller uses vat
2131 }
2132
2133 $expenseik = new ExpenseReportIk($this->db);
2134 $range = $expenseik->getRangeByUser($userauthor, $this->line->fk_c_exp_tax_cat);
2135
2136 if (empty($range)) {
2137 $this->error = 'ErrorNoRangeAvailable';
2138 $this->errors[] = 'ErrorNoRangeAvailable';
2139 return false;
2140 }
2141
2142 if (getDolGlobalString('MAIN_EXPENSE_APPLY_ENTIRE_OFFSET')) {
2143 $ikoffset = $range->ikoffset;
2144 } else {
2145 $ikoffset = $range->ikoffset / 12; // The amount of offset is a global value for the year
2146 }
2147
2148 // Test if ikoffset has been applied for the current month
2149 if (!$this->offsetAlreadyGiven()) {
2150 $new_up = $range->coef + ($ikoffset / $this->line->qty);
2151 $tmp = calcul_price_total($this->line->qty, $new_up, 0, $this->line->vatrate, 0, 0, 0, 'TTC', 0, $type, $seller);
2152
2153 $this->line->value_unit = $tmp[5];
2154 $this->line->total_ttc = $tmp[2];
2155 $this->line->total_ht = $tmp[0];
2156 $this->line->total_tva = $tmp[1];
2157 $this->line->total_localtax1 = $tmp[9];
2158 $this->line->total_localtax2 = $tmp[10];
2159
2160 return true;
2161 }
2162
2163 return false;
2164 }
2165
2171 public function offsetAlreadyGiven()
2172 {
2173 $sql = 'SELECT e.rowid FROM '.MAIN_DB_PREFIX.'expensereport e';
2174 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."expensereport_det d ON (e.rowid = d.fk_expensereport)";
2175 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."c_type_fees f ON (d.fk_c_type_fees = f.id AND f.code = 'EX_KME')";
2176 $sql .= " WHERE e.fk_user_author = ".(int) $this->fk_user_author;
2177 $sql .= " AND YEAR(d.date) = '".dol_print_date($this->line->date, '%Y')."' AND MONTH(d.date) = '".dol_print_date($this->line->date, '%m')."'";
2178 if (!empty($this->line->id)) {
2179 $sql .= ' AND d.rowid <> '.((int) $this->line->id);
2180 }
2181
2182 dol_syslog(get_class($this)."::offsetAlreadyGiven");
2183 $resql = $this->db->query($sql);
2184 if ($resql) {
2185 $num = $this->db->num_rows($resql);
2186 if ($num > 0) {
2187 return true;
2188 }
2189 } else {
2190 dol_print_error($this->db);
2191 }
2192
2193 return false;
2194 }
2195
2213 public function updateline($rowid, $type_fees_id, $projet_id, $vatrate, $comments, $qty, $value_unit, $date, $expensereport_id, $fk_c_exp_tax_cat = 0, $fk_ecm_files = 0, $notrigger = 0)
2214 {
2215 global $user, $mysoc;
2216
2217 if ($this->status == self::STATUS_DRAFT || $this->status == self::STATUS_REFUSED) {
2218 $this->db->begin();
2219
2220 $error = 0;
2221 $type = 0; // TODO What if type is service ?
2222
2223 // We don't know seller and buyer for expense reports
2224 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
2225 $seller->tva_assuj = 1; // Most seller uses vat
2226 $seller->localtax1_assuj = $mysoc->localtax1_assuj; // We don't know, we reuse the state of company
2227 $seller->localtax2_assuj = $mysoc->localtax1_assuj; // We don't know, we reuse the state of company
2228 $buyer = new Societe($this->db);
2229
2230 $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller);
2231
2232 // Clean vat code
2233 $reg = array();
2234 $vat_src_code = '';
2235 if (preg_match('/\‍((.*)\‍)/', (string) $vatrate, $reg)) {
2236 $vat_src_code = $reg[1];
2237 $vatrate = preg_replace('/\s*\‍(.*\‍)/', '', (string) $vatrate); // Remove code into vatrate.
2238 }
2239 $vatrate = preg_replace('/\*/', '', $vatrate);
2240
2241 $tmp = calcul_price_total($qty, $value_unit, 0, (float) price2num($vatrate), -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
2242 // calcul total of line
2243 // $total_ttc = price2num($qty*$value_unit, 'MT');
2244
2245 $tx_tva = 1 + (float) $vatrate / 100;
2246
2247 $this->line = new ExpenseReportLine($this->db);
2248 $this->line->comments = $comments;
2249 $this->line->qty = $qty;
2250 $this->line->value_unit = $value_unit;
2251 $this->line->date = $date;
2252
2253 $this->line->fk_expensereport = $expensereport_id;
2254 $this->line->fk_c_type_fees = $type_fees_id;
2255 $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
2256 $this->line->fk_projet = $projet_id; // deprecated
2257 $this->line->fk_project = $projet_id;
2258
2259 $this->line->vat_src_code = $vat_src_code;
2260 $this->line->vatrate = price2num($vatrate);
2261 $this->line->localtax1_tx = $localtaxes_type[1];
2262 $this->line->localtax2_tx = $localtaxes_type[3];
2263 $this->line->localtax1_type = $localtaxes_type[0];
2264 $this->line->localtax2_type = $localtaxes_type[2];
2265
2266 $this->line->total_ttc = $tmp[2];
2267 $this->line->total_ht = $tmp[0];
2268 $this->line->total_tva = $tmp[1];
2269 $this->line->total_localtax1 = $tmp[9];
2270 $this->line->total_localtax2 = $tmp[10];
2271
2272 $this->line->fk_ecm_files = $fk_ecm_files;
2273
2274 $this->line->id = ((int) $rowid);
2275
2276 // Select des infos sur le type fees
2277 $sql = "SELECT c.code as code_type_fees, c.label as label_type_fees";
2278 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
2279 $sql .= " WHERE c.id = ".((int) $type_fees_id);
2280 $resql = $this->db->query($sql);
2281 if ($resql) {
2282 $objp_fees = $this->db->fetch_object($resql);
2283 $this->line->type_fees_code = $objp_fees->code_type_fees;
2284 $this->line->type_fees_libelle = $objp_fees->label_type_fees;
2285 $this->db->free($resql);
2286 }
2287
2288 // Select des information du projet
2289 $sql = "SELECT p.ref as ref_projet, p.title as title_projet";
2290 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
2291 $sql .= " WHERE p.rowid = ".((int) $projet_id);
2292 $resql = $this->db->query($sql);
2293 if ($resql) {
2294 $objp_projet = $this->db->fetch_object($resql);
2295 $this->line->projet_ref = $objp_projet->ref_projet;
2296 $this->line->projet_title = $objp_projet->title_projet;
2297 $this->db->free($resql);
2298 }
2299
2300 $this->applyOffset();
2301 $this->checkRules();
2302
2303 $result = $this->line->update($user);
2304 if ($result < 0) {
2305 $error++;
2306 }
2307
2308 if (!$error && !$notrigger) {
2309 // Call triggers
2310 $result = $this->call_trigger('EXPENSE_REPORT_DET_MODIFY', $user);
2311 if ($result < 0) {
2312 $error++;
2313 }
2314 // End call triggers
2315 }
2316
2317 if (!$error) {
2318 $this->db->commit();
2319 return 1;
2320 } else {
2321 $this->error = $this->line->error;
2322 $this->errors = $this->line->errors;
2323 $this->db->rollback();
2324 return -2;
2325 }
2326 }
2327
2328 return 0;
2329 }
2330
2339 public function deleteLine($rowid, $fuser = '', $notrigger = 0)
2340 {
2341 $error = 0;
2342
2343 $this->db->begin();
2344
2345 if (!$notrigger) {
2346 // Call triggers
2347 $result = $this->call_trigger('EXPENSE_REPORT_DET_DELETE', $fuser);
2348 if ($result < 0) {
2349 $error++;
2350 }
2351 // End call triggers
2352 }
2353
2354 $sql = ' DELETE FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2355 $sql .= ' WHERE rowid = '.((int) $rowid);
2356
2357 dol_syslog(get_class($this)."::deleteline sql=".$sql);
2358 $result = $this->db->query($sql);
2359
2360 if (!$result || $error > 0) {
2361 $this->error = $this->db->error();
2362 dol_syslog(get_class($this)."::deleteline Error ".$this->error, LOG_ERR);
2363 $this->db->rollback();
2364 return -1;
2365 }
2366
2367 $this->update_price(1);
2368
2369 $this->db->commit();
2370
2371 return 1;
2372 }
2373
2374 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2383 public function periode_existe($fuser, $date_debut, $date_fin)
2384 {
2385 global $conf;
2386
2387 // phpcs:enable
2388 $sql = "SELECT rowid, date_debut, date_fin";
2389 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
2390 $sql .= " WHERE entity = ".((int) $conf->entity); // not shared, only for the current entity
2391 $sql .= " AND fk_user_author = ".((int) $fuser->id);
2392
2393 dol_syslog(get_class($this)."::periode_existe sql=".$sql);
2394 $result = $this->db->query($sql);
2395 if ($result) {
2396 $num_rows = $this->db->num_rows($result);
2397 $i = 0;
2398
2399 if ($num_rows > 0) {
2400 $date_d_form = $date_debut;
2401 $date_f_form = $date_fin;
2402
2403 while ($i < $num_rows) {
2404 $objp = $this->db->fetch_object($result);
2405
2406 $date_d_req = $this->db->jdate($objp->date_debut); // 3
2407 $date_f_req = $this->db->jdate($objp->date_fin); // 4
2408
2409 if (!($date_f_form < $date_d_req || $date_d_form > $date_f_req)) {
2410 return $objp->rowid;
2411 }
2412
2413 $i++;
2414 }
2415
2416 return 0;
2417 } else {
2418 return 0;
2419 }
2420 } else {
2421 $this->error = $this->db->lasterror();
2422 dol_syslog(get_class($this)."::periode_existe Error ".$this->error, LOG_ERR);
2423 return -1;
2424 }
2425 }
2426
2427
2428 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2436 {
2437 // phpcs:enable
2438 $users_validator = array();
2439
2440 $sql = "SELECT DISTINCT ur.fk_user";
2441 $sql .= " FROM ".MAIN_DB_PREFIX."user_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2442 $sql .= " WHERE ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2443 $sql .= " UNION";
2444 $sql .= " SELECT DISTINCT ugu.fk_user";
2445 $sql .= " FROM ".MAIN_DB_PREFIX."usergroup_user as ugu, ".MAIN_DB_PREFIX."usergroup_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2446 $sql .= " WHERE ugu.fk_usergroup = ur.fk_usergroup AND ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2447 //print $sql;
2448
2449 dol_syslog(get_class($this)."::fetch_users_approver_expensereport sql=".$sql);
2450 $result = $this->db->query($sql);
2451 if ($result) {
2452 $num_rows = $this->db->num_rows($result);
2453 $i = 0;
2454 while ($i < $num_rows) {
2455 $objp = $this->db->fetch_object($result);
2456 array_push($users_validator, $objp->fk_user);
2457 $i++;
2458 }
2459 return $users_validator;
2460 } else {
2461 $this->error = $this->db->lasterror();
2462 dol_syslog(get_class($this)."::fetch_users_approver_expensereport Error ".$this->error, LOG_ERR);
2463 return -1;
2464 }
2465 }
2466
2478 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
2479 {
2480 $outputlangs->load("trips");
2481
2482 if (!dol_strlen($modele)) {
2483 if (!empty($this->model_pdf)) {
2484 $modele = $this->model_pdf;
2485 } elseif (getDolGlobalString('EXPENSEREPORT_ADDON_PDF')) {
2486 $modele = getDolGlobalString('EXPENSEREPORT_ADDON_PDF');
2487 }
2488 }
2489
2490 if (!empty($modele)) {
2491 $modelpath = "core/modules/expensereport/doc/";
2492
2493 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2494 } else {
2495 return 0;
2496 }
2497 }
2498
2505 public function listOfTypes($active = 1)
2506 {
2507 global $langs;
2508 $ret = array();
2509 $sql = "SELECT id, code, label";
2510 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees";
2511 $sql .= " WHERE active = ".((int) $active);
2512 dol_syslog(get_class($this)."::listOfTypes", LOG_DEBUG);
2513 $result = $this->db->query($sql);
2514 if ($result) {
2515 $num = $this->db->num_rows($result);
2516 $i = 0;
2517 while ($i < $num) {
2518 $obj = $this->db->fetch_object($result);
2519 $ret[$obj->code] = (($langs->transnoentitiesnoconv($obj->code) != $obj->code) ? $langs->transnoentitiesnoconv($obj->code) : $obj->label);
2520 $i++;
2521 }
2522 } else {
2523 dol_print_error($this->db);
2524 }
2525 return $ret;
2526 }
2527
2533 public function loadStateBoard()
2534 {
2535 global $user;
2536
2537 $this->nb = array();
2538
2539 $sql = "SELECT count(ex.rowid) as nb";
2540 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2541 $sql .= " WHERE ex.fk_statut > 0";
2542 $sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2543 if (!$user->hasRight('expensereport', 'readall')) {
2544 $userchildids = $user->getAllChildIds(1);
2545 $sql .= " AND (ex.fk_user_author IN (".$this->db->sanitize(implode(',', $userchildids)).")";
2546 $sql .= " OR ex.fk_user_validator IN (".$this->db->sanitize(implode(',', $userchildids))."))";
2547 }
2548
2549 $resql = $this->db->query($sql);
2550 if ($resql) {
2551 while ($obj = $this->db->fetch_object($resql)) {
2552 $this->nb["expensereports"] = $obj->nb;
2553 }
2554 $this->db->free($resql);
2555 return 1;
2556 } else {
2557 dol_print_error($this->db);
2558 $this->error = $this->db->error();
2559 return -1;
2560 }
2561 }
2562
2563 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2571 public function load_board($user, $option = 'topay')
2572 {
2573 // phpcs:enable
2574 global $conf, $langs;
2575
2576 if ($user->socid) {
2577 return -1; // protection pour eviter appel par utilisateur externe
2578 }
2579
2580 $now = dol_now();
2581
2582 $sql = "SELECT ex.rowid, ex.date_valid";
2583 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2584 if ($option == 'toapprove') {
2585 $sql .= " WHERE ex.fk_statut = ".self::STATUS_VALIDATED;
2586 } else {
2587 $sql .= " WHERE ex.fk_statut = ".self::STATUS_APPROVED;
2588 }
2589 $sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2590 if (!$user->hasRight('expensereport', 'readall')) {
2591 $userchildids = $user->getAllChildIds(1);
2592 $sql .= " AND (ex.fk_user_author IN (".$this->db->sanitize(implode(',', $userchildids)).")";
2593 $sql .= " OR ex.fk_user_validator IN (".$this->db->sanitize(implode(',', $userchildids))."))";
2594 }
2595
2596 $resql = $this->db->query($sql);
2597 if ($resql) {
2598 $langs->load("trips");
2599
2600 $response = new WorkboardResponse();
2601 if ($option == 'toapprove') {
2602 $response->warning_delay = $conf->expensereport->approve->warning_delay / 60 / 60 / 24;
2603 $response->label = $langs->trans("ExpenseReportsToApprove");
2604 $response->labelShort = $langs->trans("ToApprove");
2605 $response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_VALIDATED;
2606 } else {
2607 $response->warning_delay = $conf->expensereport->payment->warning_delay / 60 / 60 / 24;
2608 $response->label = $langs->trans("ExpenseReportsToPay");
2609 $response->labelShort = $langs->trans("StatusToPay");
2610 $response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_APPROVED;
2611 }
2612 $response->img = img_object('', "trip");
2613
2614 while ($obj = $this->db->fetch_object($resql)) {
2615 $response->nbtodo++;
2616
2617 if ($option == 'toapprove') {
2618 if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->approve->warning_delay)) {
2619 $response->nbtodolate++;
2620 }
2621 } else {
2622 if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->payment->warning_delay)) {
2623 $response->nbtodolate++;
2624 }
2625 }
2626 }
2627
2628 return $response;
2629 } else {
2630 dol_print_error($this->db);
2631 $this->error = $this->db->error();
2632 return -1;
2633 }
2634 }
2635
2642 public function hasDelay($option)
2643 {
2644 global $conf;
2645
2646 // Only valid expenses reports
2647 if ($option == 'toapprove' && $this->status != 2) {
2648 return false;
2649 }
2650 if ($option == 'topay' && $this->status != 5) {
2651 return false;
2652 }
2653
2654 $now = dol_now();
2655 if ($option == 'toapprove') {
2656 return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->approve->warning_delay);
2657 } else {
2658 return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->payment->warning_delay);
2659 }
2660 }
2661
2667 public function getVentilExportCompta()
2668 {
2669 $alreadydispatched = 0;
2670
2671 $type = 'expense_report';
2672
2673 $sql = " SELECT COUNT(ab.rowid) as nb FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab WHERE ab.doc_type='".$this->db->escape($type)."' AND ab.fk_doc = ".((int) $this->id);
2674 $resql = $this->db->query($sql);
2675 if ($resql) {
2676 $obj = $this->db->fetch_object($resql);
2677 if ($obj) {
2678 $alreadydispatched = $obj->nb;
2679 }
2680 } else {
2681 $this->error = $this->db->lasterror();
2682 return -1;
2683 }
2684
2685 if ($alreadydispatched) {
2686 return 1;
2687 }
2688 return 0;
2689 }
2690
2696 public function getSumPayments()
2697 {
2698 $table = 'payment_expensereport';
2699 $field = 'fk_expensereport';
2700
2701 $sql = 'SELECT sum(amount) as amount';
2702 $sql .= ' FROM '.MAIN_DB_PREFIX.$table;
2703 $sql .= " WHERE ".$field." = ".((int) $this->id);
2704
2705 dol_syslog(get_class($this)."::getSumPayments", LOG_DEBUG);
2706 $resql = $this->db->query($sql);
2707 if ($resql) {
2708 $obj = $this->db->fetch_object($resql);
2709 $this->db->free($resql);
2710 return (empty($obj->amount) ? 0 : $obj->amount);
2711 } else {
2712 $this->error = $this->db->lasterror();
2713 return -1;
2714 }
2715 }
2716
2725 public function computeTotalKm($fk_cat, $qty, $tva)
2726 {
2727 global $langs, $db, $conf;
2728
2729 $cumulYearQty = 0;
2730 $ranges = array();
2731 $coef = 0;
2732
2733
2734 if ($fk_cat < 0) {
2735 $this->error = $langs->trans('ErrorBadParameterCat');
2736 return -1;
2737 }
2738
2739 if ($qty <= 0) {
2740 $this->error = $langs->trans('ErrorBadParameterQty');
2741 return -1;
2742 }
2743
2744 $currentUser = new User($db);
2745 $currentUser->fetch($this->fk_user);
2746 $currentUser->getrights('expensereport');
2747 //Clean
2748 $qty = (float) price2num($qty);
2749
2750 $sql = " SELECT r.range_ik, t.ikoffset, t.coef";
2751 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport_ik t";
2752 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_exp_tax_range r ON r.rowid = t.fk_range";
2753 $sql .= " WHERE t.fk_c_exp_tax_cat = ".(int) $fk_cat;
2754 $sql .= " ORDER BY r.range_ik ASC";
2755
2756 dol_syslog("expenseReport::computeTotalkm sql=".$sql, LOG_DEBUG);
2757
2758 $result = $this->db->query($sql);
2759
2760 if ($result) {
2761 if ($conf->global->EXPENSEREPORT_CALCULATE_MILEAGE_EXPENSE_COEFFICIENT_ON_CURRENT_YEAR) {
2762 $arrayDate = dol_getdate(dol_now());
2763 $sql = " SELECT count(n.qty) as cumul FROM ".MAIN_DB_PREFIX."expensereport_det n";
2764 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expensereport e ON e.rowid = n.fk_expensereport";
2765 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_type_fees tf ON tf.id = n.fk_c_type_fees";
2766 $sql .= " WHERE e.fk_user_author = ".(int) $this->fk_user_author;
2767 $sql .= " AND YEAR(n.date) = ".(int) $arrayDate['year'];
2768 $sql .= " AND tf.code = 'EX_KME' ";
2769 $sql .= " AND e.fk_statut = ".(int) ExpenseReport::STATUS_VALIDATED;
2770
2771 $resql = $this->db->query($sql);
2772
2773 if ($resql) {
2774 $obj = $this->db->fetch_object($resql);
2775 $cumulYearQty = $obj->cumul;
2776 }
2777
2778 $qty += (float) $cumulYearQty;
2779 }
2780
2781 $num = $this->db->num_rows($result);
2782
2783 if ($num) {
2784 for ($i = 0; $i < $num; $i++) {
2785 $obj = $this->db->fetch_object($result);
2786
2787 $ranges[$i] = $obj;
2788 }
2789
2790
2791 for ($i = 0; $i < $num; $i++) {
2792 if ($i < ($num - 1)) {
2793 if ($qty > $ranges[$i]->range_ik && $qty < $ranges[$i + 1]->range_ik) {
2794 $coef = $ranges[$i]->coef;
2795 $offset = $ranges[$i]->ikoffset;
2796 }
2797 } else {
2798 if ($qty > $ranges[$i]->range_ik) {
2799 $coef = $ranges[$i]->coef;
2800 $offset = $ranges[$i]->ikoffset;
2801 }
2802 }
2803 }
2804 $total_ht = $coef;
2805 return $total_ht;
2806 } else {
2807 $this->error = $langs->trans('TaxUndefinedForThisCategory');
2808 return 0;
2809 }
2810 } else {
2811 $this->error = $this->db->error()." sql=".$sql;
2812
2813 return -1;
2814 }
2815 }
2816
2824 public function getKanbanView($option = '', $arraydata = null)
2825 {
2826 global $langs;
2827
2828 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
2829
2830 $return = '<div class="box-flex-item box-flex-grow-zero">';
2831 $return .= '<div class="info-box info-box-sm">';
2832 $return .= '<span class="info-box-icon bg-infobox-action">';
2833 $return .= img_picto('', $this->picto);
2834 $return .= '</span>';
2835 $return .= '<div class="info-box-content">';
2836 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
2837 if ($selected >= 0) {
2838 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
2839 }
2840 if (array_key_exists('userauthor', $arraydata)) {
2841 $return .= '<br><span class="info-box-label">'.$arraydata['userauthor']->getNomUrl(-1).'</span>';
2842 }
2843 if (property_exists($this, 'date_debut') && property_exists($this, 'date_fin')) {
2844 $return .= '<br><span class="info-box-label">'.dol_print_date($this->date_debut, 'day').'</span>';
2845 $return .= ' <span class="opacitymedium">'.$langs->trans("To").'</span> ';
2846 $return .= '<span class="info-box-label">'.dol_print_date($this->date_fin, 'day').'</span>';
2847 }
2848 if (method_exists($this, 'getLibStatut')) {
2849 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
2850 }
2851 $return .= '</div>';
2852 $return .= '</div>';
2853 $return .= '</div>';
2854 return $return;
2855 }
2856}
2857
2858
2863{
2867 public $db;
2868
2872 public $table_element = 'expensereport_det';
2873
2877 public $error = '';
2878
2882 public $rowid;
2883
2884 public $comments;
2885
2889 public $qty;
2890 public $value_unit;
2891 public $date;
2892
2896 public $dates;
2897
2901 public $fk_c_type_fees;
2902
2906 public $fk_c_exp_tax_cat;
2907
2911 public $fk_projet;
2912
2916 public $fk_expensereport;
2917
2918 public $type_fees_code;
2919 public $type_fees_libelle;
2920 public $type_fees_accountancy_code;
2921
2922 public $projet_ref;
2923 public $projet_title;
2924 public $rang;
2925
2926 public $vatrate;
2927 public $vat_src_code;
2928 public $tva_tx;
2929 public $localtax1_tx;
2930 public $localtax2_tx;
2931 public $localtax1_type;
2932 public $localtax2_type;
2933
2934 public $total_ht;
2935 public $total_tva;
2936 public $total_ttc;
2937 public $total_localtax1;
2938 public $total_localtax2;
2939
2940 // Multicurrency
2944 public $fk_multicurrency;
2945
2949 public $multicurrency_code;
2950 public $multicurrency_tx;
2951 public $multicurrency_total_ht;
2952 public $multicurrency_total_tva;
2953 public $multicurrency_total_ttc;
2954
2958 public $fk_ecm_files;
2959
2960 public $rule_warning_message;
2961
2962
2968 public function __construct($db)
2969 {
2970 $this->db = $db;
2971 }
2972
2979 public function fetch($rowid)
2980 {
2981 $sql = 'SELECT fde.rowid, fde.fk_expensereport, fde.fk_c_type_fees, fde.fk_c_exp_tax_cat, fde.fk_projet as fk_project, fde.date,';
2982 $sql .= ' fde.tva_tx as vatrate, fde.vat_src_code, fde.comments, fde.qty, fde.value_unit, fde.total_ht, fde.total_tva, fde.total_ttc, fde.fk_ecm_files,';
2983 $sql .= ' fde.localtax1_tx, fde.localtax2_tx, fde.localtax1_type, fde.localtax2_type, fde.total_localtax1, fde.total_localtax2, fde.rule_warning_message,';
2984 $sql .= ' ctf.code as type_fees_code, ctf.label as type_fees_libelle,';
2985 $sql .= ' pjt.rowid as projet_id, pjt.title as projet_title, pjt.ref as projet_ref';
2986 $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det as fde';
2987 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_type_fees as ctf ON fde.fk_c_type_fees=ctf.id'; // Sometimes type of expense report has been removed, so we use a left join here.
2988 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as pjt ON fde.fk_projet=pjt.rowid';
2989 $sql .= ' WHERE fde.rowid = '.((int) $rowid);
2990
2991 $result = $this->db->query($sql);
2992
2993 if ($result) {
2994 $objp = $this->db->fetch_object($result);
2995
2996 $this->rowid = $objp->rowid;
2997 $this->id = $objp->rowid;
2998 $this->ref = $objp->ref;
2999 $this->fk_expensereport = $objp->fk_expensereport;
3000 $this->comments = $objp->comments;
3001 $this->qty = $objp->qty;
3002 $this->date = $objp->date;
3003 $this->dates = $this->db->jdate($objp->date);
3004 $this->value_unit = $objp->value_unit;
3005 $this->fk_c_type_fees = $objp->fk_c_type_fees;
3006 $this->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
3007 $this->fk_projet = $objp->fk_project; // deprecated
3008 $this->fk_project = $objp->fk_project;
3009 $this->type_fees_code = $objp->type_fees_code;
3010 $this->type_fees_libelle = $objp->type_fees_libelle;
3011 $this->projet_ref = $objp->projet_ref;
3012 $this->projet_title = $objp->projet_title;
3013
3014 $this->vatrate = $objp->vatrate;
3015 $this->vat_src_code = $objp->vat_src_code;
3016 $this->localtax1_tx = $objp->localtax1_tx;
3017 $this->localtax2_tx = $objp->localtax2_tx;
3018 $this->localtax1_type = $objp->localtax1_type;
3019 $this->localtax2_type = $objp->localtax2_type;
3020
3021 $this->total_ht = $objp->total_ht;
3022 $this->total_tva = $objp->total_tva;
3023 $this->total_ttc = $objp->total_ttc;
3024 $this->total_localtax1 = $objp->total_localtax1;
3025 $this->total_localtax2 = $objp->total_localtax2;
3026
3027 $this->fk_ecm_files = $objp->fk_ecm_files;
3028
3029 $this->rule_warning_message = $objp->rule_warning_message;
3030
3031 $this->db->free($result);
3032
3033 return $this->id;
3034 } else {
3035 dol_print_error($this->db);
3036 return -1;
3037 }
3038 }
3039
3047 public function insert($notrigger = 0, $fromaddline = false)
3048 {
3049 global $user;
3050
3051 $error = 0;
3052
3053 dol_syslog("ExpenseReportLine::Insert", LOG_DEBUG);
3054
3055 // Clean parameters
3056 $this->comments = trim($this->comments);
3057 if (empty($this->value_unit)) {
3058 $this->value_unit = 0;
3059 }
3060 $this->qty = (float) price2num($this->qty);
3061 $this->vatrate = price2num($this->vatrate);
3062 if (empty($this->fk_c_exp_tax_cat)) {
3063 $this->fk_c_exp_tax_cat = 0;
3064 }
3065
3066 $this->db->begin();
3067
3068 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'expensereport_det';
3069 $sql .= ' (fk_expensereport, fk_c_type_fees, fk_projet,';
3070 $sql .= ' tva_tx, vat_src_code,';
3071 $sql .= ' localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3072 $sql .= ' comments, qty, value_unit,';
3073 $sql .= ' total_ht, total_tva, total_ttc,';
3074 $sql .= ' total_localtax1, total_localtax2,';
3075 $sql .= ' date, rule_warning_message, fk_c_exp_tax_cat, fk_ecm_files)';
3076 $sql .= " VALUES (".$this->db->escape($this->fk_expensereport).",";
3077 $sql .= " ".((int) $this->fk_c_type_fees).",";
3078 $sql .= " ".((int) (!empty($this->fk_project) && $this->fk_project > 0) ? $this->fk_project : ((!empty($this->fk_projet) && $this->fk_projet > 0) ? $this->fk_projet : 'null')).",";
3079 $sql .= " ".((float) $this->vatrate).",";
3080 $sql .= " '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."',";
3081 $sql .= " ".((float) price2num($this->localtax1_tx)).",";
3082 $sql .= " ".((float) price2num($this->localtax2_tx)).",";
3083 $sql .= " '".$this->db->escape($this->localtax1_type)."',";
3084 $sql .= " '".$this->db->escape($this->localtax2_type)."',";
3085 $sql .= " '".$this->db->escape($this->comments)."',";
3086 $sql .= " ".((float) $this->qty).",";
3087 $sql .= " ".((float) $this->value_unit).",";
3088 $sql .= " ".((float) price2num($this->total_ht)).",";
3089 $sql .= " ".((float) price2num($this->total_tva)).",";
3090 $sql .= " ".((float) price2num($this->total_ttc)).",";
3091 $sql .= " ".((float) price2num($this->total_localtax1)).",";
3092 $sql .= " ".((float) price2num($this->total_localtax2)).",";
3093 $sql .= " '".$this->db->idate($this->date)."',";
3094 $sql .= " ".(empty($this->rule_warning_message) ? 'null' : "'".$this->db->escape($this->rule_warning_message)."'").",";
3095 $sql .= " ".((int) $this->fk_c_exp_tax_cat).",";
3096 $sql .= " ".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
3097 $sql .= ")";
3098
3099 $resql = $this->db->query($sql);
3100 if ($resql) {
3101 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'expensereport_det');
3102
3103
3104 if (!$error && !$notrigger) {
3105 // Call triggers
3106 $result = $this->call_trigger('EXPENSE_REPORT_DET_CREATE', $user);
3107 if ($result < 0) {
3108 $error++;
3109 }
3110 // End call triggers
3111 }
3112
3113
3114 if (!$fromaddline) {
3115 $tmpparent = new ExpenseReport($this->db);
3116 $tmpparent->fetch($this->fk_expensereport);
3117 $result = $tmpparent->update_price(1);
3118 if ($result < 0) {
3119 $error++;
3120 $this->error = $tmpparent->error;
3121 $this->errors = $tmpparent->errors;
3122 }
3123 }
3124 } else {
3125 $error++;
3126 }
3127
3128 if (!$error) {
3129 $this->db->commit();
3130 return $this->id;
3131 } else {
3132 $this->error = $this->db->lasterror();
3133 dol_syslog("ExpenseReportLine::insert Error ".$this->error, LOG_ERR);
3134 $this->db->rollback();
3135 return -2;
3136 }
3137 }
3138
3147 public function getExpAmount(ExpenseReportRule $rule, $fk_user, $mode = 'day')
3148 {
3149 $amount = 0;
3150
3151 $sql = 'SELECT SUM(d.total_ttc) as total_amount';
3152 $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det d';
3153 $sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'expensereport e ON (d.fk_expensereport = e.rowid)';
3154 $sql .= ' WHERE e.fk_user_author = '.((int) $fk_user);
3155 if (!empty($this->id)) {
3156 $sql .= ' AND d.rowid <> '.((int) $this->id);
3157 }
3158 $sql .= ' AND d.fk_c_type_fees = '.((int) $rule->fk_c_type_fees);
3159 if ($mode == 'day' || $mode == 'EX_DAY') {
3160 $sql .= " AND d.date = '".dol_print_date($this->date, '%Y-%m-%d')."'";
3161 } elseif ($mode == 'mon' || $mode == 'EX_MON') {
3162 $sql .= " AND DATE_FORMAT(d.date, '%Y-%m') = '".dol_print_date($this->date, '%Y-%m')."'"; // @todo DATE_FORMAT is forbidden
3163 } elseif ($mode == 'year' || $mode == 'EX_YEA') {
3164 $sql .= " AND DATE_FORMAT(d.date, '%Y') = '".dol_print_date($this->date, '%Y')."'"; // @todo DATE_FORMAT is forbidden
3165 }
3166
3167 dol_syslog('ExpenseReportLine::getExpAmount');
3168
3169 $resql = $this->db->query($sql);
3170 if ($resql) {
3171 $num = $this->db->num_rows($resql);
3172 if ($num > 0) {
3173 $obj = $this->db->fetch_object($resql);
3174 $amount = (float) $obj->total_amount;
3175 }
3176 } else {
3177 dol_print_error($this->db);
3178 }
3179
3180 return $amount + $this->total_ttc;
3181 }
3182
3189 public function update(User $user)
3190 {
3191 global $langs;
3192
3193 $error = 0;
3194
3195 // Clean parameters
3196 $this->comments = trim($this->comments);
3197 $this->vatrate = price2num($this->vatrate);
3198 $this->value_unit = price2num($this->value_unit);
3199 if (empty($this->fk_c_exp_tax_cat)) {
3200 $this->fk_c_exp_tax_cat = 0;
3201 }
3202
3203 $this->db->begin();
3204
3205 // Update line in database
3206 $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport_det SET";
3207 $sql .= " comments='".$this->db->escape($this->comments)."'";
3208 $sql .= ", value_unit = ".((float) $this->value_unit);
3209 $sql .= ", qty=".((float) $this->qty);
3210 $sql .= ", date='".$this->db->idate($this->date)."'";
3211 $sql .= ", total_ht=".((float) price2num($this->total_ht, 'MT'));
3212 $sql .= ", total_tva=".((float) price2num($this->total_tva, 'MT'));
3213 $sql .= ", total_ttc=".((float) price2num($this->total_ttc, 'MT'));
3214 $sql .= ", total_localtax1=".((float) price2num($this->total_localtax1, 'MT'));
3215 $sql .= ", total_localtax2=".((float) price2num($this->total_localtax2, 'MT'));
3216 $sql .= ", tva_tx=".((float) $this->vatrate);
3217 $sql .= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
3218 $sql .= ", localtax1_tx=".((float) $this->localtax1_tx);
3219 $sql .= ", localtax2_tx=".((float) $this->localtax2_tx);
3220 $sql .= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
3221 $sql .= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
3222 $sql .= ", rule_warning_message='".$this->db->escape($this->rule_warning_message)."'";
3223 $sql .= ", fk_c_exp_tax_cat=".$this->db->escape($this->fk_c_exp_tax_cat);
3224 $sql .= ", fk_ecm_files=".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
3225 if ($this->fk_c_type_fees) {
3226 $sql .= ", fk_c_type_fees = ".((int) $this->fk_c_type_fees);
3227 } else {
3228 $sql .= ", fk_c_type_fees=null";
3229 }
3230 if ($this->fk_project > 0) {
3231 $sql .= ", fk_projet=".((int) $this->fk_project);
3232 } else {
3233 $sql .= ", fk_projet=null";
3234 }
3235 $sql .= " WHERE rowid = ".((int) ($this->rowid ? $this->rowid : $this->id));
3236
3237 dol_syslog("ExpenseReportLine::update");
3238
3239 $resql = $this->db->query($sql);
3240 if ($resql) {
3241 $tmpparent = new ExpenseReport($this->db);
3242 $result = $tmpparent->fetch($this->fk_expensereport);
3243 if ($result > 0) {
3244 $result = $tmpparent->update_price(1);
3245 if ($result < 0) {
3246 $error++;
3247 $this->error = $tmpparent->error;
3248 $this->errors = $tmpparent->errors;
3249 }
3250 } else {
3251 $error++;
3252 $this->error = $tmpparent->error;
3253 $this->errors = $tmpparent->errors;
3254 }
3255 } else {
3256 $error++;
3257 dol_print_error($this->db);
3258 }
3259
3260 if (!$error) {
3261 $this->db->commit();
3262 return 1;
3263 } else {
3264 $this->error = $this->db->lasterror();
3265 dol_syslog("ExpenseReportLine::update Error ".$this->error, LOG_ERR);
3266 $this->db->rollback();
3267 return -2;
3268 }
3269 }
3270
3271 // ajouter ici comput_ ...
3272}
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition security.php:626
$object ref
Definition info.php:79
Parent class of all other business classes (invoices, contracts, proposals, orders,...
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...
deleteEcmFiles($mode=0)
Delete related files of object in database.
update_price($exclspec=0, $roundingadjust='auto', $nodatabaseupdate=0, $seller=null)
Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid=0, $f_user=null, $notrigger=0)
Delete all links between an object $this.
setErrorsFromObject($object)
setErrorsFromObject
deleteExtraFields()
Delete all extra fields values for the current object.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
delete_linked_contact($source='', $code='')
Delete all links between an object $this and all its contacts in llx_element_contact.
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 Trips and Expenses.
setPaid($id, $fuser, $notrigger=0)
Classify the expense report as paid.
loadStateBoard()
Load the indicators this->nb for the state board.
__construct($db)
Constructor.
checkRules($type=0, $seller='')
Check constraint of rules and update price if needed.
updateline($rowid, $type_fees_id, $projet_id, $vatrate, $comments, $qty, $value_unit, $date, $expensereport_id, $fk_c_exp_tax_cat=0, $fk_ecm_files=0, $notrigger=0)
Update an expense report line.
getNextNumRef()
Return next reference of expense report not already used.
createFromClone(User $user, $fk_user_author)
Load an object from its id and create a new one in database.
addline($qty=0, $up=0, $fk_c_type_fees=0, $vatrate=0, $date='', $comments='', $fk_project=0, $fk_c_exp_tax_cat=0, $type=0, $fk_ecm_files=0)
Add expense report line.
const STATUS_DRAFT
Draft status.
computeTotalKm($fk_cat, $qty, $tva)
Compute the cost of the kilometers expense based on the number of kilometers and the vehicle category...
offsetAlreadyGiven()
If the sql find any rows then the ikoffset is already given (ikoffset is applied at the first expense...
listOfTypes($active=1)
List of types.
const STATUS_APPROVED
Classified approved.
set_save_from_refuse($fuser)
set_save_from_refuse
periode_existe($fuser, $date_debut, $date_fin)
periode_existe
setValidate($fuser, $notrigger=0)
Set to status validate.
getSumPayments()
Return amount of payments already done.
getLibStatut($mode=0)
Returns the label status.
set_cancel($fuser, $detail, $notrigger=0)
set_cancel
getNomUrl($withpicto=0, $option='', $max=0, $short=0, $moretitle='', $notooltip=0, $save_lastsearch_value=-1)
Return clicable name (with picto eventually)
set_unpaid($fuser, $notrigger=0)
set_unpaid
info($id)
Load information on object.
getTooltipContentArray($params)
getTooltipContentArray
hasDelay($option)
Return if an expense report is late or not.
applyOffset($type=0, $seller='')
Method to apply the offset if needed.
const STATUS_CANCELED
Classified canceled.
const STATUS_CLOSED
Classified paid.
const STATUS_REFUSED
Classified refused.
deleteLine($rowid, $fuser='', $notrigger=0)
deleteline
setDeny($fuser, $details, $notrigger=0)
setDeny
getVentilExportCompta()
Return if object was dispatched into bookkeeping.
getKanbanView($option='', $arraydata=null)
Return clickable link of object (with optional picto)
update($user, $notrigger=0, $userofexpensereport=null)
update
const STATUS_VALIDATED
Validated (need to be paid)
create($user, $notrigger=0)
Create object in database.
load_board($user, $option='topay')
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
set_paid($id, $fuser, $notrigger=0)
Classify the expense report as paid.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
initAsSpecimen()
Initialise an instance with random values.
fetch_users_approver_expensereport()
Return list of people with permission to validate expense reports.
setApproved($fuser, $notrigger=0)
Set status to approved.
LibStatut($status, $mode=0)
Returns the label of a status.
setUnpaid($fuser, $notrigger=0)
set_unpaid
fetch_line_by_project($projectid, $user)
fetch_line_by_project
update_totaux_add($ligne_total_ht, $ligne_total_tva)
Update total of an expense report when you add a line.
Class to manage inventories.
Class of expense report details lines.
fetch($rowid)
Fetch record for expense report detailed line.
update(User $user)
Update line.
getExpAmount(ExpenseReportRule $rule, $fk_user, $mode='day')
Function to get total amount in expense reports for a same rule.
insert($notrigger=0, $fromaddline=false)
Insert a line of expense report.
__construct($db)
Constructor.
Class to manage inventories.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
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($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:63
dol_delete_preview($object)
Delete all preview files linked to object instance.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
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_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
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_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
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:88
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall TAKEPOS_SHOW_SUBPRICE right right right takeposterminal SELECT e rowid
Definition invoice.php:1929