dolibarr 20.0.0
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, $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, $vatrate, -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
2242 //var_dump($vatrate);var_dump($localtaxes_type);var_dump($tmp);exit;
2243 // calcul total of line
2244 //$total_ttc = price2num($qty*$value_unit, 'MT');
2245
2246 $tx_tva = 1 + (float) $vatrate / 100;
2247
2248 $this->line = new ExpenseReportLine($this->db);
2249 $this->line->comments = $comments;
2250 $this->line->qty = $qty;
2251 $this->line->value_unit = $value_unit;
2252 $this->line->date = $date;
2253
2254 $this->line->fk_expensereport = $expensereport_id;
2255 $this->line->fk_c_type_fees = $type_fees_id;
2256 $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
2257 $this->line->fk_projet = $projet_id; // deprecated
2258 $this->line->fk_project = $projet_id;
2259
2260 $this->line->vat_src_code = $vat_src_code;
2261 $this->line->vatrate = price2num($vatrate);
2262 $this->line->localtax1_tx = $localtaxes_type[1];
2263 $this->line->localtax2_tx = $localtaxes_type[3];
2264 $this->line->localtax1_type = $localtaxes_type[0];
2265 $this->line->localtax2_type = $localtaxes_type[2];
2266
2267 $this->line->total_ttc = $tmp[2];
2268 $this->line->total_ht = $tmp[0];
2269 $this->line->total_tva = $tmp[1];
2270 $this->line->total_localtax1 = $tmp[9];
2271 $this->line->total_localtax2 = $tmp[10];
2272
2273 $this->line->fk_ecm_files = $fk_ecm_files;
2274
2275 $this->line->id = ((int) $rowid);
2276
2277 // Select des infos sur le type fees
2278 $sql = "SELECT c.code as code_type_fees, c.label as label_type_fees";
2279 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
2280 $sql .= " WHERE c.id = ".((int) $type_fees_id);
2281 $resql = $this->db->query($sql);
2282 if ($resql) {
2283 $objp_fees = $this->db->fetch_object($resql);
2284 $this->line->type_fees_code = $objp_fees->code_type_fees;
2285 $this->line->type_fees_libelle = $objp_fees->label_type_fees;
2286 $this->db->free($resql);
2287 }
2288
2289 // Select des information du projet
2290 $sql = "SELECT p.ref as ref_projet, p.title as title_projet";
2291 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
2292 $sql .= " WHERE p.rowid = ".((int) $projet_id);
2293 $resql = $this->db->query($sql);
2294 if ($resql) {
2295 $objp_projet = $this->db->fetch_object($resql);
2296 $this->line->projet_ref = $objp_projet->ref_projet;
2297 $this->line->projet_title = $objp_projet->title_projet;
2298 $this->db->free($resql);
2299 }
2300
2301 $this->applyOffset();
2302 $this->checkRules();
2303
2304 $result = $this->line->update($user);
2305 if ($result < 0) {
2306 $error++;
2307 }
2308
2309 if (!$error && !$notrigger) {
2310 // Call triggers
2311 $result = $this->call_trigger('EXPENSE_REPORT_DET_MODIFY', $user);
2312 if ($result < 0) {
2313 $error++;
2314 }
2315 // End call triggers
2316 }
2317
2318 if (!$error) {
2319 $this->db->commit();
2320 return 1;
2321 } else {
2322 $this->error = $this->line->error;
2323 $this->errors = $this->line->errors;
2324 $this->db->rollback();
2325 return -2;
2326 }
2327 }
2328
2329 return 0;
2330 }
2331
2340 public function deleteLine($rowid, $fuser = '', $notrigger = 0)
2341 {
2342 $error = 0;
2343
2344 $this->db->begin();
2345
2346 if (!$notrigger) {
2347 // Call triggers
2348 $result = $this->call_trigger('EXPENSE_REPORT_DET_DELETE', $fuser);
2349 if ($result < 0) {
2350 $error++;
2351 }
2352 // End call triggers
2353 }
2354
2355 $sql = ' DELETE FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2356 $sql .= ' WHERE rowid = '.((int) $rowid);
2357
2358 dol_syslog(get_class($this)."::deleteline sql=".$sql);
2359 $result = $this->db->query($sql);
2360
2361 if (!$result || $error > 0) {
2362 $this->error = $this->db->error();
2363 dol_syslog(get_class($this)."::deleteline Error ".$this->error, LOG_ERR);
2364 $this->db->rollback();
2365 return -1;
2366 }
2367
2368 $this->update_price(1);
2369
2370 $this->db->commit();
2371
2372 return 1;
2373 }
2374
2375 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2384 public function periode_existe($fuser, $date_debut, $date_fin)
2385 {
2386 global $conf;
2387
2388 // phpcs:enable
2389 $sql = "SELECT rowid, date_debut, date_fin";
2390 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
2391 $sql .= " WHERE entity = ".((int) $conf->entity); // not shared, only for the current entity
2392 $sql .= " AND fk_user_author = ".((int) $fuser->id);
2393
2394 dol_syslog(get_class($this)."::periode_existe sql=".$sql);
2395 $result = $this->db->query($sql);
2396 if ($result) {
2397 $num_rows = $this->db->num_rows($result);
2398 $i = 0;
2399
2400 if ($num_rows > 0) {
2401 $date_d_form = $date_debut;
2402 $date_f_form = $date_fin;
2403
2404 while ($i < $num_rows) {
2405 $objp = $this->db->fetch_object($result);
2406
2407 $date_d_req = $this->db->jdate($objp->date_debut); // 3
2408 $date_f_req = $this->db->jdate($objp->date_fin); // 4
2409
2410 if (!($date_f_form < $date_d_req || $date_d_form > $date_f_req)) {
2411 return $objp->rowid;
2412 }
2413
2414 $i++;
2415 }
2416
2417 return 0;
2418 } else {
2419 return 0;
2420 }
2421 } else {
2422 $this->error = $this->db->lasterror();
2423 dol_syslog(get_class($this)."::periode_existe Error ".$this->error, LOG_ERR);
2424 return -1;
2425 }
2426 }
2427
2428
2429 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2437 {
2438 // phpcs:enable
2439 $users_validator = array();
2440
2441 $sql = "SELECT DISTINCT ur.fk_user";
2442 $sql .= " FROM ".MAIN_DB_PREFIX."user_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2443 $sql .= " WHERE ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2444 $sql .= " UNION";
2445 $sql .= " SELECT DISTINCT ugu.fk_user";
2446 $sql .= " FROM ".MAIN_DB_PREFIX."usergroup_user as ugu, ".MAIN_DB_PREFIX."usergroup_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2447 $sql .= " WHERE ugu.fk_usergroup = ur.fk_usergroup AND ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2448 //print $sql;
2449
2450 dol_syslog(get_class($this)."::fetch_users_approver_expensereport sql=".$sql);
2451 $result = $this->db->query($sql);
2452 if ($result) {
2453 $num_rows = $this->db->num_rows($result);
2454 $i = 0;
2455 while ($i < $num_rows) {
2456 $objp = $this->db->fetch_object($result);
2457 array_push($users_validator, $objp->fk_user);
2458 $i++;
2459 }
2460 return $users_validator;
2461 } else {
2462 $this->error = $this->db->lasterror();
2463 dol_syslog(get_class($this)."::fetch_users_approver_expensereport Error ".$this->error, LOG_ERR);
2464 return -1;
2465 }
2466 }
2467
2479 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
2480 {
2481 $outputlangs->load("trips");
2482
2483 if (!dol_strlen($modele)) {
2484 if (!empty($this->model_pdf)) {
2485 $modele = $this->model_pdf;
2486 } elseif (getDolGlobalString('EXPENSEREPORT_ADDON_PDF')) {
2487 $modele = getDolGlobalString('EXPENSEREPORT_ADDON_PDF');
2488 }
2489 }
2490
2491 if (!empty($modele)) {
2492 $modelpath = "core/modules/expensereport/doc/";
2493
2494 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2495 } else {
2496 return 0;
2497 }
2498 }
2499
2506 public function listOfTypes($active = 1)
2507 {
2508 global $langs;
2509 $ret = array();
2510 $sql = "SELECT id, code, label";
2511 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees";
2512 $sql .= " WHERE active = ".((int) $active);
2513 dol_syslog(get_class($this)."::listOfTypes", LOG_DEBUG);
2514 $result = $this->db->query($sql);
2515 if ($result) {
2516 $num = $this->db->num_rows($result);
2517 $i = 0;
2518 while ($i < $num) {
2519 $obj = $this->db->fetch_object($result);
2520 $ret[$obj->code] = (($langs->transnoentitiesnoconv($obj->code) != $obj->code) ? $langs->transnoentitiesnoconv($obj->code) : $obj->label);
2521 $i++;
2522 }
2523 } else {
2524 dol_print_error($this->db);
2525 }
2526 return $ret;
2527 }
2528
2534 public function loadStateBoard()
2535 {
2536 global $user;
2537
2538 $this->nb = array();
2539
2540 $sql = "SELECT count(ex.rowid) as nb";
2541 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2542 $sql .= " WHERE ex.fk_statut > 0";
2543 $sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2544 if (!$user->hasRight('expensereport', 'readall')) {
2545 $userchildids = $user->getAllChildIds(1);
2546 $sql .= " AND (ex.fk_user_author IN (".$this->db->sanitize(implode(',', $userchildids)).")";
2547 $sql .= " OR ex.fk_user_validator IN (".$this->db->sanitize(implode(',', $userchildids))."))";
2548 }
2549
2550 $resql = $this->db->query($sql);
2551 if ($resql) {
2552 while ($obj = $this->db->fetch_object($resql)) {
2553 $this->nb["expensereports"] = $obj->nb;
2554 }
2555 $this->db->free($resql);
2556 return 1;
2557 } else {
2558 dol_print_error($this->db);
2559 $this->error = $this->db->error();
2560 return -1;
2561 }
2562 }
2563
2564 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2572 public function load_board($user, $option = 'topay')
2573 {
2574 // phpcs:enable
2575 global $conf, $langs;
2576
2577 if ($user->socid) {
2578 return -1; // protection pour eviter appel par utilisateur externe
2579 }
2580
2581 $now = dol_now();
2582
2583 $sql = "SELECT ex.rowid, ex.date_valid";
2584 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2585 if ($option == 'toapprove') {
2586 $sql .= " WHERE ex.fk_statut = ".self::STATUS_VALIDATED;
2587 } else {
2588 $sql .= " WHERE ex.fk_statut = ".self::STATUS_APPROVED;
2589 }
2590 $sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2591 if (!$user->hasRight('expensereport', 'readall')) {
2592 $userchildids = $user->getAllChildIds(1);
2593 $sql .= " AND (ex.fk_user_author IN (".$this->db->sanitize(implode(',', $userchildids)).")";
2594 $sql .= " OR ex.fk_user_validator IN (".$this->db->sanitize(implode(',', $userchildids))."))";
2595 }
2596
2597 $resql = $this->db->query($sql);
2598 if ($resql) {
2599 $langs->load("trips");
2600
2601 $response = new WorkboardResponse();
2602 if ($option == 'toapprove') {
2603 $response->warning_delay = $conf->expensereport->approve->warning_delay / 60 / 60 / 24;
2604 $response->label = $langs->trans("ExpenseReportsToApprove");
2605 $response->labelShort = $langs->trans("ToApprove");
2606 $response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_VALIDATED;
2607 } else {
2608 $response->warning_delay = $conf->expensereport->payment->warning_delay / 60 / 60 / 24;
2609 $response->label = $langs->trans("ExpenseReportsToPay");
2610 $response->labelShort = $langs->trans("StatusToPay");
2611 $response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_APPROVED;
2612 }
2613 $response->img = img_object('', "trip");
2614
2615 while ($obj = $this->db->fetch_object($resql)) {
2616 $response->nbtodo++;
2617
2618 if ($option == 'toapprove') {
2619 if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->approve->warning_delay)) {
2620 $response->nbtodolate++;
2621 }
2622 } else {
2623 if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->payment->warning_delay)) {
2624 $response->nbtodolate++;
2625 }
2626 }
2627 }
2628
2629 return $response;
2630 } else {
2631 dol_print_error($this->db);
2632 $this->error = $this->db->error();
2633 return -1;
2634 }
2635 }
2636
2643 public function hasDelay($option)
2644 {
2645 global $conf;
2646
2647 // Only valid expenses reports
2648 if ($option == 'toapprove' && $this->status != 2) {
2649 return false;
2650 }
2651 if ($option == 'topay' && $this->status != 5) {
2652 return false;
2653 }
2654
2655 $now = dol_now();
2656 if ($option == 'toapprove') {
2657 return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->approve->warning_delay);
2658 } else {
2659 return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->payment->warning_delay);
2660 }
2661 }
2662
2668 public function getVentilExportCompta()
2669 {
2670 $alreadydispatched = 0;
2671
2672 $type = 'expense_report';
2673
2674 $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);
2675 $resql = $this->db->query($sql);
2676 if ($resql) {
2677 $obj = $this->db->fetch_object($resql);
2678 if ($obj) {
2679 $alreadydispatched = $obj->nb;
2680 }
2681 } else {
2682 $this->error = $this->db->lasterror();
2683 return -1;
2684 }
2685
2686 if ($alreadydispatched) {
2687 return 1;
2688 }
2689 return 0;
2690 }
2691
2697 public function getSumPayments()
2698 {
2699 $table = 'payment_expensereport';
2700 $field = 'fk_expensereport';
2701
2702 $sql = 'SELECT sum(amount) as amount';
2703 $sql .= ' FROM '.MAIN_DB_PREFIX.$table;
2704 $sql .= " WHERE ".$field." = ".((int) $this->id);
2705
2706 dol_syslog(get_class($this)."::getSumPayments", LOG_DEBUG);
2707 $resql = $this->db->query($sql);
2708 if ($resql) {
2709 $obj = $this->db->fetch_object($resql);
2710 $this->db->free($resql);
2711 return (empty($obj->amount) ? 0 : $obj->amount);
2712 } else {
2713 $this->error = $this->db->lasterror();
2714 return -1;
2715 }
2716 }
2717
2726 public function computeTotalKm($fk_cat, $qty, $tva)
2727 {
2728 global $langs, $db, $conf;
2729
2730 $cumulYearQty = 0;
2731 $ranges = array();
2732 $coef = 0;
2733
2734
2735 if ($fk_cat < 0) {
2736 $this->error = $langs->trans('ErrorBadParameterCat');
2737 return -1;
2738 }
2739
2740 if ($qty <= 0) {
2741 $this->error = $langs->trans('ErrorBadParameterQty');
2742 return -1;
2743 }
2744
2745 $currentUser = new User($db);
2746 $currentUser->fetch($this->fk_user);
2747 $currentUser->getrights('expensereport');
2748 //Clean
2749 $qty = (float) price2num($qty);
2750
2751 $sql = " SELECT r.range_ik, t.ikoffset, t.coef";
2752 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport_ik t";
2753 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_exp_tax_range r ON r.rowid = t.fk_range";
2754 $sql .= " WHERE t.fk_c_exp_tax_cat = ".(int) $fk_cat;
2755 $sql .= " ORDER BY r.range_ik ASC";
2756
2757 dol_syslog("expenseReport::computeTotalkm sql=".$sql, LOG_DEBUG);
2758
2759 $result = $this->db->query($sql);
2760
2761 if ($result) {
2762 if ($conf->global->EXPENSEREPORT_CALCULATE_MILEAGE_EXPENSE_COEFFICIENT_ON_CURRENT_YEAR) {
2763 $arrayDate = dol_getdate(dol_now());
2764 $sql = " SELECT count(n.qty) as cumul FROM ".MAIN_DB_PREFIX."expensereport_det n";
2765 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expensereport e ON e.rowid = n.fk_expensereport";
2766 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_type_fees tf ON tf.id = n.fk_c_type_fees";
2767 $sql .= " WHERE e.fk_user_author = ".(int) $this->fk_user_author;
2768 $sql .= " AND YEAR(n.date) = ".(int) $arrayDate['year'];
2769 $sql .= " AND tf.code = 'EX_KME' ";
2770 $sql .= " AND e.fk_statut = ".(int) ExpenseReport::STATUS_VALIDATED;
2771
2772 $resql = $this->db->query($sql);
2773
2774 if ($resql) {
2775 $obj = $this->db->fetch_object($resql);
2776 $cumulYearQty = $obj->cumul;
2777 }
2778
2779 $qty += (float) $cumulYearQty;
2780 }
2781
2782 $num = $this->db->num_rows($result);
2783
2784 if ($num) {
2785 for ($i = 0; $i < $num; $i++) {
2786 $obj = $this->db->fetch_object($result);
2787
2788 $ranges[$i] = $obj;
2789 }
2790
2791
2792 for ($i = 0; $i < $num; $i++) {
2793 if ($i < ($num - 1)) {
2794 if ($qty > $ranges[$i]->range_ik && $qty < $ranges[$i + 1]->range_ik) {
2795 $coef = $ranges[$i]->coef;
2796 $offset = $ranges[$i]->ikoffset;
2797 }
2798 } else {
2799 if ($qty > $ranges[$i]->range_ik) {
2800 $coef = $ranges[$i]->coef;
2801 $offset = $ranges[$i]->ikoffset;
2802 }
2803 }
2804 }
2805 $total_ht = $coef;
2806 return $total_ht;
2807 } else {
2808 $this->error = $langs->trans('TaxUndefinedForThisCategory');
2809 return 0;
2810 }
2811 } else {
2812 $this->error = $this->db->error()." sql=".$sql;
2813
2814 return -1;
2815 }
2816 }
2817
2825 public function getKanbanView($option = '', $arraydata = null)
2826 {
2827 global $langs;
2828
2829 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
2830
2831 $return = '<div class="box-flex-item box-flex-grow-zero">';
2832 $return .= '<div class="info-box info-box-sm">';
2833 $return .= '<span class="info-box-icon bg-infobox-action">';
2834 $return .= img_picto('', $this->picto);
2835 $return .= '</span>';
2836 $return .= '<div class="info-box-content">';
2837 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
2838 if ($selected >= 0) {
2839 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
2840 }
2841 if (array_key_exists('userauthor', $arraydata)) {
2842 $return .= '<br><span class="info-box-label">'.$arraydata['userauthor']->getNomUrl(-1).'</span>';
2843 }
2844 if (property_exists($this, 'date_debut') && property_exists($this, 'date_fin')) {
2845 $return .= '<br><span class="info-box-label">'.dol_print_date($this->date_debut, 'day').'</span>';
2846 $return .= ' <span class="opacitymedium">'.$langs->trans("To").'</span> ';
2847 $return .= '<span class="info-box-label">'.dol_print_date($this->date_fin, 'day').'</span>';
2848 }
2849 if (method_exists($this, 'getLibStatut')) {
2850 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
2851 }
2852 $return .= '</div>';
2853 $return .= '</div>';
2854 $return .= '</div>';
2855 return $return;
2856 }
2857}
2858
2859
2864{
2868 public $db;
2869
2873 public $table_element = 'expensereport_det';
2874
2878 public $error = '';
2879
2883 public $rowid;
2884
2885 public $comments;
2886
2890 public $qty;
2891 public $value_unit;
2892 public $date;
2893
2897 public $dates;
2898
2902 public $fk_c_type_fees;
2903
2907 public $fk_c_exp_tax_cat;
2908
2912 public $fk_projet;
2913
2917 public $fk_expensereport;
2918
2919 public $type_fees_code;
2920 public $type_fees_libelle;
2921 public $type_fees_accountancy_code;
2922
2923 public $projet_ref;
2924 public $projet_title;
2925 public $rang;
2926
2927 public $vatrate;
2928 public $vat_src_code;
2929 public $tva_tx;
2930 public $localtax1_tx;
2931 public $localtax2_tx;
2932 public $localtax1_type;
2933 public $localtax2_type;
2934
2935 public $total_ht;
2936 public $total_tva;
2937 public $total_ttc;
2938 public $total_localtax1;
2939 public $total_localtax2;
2940
2941 // Multicurrency
2945 public $fk_multicurrency;
2946
2950 public $multicurrency_code;
2951 public $multicurrency_tx;
2952 public $multicurrency_total_ht;
2953 public $multicurrency_total_tva;
2954 public $multicurrency_total_ttc;
2955
2959 public $fk_ecm_files;
2960
2961 public $rule_warning_message;
2962
2963
2969 public function __construct($db)
2970 {
2971 $this->db = $db;
2972 }
2973
2980 public function fetch($rowid)
2981 {
2982 $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,';
2983 $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,';
2984 $sql .= ' fde.localtax1_tx, fde.localtax2_tx, fde.localtax1_type, fde.localtax2_type, fde.total_localtax1, fde.total_localtax2, fde.rule_warning_message,';
2985 $sql .= ' ctf.code as type_fees_code, ctf.label as type_fees_libelle,';
2986 $sql .= ' pjt.rowid as projet_id, pjt.title as projet_title, pjt.ref as projet_ref';
2987 $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det as fde';
2988 $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.
2989 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as pjt ON fde.fk_projet=pjt.rowid';
2990 $sql .= ' WHERE fde.rowid = '.((int) $rowid);
2991
2992 $result = $this->db->query($sql);
2993
2994 if ($result) {
2995 $objp = $this->db->fetch_object($result);
2996
2997 $this->rowid = $objp->rowid;
2998 $this->id = $objp->rowid;
2999 $this->ref = $objp->ref;
3000 $this->fk_expensereport = $objp->fk_expensereport;
3001 $this->comments = $objp->comments;
3002 $this->qty = $objp->qty;
3003 $this->date = $objp->date;
3004 $this->dates = $this->db->jdate($objp->date);
3005 $this->value_unit = $objp->value_unit;
3006 $this->fk_c_type_fees = $objp->fk_c_type_fees;
3007 $this->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
3008 $this->fk_projet = $objp->fk_project; // deprecated
3009 $this->fk_project = $objp->fk_project;
3010 $this->type_fees_code = $objp->type_fees_code;
3011 $this->type_fees_libelle = $objp->type_fees_libelle;
3012 $this->projet_ref = $objp->projet_ref;
3013 $this->projet_title = $objp->projet_title;
3014
3015 $this->vatrate = $objp->vatrate;
3016 $this->vat_src_code = $objp->vat_src_code;
3017 $this->localtax1_tx = $objp->localtax1_tx;
3018 $this->localtax2_tx = $objp->localtax2_tx;
3019 $this->localtax1_type = $objp->localtax1_type;
3020 $this->localtax2_type = $objp->localtax2_type;
3021
3022 $this->total_ht = $objp->total_ht;
3023 $this->total_tva = $objp->total_tva;
3024 $this->total_ttc = $objp->total_ttc;
3025 $this->total_localtax1 = $objp->total_localtax1;
3026 $this->total_localtax2 = $objp->total_localtax2;
3027
3028 $this->fk_ecm_files = $objp->fk_ecm_files;
3029
3030 $this->rule_warning_message = $objp->rule_warning_message;
3031
3032 $this->db->free($result);
3033
3034 return $this->id;
3035 } else {
3036 dol_print_error($this->db);
3037 return -1;
3038 }
3039 }
3040
3048 public function insert($notrigger = 0, $fromaddline = false)
3049 {
3050 global $user;
3051
3052 $error = 0;
3053
3054 dol_syslog("ExpenseReportLine::Insert", LOG_DEBUG);
3055
3056 // Clean parameters
3057 $this->comments = trim($this->comments);
3058 if (empty($this->value_unit)) {
3059 $this->value_unit = 0;
3060 }
3061 $this->qty = (float) price2num($this->qty);
3062 $this->vatrate = price2num($this->vatrate);
3063 if (empty($this->fk_c_exp_tax_cat)) {
3064 $this->fk_c_exp_tax_cat = 0;
3065 }
3066
3067 $this->db->begin();
3068
3069 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'expensereport_det';
3070 $sql .= ' (fk_expensereport, fk_c_type_fees, fk_projet,';
3071 $sql .= ' tva_tx, vat_src_code,';
3072 $sql .= ' localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3073 $sql .= ' comments, qty, value_unit,';
3074 $sql .= ' total_ht, total_tva, total_ttc,';
3075 $sql .= ' total_localtax1, total_localtax2,';
3076 $sql .= ' date, rule_warning_message, fk_c_exp_tax_cat, fk_ecm_files)';
3077 $sql .= " VALUES (".$this->db->escape($this->fk_expensereport).",";
3078 $sql .= " ".((int) $this->fk_c_type_fees).",";
3079 $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')).",";
3080 $sql .= " ".((float) $this->vatrate).",";
3081 $sql .= " '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."',";
3082 $sql .= " ".((float) price2num($this->localtax1_tx)).",";
3083 $sql .= " ".((float) price2num($this->localtax2_tx)).",";
3084 $sql .= " '".$this->db->escape($this->localtax1_type)."',";
3085 $sql .= " '".$this->db->escape($this->localtax2_type)."',";
3086 $sql .= " '".$this->db->escape($this->comments)."',";
3087 $sql .= " ".((float) $this->qty).",";
3088 $sql .= " ".((float) $this->value_unit).",";
3089 $sql .= " ".((float) price2num($this->total_ht)).",";
3090 $sql .= " ".((float) price2num($this->total_tva)).",";
3091 $sql .= " ".((float) price2num($this->total_ttc)).",";
3092 $sql .= " ".((float) price2num($this->total_localtax1)).",";
3093 $sql .= " ".((float) price2num($this->total_localtax2)).",";
3094 $sql .= " '".$this->db->idate($this->date)."',";
3095 $sql .= " ".(empty($this->rule_warning_message) ? 'null' : "'".$this->db->escape($this->rule_warning_message)."'").",";
3096 $sql .= " ".((int) $this->fk_c_exp_tax_cat).",";
3097 $sql .= " ".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
3098 $sql .= ")";
3099
3100 $resql = $this->db->query($sql);
3101 if ($resql) {
3102 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'expensereport_det');
3103
3104
3105 if (!$error && !$notrigger) {
3106 // Call triggers
3107 $result = $this->call_trigger('EXPENSE_REPORT_DET_CREATE', $user);
3108 if ($result < 0) {
3109 $error++;
3110 }
3111 // End call triggers
3112 }
3113
3114
3115 if (!$fromaddline) {
3116 $tmpparent = new ExpenseReport($this->db);
3117 $tmpparent->fetch($this->fk_expensereport);
3118 $result = $tmpparent->update_price(1);
3119 if ($result < 0) {
3120 $error++;
3121 $this->error = $tmpparent->error;
3122 $this->errors = $tmpparent->errors;
3123 }
3124 }
3125 } else {
3126 $error++;
3127 }
3128
3129 if (!$error) {
3130 $this->db->commit();
3131 return $this->id;
3132 } else {
3133 $this->error = $this->db->lasterror();
3134 dol_syslog("ExpenseReportLine::insert Error ".$this->error, LOG_ERR);
3135 $this->db->rollback();
3136 return -2;
3137 }
3138 }
3139
3148 public function getExpAmount(ExpenseReportRule $rule, $fk_user, $mode = 'day')
3149 {
3150 $amount = 0;
3151
3152 $sql = 'SELECT SUM(d.total_ttc) as total_amount';
3153 $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det d';
3154 $sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'expensereport e ON (d.fk_expensereport = e.rowid)';
3155 $sql .= ' WHERE e.fk_user_author = '.((int) $fk_user);
3156 if (!empty($this->id)) {
3157 $sql .= ' AND d.rowid <> '.((int) $this->id);
3158 }
3159 $sql .= ' AND d.fk_c_type_fees = '.((int) $rule->fk_c_type_fees);
3160 if ($mode == 'day' || $mode == 'EX_DAY') {
3161 $sql .= " AND d.date = '".dol_print_date($this->date, '%Y-%m-%d')."'";
3162 } elseif ($mode == 'mon' || $mode == 'EX_MON') {
3163 $sql .= " AND DATE_FORMAT(d.date, '%Y-%m') = '".dol_print_date($this->date, '%Y-%m')."'"; // @todo DATE_FORMAT is forbidden
3164 } elseif ($mode == 'year' || $mode == 'EX_YEA') {
3165 $sql .= " AND DATE_FORMAT(d.date, '%Y') = '".dol_print_date($this->date, '%Y')."'"; // @todo DATE_FORMAT is forbidden
3166 }
3167
3168 dol_syslog('ExpenseReportLine::getExpAmount');
3169
3170 $resql = $this->db->query($sql);
3171 if ($resql) {
3172 $num = $this->db->num_rows($resql);
3173 if ($num > 0) {
3174 $obj = $this->db->fetch_object($resql);
3175 $amount = (float) $obj->total_amount;
3176 }
3177 } else {
3178 dol_print_error($this->db);
3179 }
3180
3181 return $amount + $this->total_ttc;
3182 }
3183
3190 public function update(User $user)
3191 {
3192 global $langs;
3193
3194 $error = 0;
3195
3196 // Clean parameters
3197 $this->comments = trim($this->comments);
3198 $this->vatrate = price2num($this->vatrate);
3199 $this->value_unit = price2num($this->value_unit);
3200 if (empty($this->fk_c_exp_tax_cat)) {
3201 $this->fk_c_exp_tax_cat = 0;
3202 }
3203
3204 $this->db->begin();
3205
3206 // Update line in database
3207 $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport_det SET";
3208 $sql .= " comments='".$this->db->escape($this->comments)."'";
3209 $sql .= ", value_unit = ".((float) $this->value_unit);
3210 $sql .= ", qty=".((float) $this->qty);
3211 $sql .= ", date='".$this->db->idate($this->date)."'";
3212 $sql .= ", total_ht=".((float) price2num($this->total_ht, 'MT'));
3213 $sql .= ", total_tva=".((float) price2num($this->total_tva, 'MT'));
3214 $sql .= ", total_ttc=".((float) price2num($this->total_ttc, 'MT'));
3215 $sql .= ", total_localtax1=".((float) price2num($this->total_localtax1, 'MT'));
3216 $sql .= ", total_localtax2=".((float) price2num($this->total_localtax2, 'MT'));
3217 $sql .= ", tva_tx=".((float) $this->vatrate);
3218 $sql .= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
3219 $sql .= ", localtax1_tx=".((float) $this->localtax1_tx);
3220 $sql .= ", localtax2_tx=".((float) $this->localtax2_tx);
3221 $sql .= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
3222 $sql .= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
3223 $sql .= ", rule_warning_message='".$this->db->escape($this->rule_warning_message)."'";
3224 $sql .= ", fk_c_exp_tax_cat=".$this->db->escape($this->fk_c_exp_tax_cat);
3225 $sql .= ", fk_ecm_files=".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
3226 if ($this->fk_c_type_fees) {
3227 $sql .= ", fk_c_type_fees = ".((int) $this->fk_c_type_fees);
3228 } else {
3229 $sql .= ", fk_c_type_fees=null";
3230 }
3231 if ($this->fk_project > 0) {
3232 $sql .= ", fk_projet=".((int) $this->fk_project);
3233 } else {
3234 $sql .= ", fk_projet=null";
3235 }
3236 $sql .= " WHERE rowid = ".((int) ($this->rowid ? $this->rowid : $this->id));
3237
3238 dol_syslog("ExpenseReportLine::update");
3239
3240 $resql = $this->db->query($sql);
3241 if ($resql) {
3242 $tmpparent = new ExpenseReport($this->db);
3243 $result = $tmpparent->fetch($this->fk_expensereport);
3244 if ($result > 0) {
3245 $result = $tmpparent->update_price(1);
3246 if ($result < 0) {
3247 $error++;
3248 $this->error = $tmpparent->error;
3249 $this->errors = $tmpparent->errors;
3250 }
3251 } else {
3252 $error++;
3253 $this->error = $tmpparent->error;
3254 $this->errors = $tmpparent->errors;
3255 }
3256 } else {
3257 $error++;
3258 dol_print_error($this->db);
3259 }
3260
3261 if (!$error) {
3262 $this->db->commit();
3263 return 1;
3264 } else {
3265 $this->error = $this->db->lasterror();
3266 dol_syslog("ExpenseReportLine::update Error ".$this->error, LOG_ERR);
3267 $this->db->rollback();
3268 return -2;
3269 }
3270 }
3271
3272 // ajouter ici comput_ ...
3273}
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:637
$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:1991