dolibarr 20.0.5
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 $sql .= " AND d.entity IN (".getEntity('expensereport').")";
680 } else {
681 $sql .= " WHERE d.rowid = ".((int) $id);
682 }
683 //$sql.= $restrict;
684
685 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
686 $resql = $this->db->query($sql);
687 if ($resql) {
688 $obj = $this->db->fetch_object($resql);
689 if ($obj) {
690 $this->id = $obj->rowid;
691 $this->ref = $obj->ref;
692
693 $this->entity = $obj->entity;
694
695 $this->total_ht = $obj->total_ht;
696 $this->total_tva = $obj->total_tva;
697 $this->total_ttc = $obj->total_ttc;
698 $this->localtax1 = $obj->total_localtax1; // For backward compatibility
699 $this->localtax2 = $obj->total_localtax2; // For backward compatibility
700 $this->total_localtax1 = $obj->total_localtax1;
701 $this->total_localtax2 = $obj->total_localtax2;
702
703 $this->note_public = $obj->note_public;
704 $this->note_private = $obj->note_private;
705 $this->detail_refuse = $obj->detail_refuse;
706 $this->detail_cancel = $obj->detail_cancel;
707
708 $this->date_debut = $this->db->jdate($obj->date_debut);
709 $this->date_fin = $this->db->jdate($obj->date_fin);
710 $this->date_valid = $this->db->jdate($obj->date_valid);
711 $this->date_approve = $this->db->jdate($obj->date_approve);
712 $this->date_create = $this->db->jdate($obj->date_create);
713 $this->date_modif = $this->db->jdate($obj->date_modif);
714 $this->date_refuse = $this->db->jdate($obj->date_refuse);
715 $this->date_cancel = $this->db->jdate($obj->date_cancel);
716
717 $this->fk_user_creat = $obj->fk_user_creat;
718 $this->fk_user_author = $obj->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
719 $this->fk_user_modif = $obj->fk_user_modif;
720 $this->fk_user_validator = $obj->fk_user_validator;
721 $this->fk_user_valid = $obj->fk_user_valid;
722 $this->fk_user_refuse = $obj->fk_user_refuse;
723 $this->fk_user_cancel = $obj->fk_user_cancel;
724 $this->fk_user_approve = $obj->fk_user_approve;
725
726 $user_author = new User($this->db);
727 if ($this->fk_user_author > 0) {
728 $user_author->fetch($this->fk_user_author);
729 }
730
731 $this->user_author_infos = dolGetFirstLastname($user_author->firstname, $user_author->lastname);
732
733 $user_approver = new User($this->db);
734 if ($this->fk_user_approve > 0) {
735 $user_approver->fetch($this->fk_user_approve);
736 } elseif ($this->fk_user_validator > 0) {
737 $user_approver->fetch($this->fk_user_validator); // For backward compatibility
738 }
739 $this->user_validator_infos = dolGetFirstLastname($user_approver->firstname, $user_approver->lastname);
740
741 $this->fk_statut = $obj->status; // deprecated
742 $this->status = $obj->status;
743 $this->fk_c_paiement = $obj->fk_c_paiement;
744 $this->paid = $obj->paid;
745
746 if ($this->status == self::STATUS_APPROVED || $this->status == self::STATUS_CLOSED) {
747 $user_valid = new User($this->db);
748 if ($this->fk_user_valid > 0) {
749 $user_valid->fetch($this->fk_user_valid);
750 }
751 $this->user_valid_infos = dolGetFirstLastname($user_valid->firstname, $user_valid->lastname);
752 }
753
754 $this->fetch_optionals();
755
756 $result = $this->fetch_lines();
757
758 return $result;
759 } else {
760 return 0;
761 }
762 } else {
763 $this->error = $this->db->lasterror();
764 return -1;
765 }
766 }
767
768 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
779 public function set_paid($id, $fuser, $notrigger = 0)
780 {
781 // phpcs:enable
782 dol_syslog(get_class($this)."::set_paid is deprecated, use setPaid instead", LOG_NOTICE);
783 return $this->setPaid($id, $fuser, $notrigger);
784 }
785
794 public function setPaid($id, $fuser, $notrigger = 0)
795 {
796 $error = 0;
797 $this->db->begin();
798
799 $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport";
800 $sql .= " SET fk_statut = ".self::STATUS_CLOSED.", paid=1";
801 $sql .= " WHERE rowid = ".((int) $id)." AND fk_statut = ".self::STATUS_APPROVED;
802
803 dol_syslog(get_class($this)."::setPaid", LOG_DEBUG);
804 $resql = $this->db->query($sql);
805 if ($resql) {
806 if ($this->db->affected_rows($resql)) {
807 if (!$notrigger) {
808 // Call trigger
809 $result = $this->call_trigger('EXPENSE_REPORT_PAID', $fuser);
810
811 if ($result < 0) {
812 $error++;
813 }
814 // End call triggers
815 }
816
817 if (empty($error)) {
818 $this->db->commit();
819 return 1;
820 } else {
821 $this->db->rollback();
822 $this->error = $this->db->error();
823 return -2;
824 }
825 } else {
826 $this->db->commit();
827 return 0;
828 }
829 } else {
830 $this->db->rollback();
831 dol_print_error($this->db);
832 return -1;
833 }
834 }
835
842 public function getLibStatut($mode = 0)
843 {
844 return $this->LibStatut($this->status, $mode);
845 }
846
847 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
855 public function LibStatut($status, $mode = 0)
856 {
857 // phpcs:enable
858 global $langs;
859
860 $labelStatus = $langs->transnoentitiesnoconv($this->labelStatus[$status]);
861 $labelStatusShort = $langs->transnoentitiesnoconv($this->labelStatusShort[$status]);
862
863 $statuslogo = array(0 => 'status0', 2 => 'status1', 4 => 'status6', 5 => 'status4', 6 => 'status6', 99 => 'status5');
864
865 $statusType = $statuslogo[$status];
866
867 return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
868 }
869
870
877 public function info($id)
878 {
879 global $conf;
880
881 $sql = "SELECT f.rowid,";
882 $sql .= " f.date_create as datec,";
883 $sql .= " f.tms as date_modification,";
884 $sql .= " f.date_valid as datev,";
885 $sql .= " f.date_approve as datea,";
886 $sql .= " f.fk_user_creat as fk_user_creation,";
887 $sql .= " f.fk_user_author as fk_user_author,";
888 $sql .= " f.fk_user_modif as fk_user_modification,";
889 $sql .= " f.fk_user_valid,";
890 $sql .= " f.fk_user_approve";
891 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as f";
892 $sql .= " WHERE f.rowid = ".((int) $id);
893 $sql .= " AND f.entity = ".$conf->entity;
894
895
896
897 $resql = $this->db->query($sql);
898 if ($resql) {
899 if ($this->db->num_rows($resql)) {
900 $obj = $this->db->fetch_object($resql);
901
902 $this->id = $obj->rowid;
903
904 $this->date_creation = $this->db->jdate($obj->datec);
905 $this->date_modification = $this->db->jdate($obj->date_modification);
906 $this->date_validation = $this->db->jdate($obj->datev);
907 $this->date_approbation = $this->db->jdate($obj->datea);
908
909 $this->user_creation_id = $obj->fk_user_author;
910 $this->user_creation_id = $obj->fk_user_creation;
911 $this->user_validation_id = $obj->fk_user_valid;
912 $this->user_modification_id = $obj->fk_user_modification;
913 $this->user_approve_id = $obj->fk_user_approve;
914 }
915 $this->db->free($resql);
916 } else {
917 dol_print_error($this->db);
918 }
919 }
920
921
922
930 public function initAsSpecimen()
931 {
932 global $user, $langs;
933
934 $now = dol_now();
935
936 // Initialise parameters
937 $this->id = 0;
938 $this->ref = 'SPECIMEN';
939 $this->specimen = 1;
940 $this->entity = 1;
941 $this->date_create = $now;
942 $this->date_debut = $now;
943 $this->date_fin = $now;
944 $this->date_valid = $now;
945 $this->date_approve = $now;
946
947 $type_fees_id = 2; // TF_TRIP
948
949 $this->status = 5;
950
951 $this->fk_user_author = $user->id;
952 $this->fk_user_validator = $user->id;
953 $this->fk_user_valid = $user->id;
954 $this->fk_user_approve = $user->id;
955
956 $this->note_private = 'Private note';
957 $this->note_public = 'SPECIMEN';
958 $nbp = 5;
959 $xnbp = 0;
960 while ($xnbp < $nbp) {
961 $line = new ExpenseReportLine($this->db);
962 $line->comments = $langs->trans("Comment")." ".$xnbp;
963 $line->date = ($now - 3600 * (1 + $xnbp));
964 $line->total_ht = 100;
965 $line->total_tva = 20;
966 $line->total_ttc = 120;
967 $line->qty = 1;
968 $line->vatrate = 20;
969 $line->value_unit = 120;
970 $line->fk_expensereport = 0;
971 $line->type_fees_code = 'TRA';
972 $line->fk_c_type_fees = $type_fees_id;
973
974 $line->projet_ref = 'ABC';
975
976 $this->lines[$xnbp] = $line;
977 $xnbp++;
978
979 $this->total_ht += $line->total_ht;
980 $this->total_tva += $line->total_tva;
981 $this->total_ttc += $line->total_ttc;
982 }
983
984 return 1;
985 }
986
987 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
995 public function fetch_line_by_project($projectid, $user)
996 {
997 // phpcs:enable
998 global $langs;
999
1000 $langs->load('trips');
1001
1002 if ($user->hasRight('expensereport', 'lire')) {
1003 $sql = "SELECT de.fk_expensereport, de.date, de.comments, de.total_ht, de.total_ttc";
1004 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport_det as de";
1005 $sql .= " WHERE de.fk_projet = ".((int) $projectid);
1006
1007 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1008 $result = $this->db->query($sql);
1009 if ($result) {
1010 $num = $this->db->num_rows($result);
1011 $i = 0;
1012 $total_HT = 0;
1013 $total_TTC = 0;
1014
1015 while ($i < $num) {
1016 $objp = $this->db->fetch_object($result);
1017
1018 $sql2 = "SELECT d.rowid, d.fk_user_author, d.ref, d.fk_statut as status";
1019 $sql2 .= " FROM ".MAIN_DB_PREFIX."expensereport as d";
1020 $sql2 .= " WHERE d.rowid = ".((int) $objp->fk_expensereport);
1021
1022 $result2 = $this->db->query($sql2);
1023 $obj = $this->db->fetch_object($result2);
1024
1025 $objp->fk_user_author = $obj->fk_user_author;
1026 $objp->ref = $obj->ref;
1027 $objp->fk_c_expensereport_status = $obj->status;
1028 $objp->rowid = $obj->rowid;
1029
1030 $total_HT += $objp->total_ht;
1031 $total_TTC += $objp->total_ttc;
1032 $author = new User($this->db);
1033 $author->fetch($objp->fk_user_author);
1034
1035 print '<tr>';
1036 print '<td><a href="'.DOL_URL_ROOT.'/expensereport/card.php?id='.$objp->rowid.'">'.$objp->ref_num.'</a></td>';
1037 print '<td class="center">'.dol_print_date($objp->date, 'day').'</td>';
1038 print '<td>'.$author->getNomUrl(1).'</td>';
1039 print '<td>'.$objp->comments.'</td>';
1040 print '<td class="right">'.price($objp->total_ht).'</td>';
1041 print '<td class="right">'.price($objp->total_ttc).'</td>';
1042 print '<td class="right">';
1043
1044 switch ($objp->fk_c_expensereport_status) {
1045 case 4:
1046 print img_picto($langs->trans('StatusOrderCanceled'), 'statut5');
1047 break;
1048 case 1:
1049 print $langs->trans('Draft').' '.img_picto($langs->trans('Draft'), 'statut0');
1050 break;
1051 case 2:
1052 print $langs->trans('TripForValid').' '.img_picto($langs->trans('TripForValid'), 'statut3');
1053 break;
1054 case 5:
1055 print $langs->trans('TripForPaid').' '.img_picto($langs->trans('TripForPaid'), 'statut3');
1056 break;
1057 case 6:
1058 print $langs->trans('TripPaid').' '.img_picto($langs->trans('TripPaid'), 'statut4');
1059 break;
1060 }
1061 /*
1062 if ($status==4) return img_picto($langs->trans('StatusOrderCanceled'),'statut5');
1063 if ($status==1) return img_picto($langs->trans('StatusOrderDraft'),'statut0');
1064 if ($status==2) return img_picto($langs->trans('StatusOrderValidated'),'statut1');
1065 if ($status==2) return img_picto($langs->trans('StatusOrderOnProcess'),'statut3');
1066 if ($status==5) return img_picto($langs->trans('StatusOrderToBill'),'statut4');
1067 if ($status==6) return img_picto($langs->trans('StatusOrderOnProcess'),'statut6');
1068 */
1069 print '</td>';
1070 print '</tr>';
1071
1072 $i++;
1073 }
1074
1075 print '<tr class="liste_total"><td colspan="4">'.$langs->trans("Number").': '.$i.'</td>';
1076 print '<td class="right" width="100">'.$langs->trans("TotalHT").' : '.price($total_HT).'</td>';
1077 print '<td class="right" width="100">'.$langs->trans("TotalTTC").' : '.price($total_TTC).'</td>';
1078 print '<td>&nbsp;</td>';
1079 print '</tr>';
1080 } else {
1081 $this->error = $this->db->lasterror();
1082 return -1;
1083 }
1084 }
1085
1086 return 0;
1087 }
1088
1089 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1095 public function fetch_lines()
1096 {
1097 // phpcs:enable
1098 $this->lines = array();
1099
1100 $sql = ' SELECT de.rowid, de.comments, de.qty, de.value_unit, de.date, de.rang,';
1101 $sql .= " de.".$this->fk_element.", de.fk_c_type_fees, de.fk_c_exp_tax_cat, de.fk_projet as fk_project,";
1102 $sql .= ' de.tva_tx, de.vat_src_code,';
1103 $sql .= ' de.localtax1_tx, de.localtax2_tx, de.localtax1_type, de.localtax2_type,';
1104 $sql .= ' de.fk_ecm_files,';
1105 $sql .= ' de.total_ht, de.total_tva, de.total_ttc,';
1106 $sql .= ' de.total_localtax1, de.total_localtax2, de.rule_warning_message,';
1107 $sql .= ' ctf.code as code_type_fees, ctf.label as label_type_fees, ctf.accountancy_code as accountancy_code_type_fees,';
1108 $sql .= ' p.ref as ref_projet, p.title as title_projet';
1109 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as de';
1110 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_type_fees as ctf ON de.fk_c_type_fees = ctf.id';
1111 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as p ON de.fk_projet = p.rowid';
1112 $sql .= " WHERE de.".$this->fk_element." = ".((int) $this->id);
1113 if (getDolGlobalString('EXPENSEREPORT_LINES_SORTED_BY_ROWID')) {
1114 $sql .= ' ORDER BY de.rang ASC, de.rowid ASC';
1115 } else {
1116 $sql .= ' ORDER BY de.rang ASC, de.date ASC';
1117 }
1118
1119 $resql = $this->db->query($sql);
1120 if ($resql) {
1121 $num = $this->db->num_rows($resql);
1122 $i = 0;
1123 while ($i < $num) {
1124 $objp = $this->db->fetch_object($resql);
1125
1126 $deplig = new ExpenseReportLine($this->db);
1127
1128 $deplig->rowid = $objp->rowid;
1129 $deplig->id = $objp->rowid;
1130 $deplig->comments = $objp->comments;
1131 $deplig->qty = $objp->qty;
1132 $deplig->value_unit = $objp->value_unit;
1133 $deplig->date = $objp->date;
1134 $deplig->dates = $this->db->jdate($objp->date);
1135
1136 $deplig->fk_expensereport = $objp->fk_expensereport;
1137 $deplig->fk_c_type_fees = $objp->fk_c_type_fees;
1138 $deplig->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
1139 $deplig->fk_projet = $objp->fk_project; // deprecated
1140 $deplig->fk_project = $objp->fk_project;
1141 $deplig->fk_ecm_files = $objp->fk_ecm_files;
1142
1143 $deplig->total_ht = $objp->total_ht;
1144 $deplig->total_tva = $objp->total_tva;
1145 $deplig->total_ttc = $objp->total_ttc;
1146 $deplig->total_localtax1 = $objp->total_localtax1;
1147 $deplig->total_localtax2 = $objp->total_localtax2;
1148
1149 $deplig->type_fees_code = empty($objp->code_type_fees) ? 'TF_OTHER' : $objp->code_type_fees;
1150 $deplig->type_fees_libelle = $objp->label_type_fees;
1151 $deplig->type_fees_accountancy_code = $objp->accountancy_code_type_fees;
1152
1153 $deplig->tva_tx = $objp->tva_tx;
1154 $deplig->vatrate = $objp->tva_tx;
1155 $deplig->vat_src_code = $objp->vat_src_code;
1156 $deplig->localtax1_tx = $objp->localtax1_tx;
1157 $deplig->localtax2_tx = $objp->localtax2_tx;
1158 $deplig->localtax1_type = $objp->localtax1_type;
1159 $deplig->localtax2_type = $objp->localtax2_type;
1160
1161 $deplig->projet_ref = $objp->ref_projet;
1162 $deplig->projet_title = $objp->title_projet;
1163
1164 $deplig->rule_warning_message = $objp->rule_warning_message;
1165
1166 $deplig->rang = $objp->rang;
1167
1168 $this->lines[$i] = $deplig;
1169
1170 $i++;
1171 }
1172 $this->db->free($resql);
1173 return 1;
1174 } else {
1175 $this->error = $this->db->lasterror();
1176 dol_syslog(get_class($this)."::fetch_lines: Error ".$this->error, LOG_ERR);
1177 return -3;
1178 }
1179 }
1180
1181
1189 public function delete(User $user = null, $notrigger = 0)
1190 {
1191 global $conf;
1192 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1193
1194 $error = 0;
1195
1196 $this->db->begin();
1197
1198 if (!$notrigger) {
1199 // Call trigger
1200 $result = $this->call_trigger('EXPENSE_REPORT_DELETE', $user);
1201 if ($result < 0) {
1202 $error++;
1203 }
1204 // End call triggers
1205 }
1206
1207 // Delete extrafields of lines and lines
1208 if (!$error && !empty($this->table_element_line)) {
1209 $tabletodelete = $this->table_element_line;
1210 //$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).")";
1211 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id);
1212 if (!$this->db->query($sql)) {
1213 $error++;
1214 $this->error = $this->db->lasterror();
1215 $this->errors[] = $this->error;
1216 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1217 }
1218 }
1219
1220 if (!$error) {
1221 // Delete linked object
1222 $res = $this->deleteObjectLinked();
1223 if ($res < 0) {
1224 $error++;
1225 }
1226 }
1227
1228 if (!$error) {
1229 // Delete linked contacts
1230 $res = $this->delete_linked_contact();
1231 if ($res < 0) {
1232 $error++;
1233 }
1234 }
1235
1236 // Removed extrafields of object
1237 if (!$error) {
1238 $result = $this->deleteExtraFields();
1239 if ($result < 0) {
1240 $error++;
1241 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1242 }
1243 }
1244
1245 // Delete main record
1246 if (!$error) {
1247 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".((int) $this->id);
1248 $res = $this->db->query($sql);
1249 if (!$res) {
1250 $error++;
1251 $this->error = $this->db->lasterror();
1252 $this->errors[] = $this->error;
1253 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1254 }
1255 }
1256
1257 // Delete record into ECM index and physically
1258 if (!$error) {
1259 $res = $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
1260 $res = $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive
1261 if (!$res) {
1262 $error++;
1263 }
1264 }
1265
1266 if (!$error) {
1267 // We remove directory
1268 $ref = dol_sanitizeFileName($this->ref);
1269 if ($conf->expensereport->multidir_output[$this->entity] && !empty($this->ref)) {
1270 $dir = $conf->expensereport->multidir_output[$this->entity]."/".$ref;
1271 $file = $dir."/".$ref.".pdf";
1272 if (file_exists($file)) {
1273 dol_delete_preview($this);
1274
1275 if (!dol_delete_file($file, 0, 0, 0, $this)) {
1276 $this->error = 'ErrorFailToDeleteFile';
1277 $this->errors[] = $this->error;
1278 $this->db->rollback();
1279 return 0;
1280 }
1281 }
1282 if (file_exists($dir)) {
1283 $res = @dol_delete_dir_recursive($dir);
1284 if (!$res) {
1285 $this->error = 'ErrorFailToDeleteDir';
1286 $this->errors[] = $this->error;
1287 $this->db->rollback();
1288 return 0;
1289 }
1290 }
1291 }
1292 }
1293
1294 if (!$error) {
1295 dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
1296 $this->db->commit();
1297 return 1;
1298 } else {
1299 $this->db->rollback();
1300 return -1;
1301 }
1302 }
1303
1311 public function setValidate($fuser, $notrigger = 0)
1312 {
1313 global $conf, $langs, $user;
1314
1315 $error = 0;
1316 $now = dol_now();
1317
1318 // Protection
1319 if ($this->status == self::STATUS_VALIDATED) {
1320 dol_syslog(get_class($this)."::valid action abandoned: already validated", LOG_WARNING);
1321 return 0;
1322 }
1323
1324 $this->date_valid = $now; // Required for the getNextNum later.
1325
1326 // Define new ref
1327 if (!$error && (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
1328 $num = $this->getNextNumRef();
1329 } else {
1330 $num = $this->ref;
1331 }
1332 if (empty($num) || $num < 0) {
1333 return -1;
1334 }
1335
1336 $this->newref = dol_sanitizeFileName($num);
1337
1338 $this->db->begin();
1339
1340 // Validate
1341 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1342 $sql .= " SET ref = '".$this->db->escape($num)."',";
1343 $sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
1344 $sql .= " date_valid = '".$this->db->idate($this->date_valid)."',";
1345 $sql .= " fk_user_valid = ".((int) $user->id);
1346 $sql .= " WHERE rowid = ".((int) $this->id);
1347
1348 $resql = $this->db->query($sql);
1349 if ($resql) {
1350 if (!$error && !$notrigger) {
1351 // Call trigger
1352 $result = $this->call_trigger('EXPENSE_REPORT_VALIDATE', $fuser);
1353 if ($result < 0) {
1354 $error++;
1355 }
1356 // End call triggers
1357 }
1358
1359 if (!$error) {
1360 $this->oldref = $this->ref;
1361
1362 // Rename directory if dir was a temporary ref
1363 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
1364 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1365
1366 // Now we rename also files into index
1367 $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)."'";
1368 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'expensereport/".$this->db->escape($this->ref)."' AND entity = ".((int) $this->entity);
1369 $resql = $this->db->query($sql);
1370 if (!$resql) {
1371 $error++;
1372 $this->error = $this->db->lasterror();
1373 }
1374 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'expensereport/".$this->db->escape($this->newref)."'";
1375 $sql .= " WHERE filepath = 'expensereport/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1376 $resql = $this->db->query($sql);
1377 if (!$resql) {
1378 $error++;
1379 $this->error = $this->db->lasterror();
1380 }
1381
1382 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1383 $oldref = dol_sanitizeFileName($this->ref);
1384 $newref = dol_sanitizeFileName($num);
1385 $dirsource = $conf->expensereport->multidir_output[$this->entity].'/'.$oldref;
1386 $dirdest = $conf->expensereport->multidir_output[$this->entity].'/'.$newref;
1387 if (!$error && file_exists($dirsource)) {
1388 dol_syslog(get_class($this)."::setValidate() rename dir ".$dirsource." into ".$dirdest);
1389
1390 if (@rename($dirsource, $dirdest)) {
1391 dol_syslog("Rename ok");
1392 // Rename docs starting with $oldref with $newref
1393 $listoffiles = dol_dir_list($dirdest, 'files', 1, '^'.preg_quote($oldref, '/'));
1394 foreach ($listoffiles as $fileentry) {
1395 $dirsource = $fileentry['name'];
1396 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1397 $dirsource = $fileentry['path'].'/'.$dirsource;
1398 $dirdest = $fileentry['path'].'/'.$dirdest;
1399 @rename($dirsource, $dirdest);
1400 }
1401 }
1402 }
1403 }
1404 }
1405
1406 // Set new ref and current status
1407 if (!$error) {
1408 $this->ref = $num;
1410 }
1411
1412 if (empty($error)) {
1413 $this->db->commit();
1414 return 1;
1415 } else {
1416 $this->db->rollback();
1417 $this->error = $this->db->error();
1418 return -2;
1419 }
1420 } else {
1421 $this->db->rollback();
1422 $this->error = $this->db->lasterror();
1423 return -1;
1424 }
1425 }
1426
1427 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1434 public function set_save_from_refuse($fuser)
1435 {
1436 // phpcs:enable
1437 // Sélection de la date de début de la NDF
1438 $sql = 'SELECT date_debut';
1439 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
1440 $sql .= " WHERE rowid = ".((int) $this->id);
1441
1442 $result = $this->db->query($sql);
1443
1444 $objp = $this->db->fetch_object($result);
1445
1446 $this->date_debut = $this->db->jdate($objp->date_debut);
1447
1448 if ($this->status != self::STATUS_VALIDATED) {
1449 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1450 $sql .= " SET fk_statut = ".self::STATUS_VALIDATED;
1451 $sql .= " WHERE rowid = ".((int) $this->id);
1452
1453 dol_syslog(get_class($this)."::set_save_from_refuse", LOG_DEBUG);
1454
1455 if ($this->db->query($sql)) {
1456 return 1;
1457 } else {
1458 $this->error = $this->db->lasterror();
1459 return -1;
1460 }
1461 } else {
1462 dol_syslog(get_class($this)."::set_save_from_refuse expensereport already with save status", LOG_WARNING);
1463 }
1464
1465 return 0;
1466 }
1467
1475 public function setApproved($fuser, $notrigger = 0)
1476 {
1477 $now = dol_now();
1478 $error = 0;
1479
1480 // date approval
1481 $this->date_approve = $now;
1482 if ($this->status != self::STATUS_APPROVED) {
1483 $this->db->begin();
1484
1485 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1486 $sql .= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = ".self::STATUS_APPROVED.", fk_user_approve = ".((int) $fuser->id).",";
1487 $sql .= " date_approve='".$this->db->idate($this->date_approve)."'";
1488 $sql .= " WHERE rowid = ".((int) $this->id);
1489 if ($this->db->query($sql)) {
1490 if (!$notrigger) {
1491 // Call trigger
1492 $result = $this->call_trigger('EXPENSE_REPORT_APPROVE', $fuser);
1493
1494 if ($result < 0) {
1495 $error++;
1496 }
1497 // End call triggers
1498 }
1499
1500 if (empty($error)) {
1501 $this->db->commit();
1502 return 1;
1503 } else {
1504 $this->db->rollback();
1505 $this->error = $this->db->error();
1506 return -2;
1507 }
1508 } else {
1509 $this->db->rollback();
1510 $this->error = $this->db->lasterror();
1511 return -1;
1512 }
1513 } else {
1514 dol_syslog(get_class($this)."::setApproved expensereport already with approve status", LOG_WARNING);
1515 }
1516
1517 return 0;
1518 }
1519
1528 public function setDeny($fuser, $details, $notrigger = 0)
1529 {
1530 $now = dol_now();
1531 $error = 0;
1532
1533 // date de refus
1534 if ($this->status != self::STATUS_REFUSED) {
1535 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1536 $sql .= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = ".self::STATUS_REFUSED.", fk_user_refuse = ".((int) $fuser->id).",";
1537 $sql .= " date_refuse='".$this->db->idate($now)."',";
1538 $sql .= " detail_refuse='".$this->db->escape($details)."',";
1539 $sql .= " fk_user_approve = NULL";
1540 $sql .= " WHERE rowid = ".((int) $this->id);
1541 if ($this->db->query($sql)) {
1542 $this->fk_statut = 99; // deprecated
1543 $this->status = 99;
1544 $this->fk_user_refuse = $fuser->id;
1545 $this->detail_refuse = $details;
1546 $this->date_refuse = $now;
1547
1548 if (!$notrigger) {
1549 // Call trigger
1550 $result = $this->call_trigger('EXPENSE_REPORT_DENY', $fuser);
1551
1552 if ($result < 0) {
1553 $error++;
1554 }
1555 // End call triggers
1556 }
1557
1558 if (empty($error)) {
1559 $this->db->commit();
1560 return 1;
1561 } else {
1562 $this->db->rollback();
1563 $this->error = $this->db->error();
1564 return -2;
1565 }
1566 } else {
1567 $this->db->rollback();
1568 $this->error = $this->db->lasterror();
1569 return -1;
1570 }
1571 } else {
1572 dol_syslog(get_class($this)."::setDeny expensereport already with refuse status", LOG_WARNING);
1573 }
1574
1575 return 0;
1576 }
1577
1578 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1588 public function set_unpaid($fuser, $notrigger = 0)
1589 {
1590 // phpcs:enable
1591 dol_syslog(get_class($this)."::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE);
1592 return $this->setUnpaid($fuser, $notrigger);
1593 }
1594
1602 public function setUnpaid($fuser, $notrigger = 0)
1603 {
1604 $error = 0;
1605
1606 if ($this->paid) {
1607 $this->db->begin();
1608
1609 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1610 $sql .= " SET paid = 0, fk_statut = ".self::STATUS_APPROVED;
1611 $sql .= " WHERE rowid = ".((int) $this->id);
1612
1613 dol_syslog(get_class($this)."::set_unpaid", LOG_DEBUG);
1614
1615 if ($this->db->query($sql)) {
1616 if (!$notrigger) {
1617 // Call trigger
1618 $result = $this->call_trigger('EXPENSE_REPORT_UNPAID', $fuser);
1619
1620 if ($result < 0) {
1621 $error++;
1622 }
1623 // End call triggers
1624 }
1625
1626 if (empty($error)) {
1627 $this->db->commit();
1628 return 1;
1629 } else {
1630 $this->db->rollback();
1631 $this->error = $this->db->error();
1632 return -2;
1633 }
1634 } else {
1635 $this->db->rollback();
1636 $this->error = $this->db->error();
1637 return -1;
1638 }
1639 } else {
1640 dol_syslog(get_class($this)."::set_unpaid expensereport already with unpaid status", LOG_WARNING);
1641 }
1642
1643 return 0;
1644 }
1645
1646 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1655 public function set_cancel($fuser, $detail, $notrigger = 0)
1656 {
1657 // phpcs:enable
1658 $error = 0;
1659 $this->date_cancel = $this->db->idate(dol_now());
1660 if ($this->status != self::STATUS_CANCELED) {
1661 $this->db->begin();
1662
1663 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1664 $sql .= " SET fk_statut = ".self::STATUS_CANCELED.", fk_user_cancel = ".((int) $fuser->id);
1665 $sql .= ", date_cancel='".$this->db->idate($this->date_cancel)."'";
1666 $sql .= ", detail_cancel='".$this->db->escape($detail)."'";
1667 $sql .= " WHERE rowid = ".((int) $this->id);
1668
1669 dol_syslog(get_class($this)."::set_cancel", LOG_DEBUG);
1670
1671 if ($this->db->query($sql)) {
1672 if (!$notrigger) {
1673 // Call trigger
1674 $result = $this->call_trigger('EXPENSE_REPORT_CANCEL', $fuser);
1675
1676 if ($result < 0) {
1677 $error++;
1678 }
1679 // End call triggers
1680 }
1681
1682 if (empty($error)) {
1683 $this->db->commit();
1684 return 1;
1685 } else {
1686 $this->db->rollback();
1687 $this->error = $this->db->error();
1688 return -2;
1689 }
1690 } else {
1691 $this->db->rollback();
1692 $this->error = $this->db->error();
1693 return -1;
1694 }
1695 } else {
1696 dol_syslog(get_class($this)."::set_cancel expensereport already with cancel status", LOG_WARNING);
1697 }
1698 return 0;
1699 }
1700
1706 public function getNextNumRef()
1707 {
1708 global $langs, $conf;
1709 $langs->load("trips");
1710
1711 if (getDolGlobalString('EXPENSEREPORT_ADDON')) {
1712 $mybool = false;
1713
1714 $file = getDolGlobalString('EXPENSEREPORT_ADDON') . ".php";
1715 $classname = getDolGlobalString('EXPENSEREPORT_ADDON');
1716
1717 // Include file with class
1718 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1719 foreach ($dirmodels as $reldir) {
1720 $dir = dol_buildpath($reldir."core/modules/expensereport/");
1721
1722 // Load file with numbering class (if found)
1723 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1724 }
1725
1726 if (!$mybool) {
1727 dol_print_error(null, "Failed to include file ".$file);
1728 return '';
1729 }
1730
1731 $obj = new $classname();
1732 $numref = $obj->getNextValue($this);
1733
1734 if ($numref != "") {
1735 return $numref;
1736 } else {
1737 $this->error = $obj->error;
1738 $this->errors = $obj->errors;
1739 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1740 return -1;
1741 }
1742 } else {
1743 $this->error = "Error_EXPENSEREPORT_ADDON_NotDefined";
1744 return -2;
1745 }
1746 }
1747
1755 public function getTooltipContentArray($params)
1756 {
1757 global $conf, $langs;
1758
1759 $langs->load('trips');
1760
1761 $nofetch = !empty($params['nofetch']);
1762 $moretitle = $params['moretitle'] ?? '';
1763
1764 $datas = array();
1765 $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("ExpenseReport").'</u>';
1766 if (isset($this->status)) {
1767 $datas['picto'] .= ' '.$this->getLibStatut(5);
1768 }
1769 if ($moretitle) {
1770 $datas['picto'] .= ' - '.$moretitle;
1771 }
1772 if (!empty($this->ref)) {
1773 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1774 }
1775 if (!empty($this->total_ht)) {
1776 $datas['total_ht'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
1777 }
1778 if (!empty($this->total_tva)) {
1779 $datas['total_tva'] = '<br><b>'.$langs->trans('VAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
1780 }
1781 if (!empty($this->total_ttc)) {
1782 $datas['total_ttc'] = '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
1783 }
1784
1785 return $datas;
1786 }
1787
1800 public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1)
1801 {
1802 global $langs, $hookmanager;
1803
1804 $result = '';
1805
1806 $url = DOL_URL_ROOT.'/expensereport/card.php?id='.$this->id;
1807
1808 if ($short) {
1809 return $url;
1810 }
1811
1812 $params = [
1813 'id' => $this->id,
1814 'objecttype' => $this->element,
1815 'option' => $option,
1816 'moretitle' => $moretitle,
1817 'nofetch' => 1,
1818 ];
1819 $classfortooltip = 'classfortooltip';
1820 $dataparams = '';
1821 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1822 $classfortooltip = 'classforajaxtooltip';
1823 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1824 $label = '';
1825 } else {
1826 $label = implode($this->getTooltipContentArray($params));
1827 }
1828
1829 if ($option != 'nolink') {
1830 // Add param to save lastsearch_values or not
1831 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1832 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1833 $add_save_lastsearch_values = 1;
1834 }
1835 if ($add_save_lastsearch_values) {
1836 $url .= '&save_lastsearch_values=1';
1837 }
1838 }
1839
1840 $ref = $this->ref;
1841 if (empty($ref)) {
1842 $ref = $this->id;
1843 }
1844
1845 $linkclose = '';
1846 if (empty($notooltip)) {
1847 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1848 $label = $langs->trans("ShowExpenseReport");
1849 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1850 }
1851 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1852 $linkclose .= $dataparams.' class="'.$classfortooltip.'"';
1853 }
1854
1855 $linkstart = '<a href="'.$url.'"';
1856 $linkstart .= $linkclose.'>';
1857 $linkend = '</a>';
1858
1859 $result .= $linkstart;
1860 if ($withpicto) {
1861 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'"'), 0, 0, $notooltip ? 0 : 1);
1862 }
1863 if ($withpicto != 2) {
1864 $result .= ($max ? dol_trunc($ref, $max) : $ref);
1865 }
1866 $result .= $linkend;
1867
1868 global $action;
1869 $hookmanager->initHooks(array($this->element . 'dao'));
1870 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1871 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1872 if ($reshook > 0) {
1873 $result = $hookmanager->resPrint;
1874 } else {
1875 $result .= $hookmanager->resPrint;
1876 }
1877 return $result;
1878 }
1879
1880 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1888 public function update_totaux_add($ligne_total_ht, $ligne_total_tva)
1889 {
1890 // phpcs:enable
1891 $this->total_ht += (float) $ligne_total_ht;
1892 $this->total_tva += (float) $ligne_total_tva;
1893 $this->total_ttc += $this->total_tva;
1894
1895 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
1896 $sql .= " total_ht = ".$this->total_ht;
1897 $sql .= " , total_ttc = ".$this->total_ttc;
1898 $sql .= " , total_tva = ".$this->total_tva;
1899 $sql .= " WHERE rowid = ".((int) $this->id);
1900
1901 $result = $this->db->query($sql);
1902 if ($result) {
1903 return 1;
1904 } else {
1905 $this->error = $this->db->error();
1906 return -1;
1907 }
1908 }
1909
1925 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)
1926 {
1927 global $langs, $mysoc;
1928
1929 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);
1930
1931 if ($this->status == self::STATUS_DRAFT || $this->status == self::STATUS_REFUSED) {
1932 if (empty($qty)) {
1933 $qty = 0;
1934 }
1935 if (empty($fk_c_type_fees) || $fk_c_type_fees < 0) {
1936 $fk_c_type_fees = 0;
1937 }
1938 if (empty($fk_c_exp_tax_cat) || $fk_c_exp_tax_cat < 0) {
1939 $fk_c_exp_tax_cat = 0;
1940 }
1941 if (empty($vatrate) || $vatrate < 0) {
1942 $vatrate = 0;
1943 }
1944 if (empty($date)) {
1945 $date = '';
1946 }
1947 if (empty($fk_project)) {
1948 $fk_project = 0;
1949 }
1950
1951 $qty = (float) price2num($qty);
1952 if (!preg_match('/\s*\‍((.*)\‍)/', $vatrate)) {
1953 $vatrate = price2num($vatrate); // $txtva can have format '5.0 (XXX)' or '5'
1954 }
1955 $up = price2num($up);
1956
1957 $this->db->begin();
1958
1959 $this->line = new ExpenseReportLine($this->db);
1960
1961 // We don't know seller and buyer for expense reports
1962 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
1963 $seller->tva_assuj = 1; // Most seller uses vat
1964 $buyer = new Societe($this->db);
1965
1966 $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller);
1967
1968 $vat_src_code = '';
1969 $reg = array();
1970 if (preg_match('/\s*\‍((.*)\‍)/', $vatrate, $reg)) {
1971 $vat_src_code = $reg[1];
1972 $vatrate = preg_replace('/\s*\‍(.*\‍)/', '', $vatrate); // Remove code into vatrate.
1973 }
1974 $vatrate = preg_replace('/\*/', '', $vatrate);
1975
1976 $tmp = calcul_price_total($qty, $up, 0, $vatrate, -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
1977
1978 $this->line->value_unit = $up;
1979
1980 $this->line->vat_src_code = $vat_src_code;
1981 $this->line->vatrate = price2num($vatrate);
1982 $this->line->localtax1_tx = $localtaxes_type[1];
1983 $this->line->localtax2_tx = $localtaxes_type[3];
1984 $this->line->localtax1_type = $localtaxes_type[0];
1985 $this->line->localtax2_type = $localtaxes_type[2];
1986
1987 $this->line->total_ttc = $tmp[2];
1988 $this->line->total_ht = $tmp[0];
1989 $this->line->total_tva = $tmp[1];
1990 $this->line->total_localtax1 = $tmp[9];
1991 $this->line->total_localtax2 = $tmp[10];
1992
1993 $this->line->fk_expensereport = $this->id;
1994 $this->line->qty = $qty;
1995 $this->line->date = $date;
1996 $this->line->fk_c_type_fees = $fk_c_type_fees;
1997 $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
1998 $this->line->comments = $comments;
1999 $this->line->fk_projet = $fk_project; // deprecated
2000 $this->line->fk_project = $fk_project;
2001
2002 $this->line->fk_ecm_files = $fk_ecm_files;
2003
2004 $this->applyOffset();
2005 $this->checkRules($type, $seller);
2006
2007 $result = $this->line->insert(0, true);
2008 if ($result > 0) {
2009 $result = $this->update_price(1); // This method is designed to add line from user input so total calculation must be done using 'auto' mode.
2010 if ($result > 0) {
2011 $this->db->commit();
2012 return $this->line->id;
2013 } else {
2014 $this->db->rollback();
2015 return -1;
2016 }
2017 } else {
2018 $this->error = $this->line->error;
2019 dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
2020 $this->db->rollback();
2021 return -2;
2022 }
2023 } else {
2024 dol_syslog(get_class($this)."::addline status of expense report must be Draft to allow use of ->addline()", LOG_ERR);
2025 $this->error = 'ErrorExpenseNotDraftAndNotRefused';
2026 return -3;
2027 }
2028 }
2029
2037 public function checkRules($type = 0, $seller = '')
2038 {
2039 global $conf, $db, $langs, $mysoc;
2040
2041 $langs->load('trips');
2042
2043 // We don't know seller and buyer for expense reports
2044 if (!is_object($seller)) {
2045 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
2046 $seller->tva_assuj = 1; // Most seller uses vat
2047 }
2048
2049 $expensereportrule = new ExpenseReportRule($db);
2050 $rulestocheck = $expensereportrule->getAllRule($this->line->fk_c_type_fees, $this->line->date, $this->fk_user_author);
2051
2052 $violation = 0;
2053 $rule_warning_message_tab = array();
2054
2055 $current_total_ttc = $this->line->total_ttc;
2056 $new_current_total_ttc = $this->line->total_ttc;
2057
2058 // check if one is violated
2059 foreach ($rulestocheck as $rule) {
2060 if (in_array($rule->code_expense_rules_type, array('EX_DAY', 'EX_MON', 'EX_YEA'))) {
2061 $amount_to_test = $this->line->getExpAmount($rule, $this->fk_user_author, $rule->code_expense_rules_type);
2062 } else {
2063 $amount_to_test = $current_total_ttc; // EX_EXP
2064 }
2065
2066 $amount_to_test = $amount_to_test - $current_total_ttc + $new_current_total_ttc; // if amount as been modified by a previous rule
2067
2068 if ($amount_to_test > $rule->amount) {
2069 $violation++;
2070
2071 if ($rule->restrictive) {
2072 $this->error = 'ExpenseReportConstraintViolationError';
2073 $this->errors[] = $this->error;
2074
2075 $new_current_total_ttc -= $amount_to_test - $rule->amount; // ex, entered 16€, limit 12€, subtracts 4€;
2076 $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));
2077 } else {
2078 $this->error = 'ExpenseReportConstraintViolationWarning';
2079 $this->errors[] = $this->error;
2080
2081 $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));
2082 }
2083
2084 // No break, we should test if another rule is violated
2085 }
2086 }
2087
2088 $this->line->rule_warning_message = implode('\n', $rule_warning_message_tab);
2089
2090 if ($violation > 0) {
2091 $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);
2092
2093 $this->line->value_unit = $tmp[5];
2094 $this->line->total_ttc = $tmp[2];
2095 $this->line->total_ht = $tmp[0];
2096 $this->line->total_tva = $tmp[1];
2097 $this->line->total_localtax1 = $tmp[9];
2098 $this->line->total_localtax2 = $tmp[10];
2099
2100 return false;
2101 } else {
2102 return true;
2103 }
2104 }
2105
2113 public function applyOffset($type = 0, $seller = '')
2114 {
2115 global $mysoc;
2116
2117 if (!getDolGlobalString('MAIN_USE_EXPENSE_IK')) {
2118 return false;
2119 }
2120
2121 $userauthor = new User($this->db);
2122 if ($userauthor->fetch($this->fk_user_author) <= 0) {
2123 $this->error = 'ErrorCantFetchUser';
2124 $this->errors[] = 'ErrorCantFetchUser';
2125 return false;
2126 }
2127
2128 // We don't know seller and buyer for expense reports
2129 if (!is_object($seller)) {
2130 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
2131 $seller->tva_assuj = 1; // Most seller uses vat
2132 }
2133
2134 $expenseik = new ExpenseReportIk($this->db);
2135 $range = $expenseik->getRangeByUser($userauthor, $this->line->fk_c_exp_tax_cat);
2136
2137 if (empty($range)) {
2138 $this->error = 'ErrorNoRangeAvailable';
2139 $this->errors[] = 'ErrorNoRangeAvailable';
2140 return false;
2141 }
2142
2143 if (getDolGlobalString('MAIN_EXPENSE_APPLY_ENTIRE_OFFSET')) {
2144 $ikoffset = $range->ikoffset;
2145 } else {
2146 $ikoffset = $range->ikoffset / 12; // The amount of offset is a global value for the year
2147 }
2148
2149 // Test if ikoffset has been applied for the current month
2150 if (!$this->offsetAlreadyGiven()) {
2151 $new_up = $range->coef + ($ikoffset / $this->line->qty);
2152 $tmp = calcul_price_total($this->line->qty, $new_up, 0, $this->line->vatrate, 0, 0, 0, 'TTC', 0, $type, $seller);
2153
2154 $this->line->value_unit = $tmp[5];
2155 $this->line->total_ttc = $tmp[2];
2156 $this->line->total_ht = $tmp[0];
2157 $this->line->total_tva = $tmp[1];
2158 $this->line->total_localtax1 = $tmp[9];
2159 $this->line->total_localtax2 = $tmp[10];
2160
2161 return true;
2162 }
2163
2164 return false;
2165 }
2166
2172 public function offsetAlreadyGiven()
2173 {
2174 $sql = 'SELECT e.rowid FROM '.MAIN_DB_PREFIX.'expensereport e';
2175 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."expensereport_det d ON (e.rowid = d.fk_expensereport)";
2176 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."c_type_fees f ON (d.fk_c_type_fees = f.id AND f.code = 'EX_KME')";
2177 $sql .= " WHERE e.fk_user_author = ".(int) $this->fk_user_author;
2178 $sql .= " AND YEAR(d.date) = '".dol_print_date($this->line->date, '%Y')."' AND MONTH(d.date) = '".dol_print_date($this->line->date, '%m')."'";
2179 if (!empty($this->line->id)) {
2180 $sql .= ' AND d.rowid <> '.((int) $this->line->id);
2181 }
2182
2183 dol_syslog(get_class($this)."::offsetAlreadyGiven");
2184 $resql = $this->db->query($sql);
2185 if ($resql) {
2186 $num = $this->db->num_rows($resql);
2187 if ($num > 0) {
2188 return true;
2189 }
2190 } else {
2191 dol_print_error($this->db);
2192 }
2193
2194 return false;
2195 }
2196
2214 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)
2215 {
2216 global $user, $mysoc;
2217
2218 if ($this->status == self::STATUS_DRAFT || $this->status == self::STATUS_REFUSED) {
2219 $this->db->begin();
2220
2221 $error = 0;
2222 $type = 0; // TODO What if type is service ?
2223
2224 // We don't know seller and buyer for expense reports
2225 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
2226 $seller->tva_assuj = 1; // Most seller uses vat
2227 $seller->localtax1_assuj = $mysoc->localtax1_assuj; // We don't know, we reuse the state of company
2228 $seller->localtax2_assuj = $mysoc->localtax1_assuj; // We don't know, we reuse the state of company
2229 $buyer = new Societe($this->db);
2230
2231 $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller);
2232
2233 // Clean vat code
2234 $reg = array();
2235 $vat_src_code = '';
2236 if (preg_match('/\‍((.*)\‍)/', (string) $vatrate, $reg)) {
2237 $vat_src_code = $reg[1];
2238 $vatrate = preg_replace('/\s*\‍(.*\‍)/', '', (string) $vatrate); // Remove code into vatrate.
2239 }
2240 $vatrate = preg_replace('/\*/', '', $vatrate);
2241
2242 $tmp = calcul_price_total($qty, $value_unit, 0, $vatrate, -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
2243 //var_dump($vatrate);var_dump($localtaxes_type);var_dump($tmp);exit;
2244 // calcul total of line
2245 //$total_ttc = price2num($qty*$value_unit, 'MT');
2246
2247 $tx_tva = 1 + (float) $vatrate / 100;
2248
2249 $this->line = new ExpenseReportLine($this->db);
2250 $this->line->comments = $comments;
2251 $this->line->qty = $qty;
2252 $this->line->value_unit = $value_unit;
2253 $this->line->date = $date;
2254
2255 $this->line->fk_expensereport = $expensereport_id;
2256 $this->line->fk_c_type_fees = $type_fees_id;
2257 $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
2258 $this->line->fk_projet = $projet_id; // deprecated
2259 $this->line->fk_project = $projet_id;
2260
2261 $this->line->vat_src_code = $vat_src_code;
2262 $this->line->vatrate = price2num($vatrate);
2263 $this->line->localtax1_tx = $localtaxes_type[1];
2264 $this->line->localtax2_tx = $localtaxes_type[3];
2265 $this->line->localtax1_type = $localtaxes_type[0];
2266 $this->line->localtax2_type = $localtaxes_type[2];
2267
2268 $this->line->total_ttc = $tmp[2];
2269 $this->line->total_ht = $tmp[0];
2270 $this->line->total_tva = $tmp[1];
2271 $this->line->total_localtax1 = $tmp[9];
2272 $this->line->total_localtax2 = $tmp[10];
2273
2274 $this->line->fk_ecm_files = $fk_ecm_files;
2275
2276 $this->line->id = ((int) $rowid);
2277
2278 // Select des infos sur le type fees
2279 $sql = "SELECT c.code as code_type_fees, c.label as label_type_fees";
2280 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
2281 $sql .= " WHERE c.id = ".((int) $type_fees_id);
2282 $resql = $this->db->query($sql);
2283 if ($resql) {
2284 $objp_fees = $this->db->fetch_object($resql);
2285 $this->line->type_fees_code = $objp_fees->code_type_fees;
2286 $this->line->type_fees_libelle = $objp_fees->label_type_fees;
2287 $this->db->free($resql);
2288 }
2289
2290 // Select des information du projet
2291 $sql = "SELECT p.ref as ref_projet, p.title as title_projet";
2292 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
2293 $sql .= " WHERE p.rowid = ".((int) $projet_id);
2294 $resql = $this->db->query($sql);
2295 if ($resql) {
2296 $objp_projet = $this->db->fetch_object($resql);
2297 $this->line->projet_ref = $objp_projet->ref_projet;
2298 $this->line->projet_title = $objp_projet->title_projet;
2299 $this->db->free($resql);
2300 }
2301
2302 $this->applyOffset();
2303 $this->checkRules();
2304
2305 $result = $this->line->update($user);
2306 if ($result < 0) {
2307 $error++;
2308 }
2309
2310 if (!$error && !$notrigger) {
2311 // Call triggers
2312 $result = $this->call_trigger('EXPENSE_REPORT_DET_MODIFY', $user);
2313 if ($result < 0) {
2314 $error++;
2315 }
2316 // End call triggers
2317 }
2318
2319 if (!$error) {
2320 $this->db->commit();
2321 return 1;
2322 } else {
2323 $this->error = $this->line->error;
2324 $this->errors = $this->line->errors;
2325 $this->db->rollback();
2326 return -2;
2327 }
2328 }
2329
2330 return 0;
2331 }
2332
2341 public function deleteLine($rowid, $fuser = '', $notrigger = 0)
2342 {
2343 $error = 0;
2344
2345 $this->db->begin();
2346
2347 if (!$notrigger) {
2348 // Call triggers
2349 $result = $this->call_trigger('EXPENSE_REPORT_DET_DELETE', $fuser);
2350 if ($result < 0) {
2351 $error++;
2352 }
2353 // End call triggers
2354 }
2355
2356 $sql = ' DELETE FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2357 $sql .= ' WHERE rowid = '.((int) $rowid);
2358
2359 dol_syslog(get_class($this)."::deleteline sql=".$sql);
2360 $result = $this->db->query($sql);
2361
2362 if (!$result || $error > 0) {
2363 $this->error = $this->db->error();
2364 dol_syslog(get_class($this)."::deleteline Error ".$this->error, LOG_ERR);
2365 $this->db->rollback();
2366 return -1;
2367 }
2368
2369 $this->update_price(1);
2370
2371 $this->db->commit();
2372
2373 return 1;
2374 }
2375
2376 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2385 public function periode_existe($fuser, $date_debut, $date_fin)
2386 {
2387 global $conf;
2388
2389 // phpcs:enable
2390 $sql = "SELECT rowid, date_debut, date_fin";
2391 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
2392 $sql .= " WHERE entity = ".((int) $conf->entity); // not shared, only for the current entity
2393 $sql .= " AND fk_user_author = ".((int) $fuser->id);
2394
2395 dol_syslog(get_class($this)."::periode_existe sql=".$sql);
2396 $result = $this->db->query($sql);
2397 if ($result) {
2398 $num_rows = $this->db->num_rows($result);
2399 $i = 0;
2400
2401 if ($num_rows > 0) {
2402 $date_d_form = $date_debut;
2403 $date_f_form = $date_fin;
2404
2405 while ($i < $num_rows) {
2406 $objp = $this->db->fetch_object($result);
2407
2408 $date_d_req = $this->db->jdate($objp->date_debut); // 3
2409 $date_f_req = $this->db->jdate($objp->date_fin); // 4
2410
2411 if (!($date_f_form < $date_d_req || $date_d_form > $date_f_req)) {
2412 return $objp->rowid;
2413 }
2414
2415 $i++;
2416 }
2417
2418 return 0;
2419 } else {
2420 return 0;
2421 }
2422 } else {
2423 $this->error = $this->db->lasterror();
2424 dol_syslog(get_class($this)."::periode_existe Error ".$this->error, LOG_ERR);
2425 return -1;
2426 }
2427 }
2428
2429
2430 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2438 {
2439 // phpcs:enable
2440 $users_validator = array();
2441
2442 $sql = "SELECT DISTINCT ur.fk_user";
2443 $sql .= " FROM ".MAIN_DB_PREFIX."user_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2444 $sql .= " WHERE ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2445 $sql .= " UNION";
2446 $sql .= " SELECT DISTINCT ugu.fk_user";
2447 $sql .= " FROM ".MAIN_DB_PREFIX."usergroup_user as ugu, ".MAIN_DB_PREFIX."usergroup_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2448 $sql .= " WHERE ugu.fk_usergroup = ur.fk_usergroup AND ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2449 //print $sql;
2450
2451 dol_syslog(get_class($this)."::fetch_users_approver_expensereport sql=".$sql);
2452 $result = $this->db->query($sql);
2453 if ($result) {
2454 $num_rows = $this->db->num_rows($result);
2455 $i = 0;
2456 while ($i < $num_rows) {
2457 $objp = $this->db->fetch_object($result);
2458 array_push($users_validator, $objp->fk_user);
2459 $i++;
2460 }
2461 return $users_validator;
2462 } else {
2463 $this->error = $this->db->lasterror();
2464 dol_syslog(get_class($this)."::fetch_users_approver_expensereport Error ".$this->error, LOG_ERR);
2465 return -1;
2466 }
2467 }
2468
2480 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
2481 {
2482 $outputlangs->load("trips");
2483
2484 if (!dol_strlen($modele)) {
2485 if (!empty($this->model_pdf)) {
2486 $modele = $this->model_pdf;
2487 } elseif (getDolGlobalString('EXPENSEREPORT_ADDON_PDF')) {
2488 $modele = getDolGlobalString('EXPENSEREPORT_ADDON_PDF');
2489 }
2490 }
2491
2492 if (!empty($modele)) {
2493 $modelpath = "core/modules/expensereport/doc/";
2494
2495 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2496 } else {
2497 return 0;
2498 }
2499 }
2500
2507 public function listOfTypes($active = 1)
2508 {
2509 global $langs;
2510 $ret = array();
2511 $sql = "SELECT id, code, label";
2512 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees";
2513 $sql .= " WHERE active = ".((int) $active);
2514 dol_syslog(get_class($this)."::listOfTypes", LOG_DEBUG);
2515 $result = $this->db->query($sql);
2516 if ($result) {
2517 $num = $this->db->num_rows($result);
2518 $i = 0;
2519 while ($i < $num) {
2520 $obj = $this->db->fetch_object($result);
2521 $ret[$obj->code] = (($langs->transnoentitiesnoconv($obj->code) != $obj->code) ? $langs->transnoentitiesnoconv($obj->code) : $obj->label);
2522 $i++;
2523 }
2524 } else {
2525 dol_print_error($this->db);
2526 }
2527 return $ret;
2528 }
2529
2535 public function loadStateBoard()
2536 {
2537 global $user;
2538
2539 $this->nb = array();
2540
2541 $sql = "SELECT count(ex.rowid) as nb";
2542 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2543 $sql .= " WHERE ex.fk_statut > 0";
2544 $sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2545 if (!$user->hasRight('expensereport', 'readall')) {
2546 $userchildids = $user->getAllChildIds(1);
2547 $sql .= " AND (ex.fk_user_author IN (".$this->db->sanitize(implode(',', $userchildids)).")";
2548 $sql .= " OR ex.fk_user_validator IN (".$this->db->sanitize(implode(',', $userchildids))."))";
2549 }
2550
2551 $resql = $this->db->query($sql);
2552 if ($resql) {
2553 while ($obj = $this->db->fetch_object($resql)) {
2554 $this->nb["expensereports"] = $obj->nb;
2555 }
2556 $this->db->free($resql);
2557 return 1;
2558 } else {
2559 dol_print_error($this->db);
2560 $this->error = $this->db->error();
2561 return -1;
2562 }
2563 }
2564
2565 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2573 public function load_board($user, $option = 'topay')
2574 {
2575 // phpcs:enable
2576 global $conf, $langs;
2577
2578 if ($user->socid) {
2579 return -1; // protection pour eviter appel par utilisateur externe
2580 }
2581
2582 $now = dol_now();
2583
2584 $sql = "SELECT ex.rowid, ex.date_valid";
2585 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2586 if ($option == 'toapprove') {
2587 $sql .= " WHERE ex.fk_statut = ".self::STATUS_VALIDATED;
2588 } else {
2589 $sql .= " WHERE ex.fk_statut = ".self::STATUS_APPROVED;
2590 }
2591 $sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2592 if (!$user->hasRight('expensereport', 'readall')) {
2593 $userchildids = $user->getAllChildIds(1);
2594 $sql .= " AND (ex.fk_user_author IN (".$this->db->sanitize(implode(',', $userchildids)).")";
2595 $sql .= " OR ex.fk_user_validator IN (".$this->db->sanitize(implode(',', $userchildids))."))";
2596 }
2597
2598 $resql = $this->db->query($sql);
2599 if ($resql) {
2600 $langs->load("trips");
2601
2602 $response = new WorkboardResponse();
2603 if ($option == 'toapprove') {
2604 $response->warning_delay = $conf->expensereport->approve->warning_delay / 60 / 60 / 24;
2605 $response->label = $langs->trans("ExpenseReportsToApprove");
2606 $response->labelShort = $langs->trans("ToApprove");
2607 $response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_VALIDATED;
2608 } else {
2609 $response->warning_delay = $conf->expensereport->payment->warning_delay / 60 / 60 / 24;
2610 $response->label = $langs->trans("ExpenseReportsToPay");
2611 $response->labelShort = $langs->trans("StatusToPay");
2612 $response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_APPROVED;
2613 }
2614 $response->img = img_object('', "trip");
2615
2616 while ($obj = $this->db->fetch_object($resql)) {
2617 $response->nbtodo++;
2618
2619 if ($option == 'toapprove') {
2620 if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->approve->warning_delay)) {
2621 $response->nbtodolate++;
2622 }
2623 } else {
2624 if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->payment->warning_delay)) {
2625 $response->nbtodolate++;
2626 }
2627 }
2628 }
2629
2630 return $response;
2631 } else {
2632 dol_print_error($this->db);
2633 $this->error = $this->db->error();
2634 return -1;
2635 }
2636 }
2637
2644 public function hasDelay($option)
2645 {
2646 global $conf;
2647
2648 // Only valid expenses reports
2649 if ($option == 'toapprove' && $this->status != 2) {
2650 return false;
2651 }
2652 if ($option == 'topay' && $this->status != 5) {
2653 return false;
2654 }
2655
2656 $now = dol_now();
2657 if ($option == 'toapprove') {
2658 return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->approve->warning_delay);
2659 } else {
2660 return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->payment->warning_delay);
2661 }
2662 }
2663
2669 public function getVentilExportCompta()
2670 {
2671 $alreadydispatched = 0;
2672
2673 $type = 'expense_report';
2674
2675 $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);
2676 $resql = $this->db->query($sql);
2677 if ($resql) {
2678 $obj = $this->db->fetch_object($resql);
2679 if ($obj) {
2680 $alreadydispatched = $obj->nb;
2681 }
2682 } else {
2683 $this->error = $this->db->lasterror();
2684 return -1;
2685 }
2686
2687 if ($alreadydispatched) {
2688 return 1;
2689 }
2690 return 0;
2691 }
2692
2698 public function getSumPayments()
2699 {
2700 $table = 'payment_expensereport';
2701 $field = 'fk_expensereport';
2702
2703 $sql = 'SELECT sum(amount) as amount';
2704 $sql .= ' FROM '.MAIN_DB_PREFIX.$table;
2705 $sql .= " WHERE ".$field." = ".((int) $this->id);
2706
2707 dol_syslog(get_class($this)."::getSumPayments", LOG_DEBUG);
2708 $resql = $this->db->query($sql);
2709 if ($resql) {
2710 $obj = $this->db->fetch_object($resql);
2711 $this->db->free($resql);
2712 return (empty($obj->amount) ? 0 : $obj->amount);
2713 } else {
2714 $this->error = $this->db->lasterror();
2715 return -1;
2716 }
2717 }
2718
2727 public function computeTotalKm($fk_cat, $qty, $tva)
2728 {
2729 global $langs, $db, $conf;
2730
2731 $cumulYearQty = 0;
2732 $ranges = array();
2733 $coef = 0;
2734
2735
2736 if ($fk_cat < 0) {
2737 $this->error = $langs->trans('ErrorBadParameterCat');
2738 return -1;
2739 }
2740
2741 if ($qty <= 0) {
2742 $this->error = $langs->trans('ErrorBadParameterQty');
2743 return -1;
2744 }
2745
2746 $currentUser = new User($db);
2747 $currentUser->fetch($this->fk_user);
2748 $currentUser->getrights('expensereport');
2749 //Clean
2750 $qty = (float) price2num($qty);
2751
2752 $sql = " SELECT r.range_ik, t.ikoffset, t.coef";
2753 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport_ik t";
2754 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_exp_tax_range r ON r.rowid = t.fk_range";
2755 $sql .= " WHERE t.fk_c_exp_tax_cat = ".(int) $fk_cat;
2756 $sql .= " ORDER BY r.range_ik ASC";
2757
2758 dol_syslog("expenseReport::computeTotalkm sql=".$sql, LOG_DEBUG);
2759
2760 $result = $this->db->query($sql);
2761
2762 if ($result) {
2763 if ($conf->global->EXPENSEREPORT_CALCULATE_MILEAGE_EXPENSE_COEFFICIENT_ON_CURRENT_YEAR) {
2764 $arrayDate = dol_getdate(dol_now());
2765 $sql = " SELECT count(n.qty) as cumul FROM ".MAIN_DB_PREFIX."expensereport_det n";
2766 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expensereport e ON e.rowid = n.fk_expensereport";
2767 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_type_fees tf ON tf.id = n.fk_c_type_fees";
2768 $sql .= " WHERE e.fk_user_author = ".(int) $this->fk_user_author;
2769 $sql .= " AND YEAR(n.date) = ".(int) $arrayDate['year'];
2770 $sql .= " AND tf.code = 'EX_KME' ";
2771 $sql .= " AND e.fk_statut = ".(int) ExpenseReport::STATUS_VALIDATED;
2772
2773 $resql = $this->db->query($sql);
2774
2775 if ($resql) {
2776 $obj = $this->db->fetch_object($resql);
2777 $cumulYearQty = $obj->cumul;
2778 }
2779
2780 $qty += (float) $cumulYearQty;
2781 }
2782
2783 $num = $this->db->num_rows($result);
2784
2785 if ($num) {
2786 for ($i = 0; $i < $num; $i++) {
2787 $obj = $this->db->fetch_object($result);
2788
2789 $ranges[$i] = $obj;
2790 }
2791
2792
2793 for ($i = 0; $i < $num; $i++) {
2794 if ($i < ($num - 1)) {
2795 if ($qty > $ranges[$i]->range_ik && $qty < $ranges[$i + 1]->range_ik) {
2796 $coef = $ranges[$i]->coef;
2797 $offset = $ranges[$i]->ikoffset;
2798 }
2799 } else {
2800 if ($qty > $ranges[$i]->range_ik) {
2801 $coef = $ranges[$i]->coef;
2802 $offset = $ranges[$i]->ikoffset;
2803 }
2804 }
2805 }
2806 $total_ht = $coef;
2807 return $total_ht;
2808 } else {
2809 $this->error = $langs->trans('TaxUndefinedForThisCategory');
2810 return 0;
2811 }
2812 } else {
2813 $this->error = $this->db->error()." sql=".$sql;
2814
2815 return -1;
2816 }
2817 }
2818
2826 public function getKanbanView($option = '', $arraydata = null)
2827 {
2828 global $langs;
2829
2830 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
2831
2832 $return = '<div class="box-flex-item box-flex-grow-zero">';
2833 $return .= '<div class="info-box info-box-sm">';
2834 $return .= '<span class="info-box-icon bg-infobox-action">';
2835 $return .= img_picto('', $this->picto);
2836 $return .= '</span>';
2837 $return .= '<div class="info-box-content">';
2838 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
2839 if ($selected >= 0) {
2840 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
2841 }
2842 if (array_key_exists('userauthor', $arraydata)) {
2843 $return .= '<br><span class="info-box-label">'.$arraydata['userauthor']->getNomUrl(-1).'</span>';
2844 }
2845 if (property_exists($this, 'date_debut') && property_exists($this, 'date_fin')) {
2846 $return .= '<br><span class="info-box-label">'.dol_print_date($this->date_debut, 'day').'</span>';
2847 $return .= ' <span class="opacitymedium">'.$langs->trans("To").'</span> ';
2848 $return .= '<span class="info-box-label">'.dol_print_date($this->date_fin, 'day').'</span>';
2849 }
2850 if (method_exists($this, 'getLibStatut')) {
2851 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
2852 }
2853 $return .= '</div>';
2854 $return .= '</div>';
2855 $return .= '</div>';
2856 return $return;
2857 }
2858}
2859
2860
2865{
2869 public $db;
2870
2874 public $table_element = 'expensereport_det';
2875
2879 public $error = '';
2880
2884 public $rowid;
2885
2886 public $comments;
2887
2891 public $qty;
2892 public $value_unit;
2893 public $date;
2894
2898 public $dates;
2899
2903 public $fk_c_type_fees;
2904
2908 public $fk_c_exp_tax_cat;
2909
2913 public $fk_projet;
2914
2918 public $fk_expensereport;
2919
2920 public $type_fees_code;
2921 public $type_fees_libelle;
2922 public $type_fees_accountancy_code;
2923
2924 public $projet_ref;
2925 public $projet_title;
2926 public $rang;
2927
2928 public $vatrate;
2929 public $vat_src_code;
2930 public $tva_tx;
2931 public $localtax1_tx;
2932 public $localtax2_tx;
2933 public $localtax1_type;
2934 public $localtax2_type;
2935
2936 public $total_ht;
2937 public $total_tva;
2938 public $total_ttc;
2939 public $total_localtax1;
2940 public $total_localtax2;
2941
2942 // Multicurrency
2946 public $fk_multicurrency;
2947
2951 public $multicurrency_code;
2952 public $multicurrency_tx;
2953 public $multicurrency_total_ht;
2954 public $multicurrency_total_tva;
2955 public $multicurrency_total_ttc;
2956
2960 public $fk_ecm_files;
2961
2962 public $rule_warning_message;
2963
2964
2970 public function __construct($db)
2971 {
2972 $this->db = $db;
2973 }
2974
2981 public function fetch($rowid)
2982 {
2983 $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,';
2984 $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,';
2985 $sql .= ' fde.localtax1_tx, fde.localtax2_tx, fde.localtax1_type, fde.localtax2_type, fde.total_localtax1, fde.total_localtax2, fde.rule_warning_message,';
2986 $sql .= ' ctf.code as type_fees_code, ctf.label as type_fees_libelle,';
2987 $sql .= ' pjt.rowid as projet_id, pjt.title as projet_title, pjt.ref as projet_ref';
2988 $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det as fde';
2989 $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.
2990 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as pjt ON fde.fk_projet=pjt.rowid';
2991 $sql .= ' WHERE fde.rowid = '.((int) $rowid);
2992
2993 $result = $this->db->query($sql);
2994
2995 if ($result) {
2996 $objp = $this->db->fetch_object($result);
2997
2998 $this->rowid = $objp->rowid;
2999 $this->id = $objp->rowid;
3000 $this->ref = $objp->ref;
3001 $this->fk_expensereport = $objp->fk_expensereport;
3002 $this->comments = $objp->comments;
3003 $this->qty = $objp->qty;
3004 $this->date = $objp->date;
3005 $this->dates = $this->db->jdate($objp->date);
3006 $this->value_unit = $objp->value_unit;
3007 $this->fk_c_type_fees = $objp->fk_c_type_fees;
3008 $this->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
3009 $this->fk_projet = $objp->fk_project; // deprecated
3010 $this->fk_project = $objp->fk_project;
3011 $this->type_fees_code = $objp->type_fees_code;
3012 $this->type_fees_libelle = $objp->type_fees_libelle;
3013 $this->projet_ref = $objp->projet_ref;
3014 $this->projet_title = $objp->projet_title;
3015
3016 $this->vatrate = $objp->vatrate;
3017 $this->vat_src_code = $objp->vat_src_code;
3018 $this->localtax1_tx = $objp->localtax1_tx;
3019 $this->localtax2_tx = $objp->localtax2_tx;
3020 $this->localtax1_type = $objp->localtax1_type;
3021 $this->localtax2_type = $objp->localtax2_type;
3022
3023 $this->total_ht = $objp->total_ht;
3024 $this->total_tva = $objp->total_tva;
3025 $this->total_ttc = $objp->total_ttc;
3026 $this->total_localtax1 = $objp->total_localtax1;
3027 $this->total_localtax2 = $objp->total_localtax2;
3028
3029 $this->fk_ecm_files = $objp->fk_ecm_files;
3030
3031 $this->rule_warning_message = $objp->rule_warning_message;
3032
3033 $this->db->free($result);
3034
3035 return $this->id;
3036 } else {
3037 dol_print_error($this->db);
3038 return -1;
3039 }
3040 }
3041
3049 public function insert($notrigger = 0, $fromaddline = false)
3050 {
3051 global $user;
3052
3053 $error = 0;
3054
3055 dol_syslog("ExpenseReportLine::Insert", LOG_DEBUG);
3056
3057 // Clean parameters
3058 $this->comments = trim($this->comments);
3059 if (empty($this->value_unit)) {
3060 $this->value_unit = 0;
3061 }
3062 $this->qty = (float) price2num($this->qty);
3063 $this->vatrate = price2num($this->vatrate);
3064 if (empty($this->fk_c_exp_tax_cat)) {
3065 $this->fk_c_exp_tax_cat = 0;
3066 }
3067
3068 $this->db->begin();
3069
3070 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'expensereport_det';
3071 $sql .= ' (fk_expensereport, fk_c_type_fees, fk_projet,';
3072 $sql .= ' tva_tx, vat_src_code,';
3073 $sql .= ' localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3074 $sql .= ' comments, qty, value_unit,';
3075 $sql .= ' total_ht, total_tva, total_ttc,';
3076 $sql .= ' total_localtax1, total_localtax2,';
3077 $sql .= ' date, rule_warning_message, fk_c_exp_tax_cat, fk_ecm_files)';
3078 $sql .= " VALUES (".$this->db->escape($this->fk_expensereport).",";
3079 $sql .= " ".((int) $this->fk_c_type_fees).",";
3080 $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')).",";
3081 $sql .= " ".((float) $this->vatrate).",";
3082 $sql .= " '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."',";
3083 $sql .= " ".((float) price2num($this->localtax1_tx)).",";
3084 $sql .= " ".((float) price2num($this->localtax2_tx)).",";
3085 $sql .= " '".$this->db->escape($this->localtax1_type)."',";
3086 $sql .= " '".$this->db->escape($this->localtax2_type)."',";
3087 $sql .= " '".$this->db->escape($this->comments)."',";
3088 $sql .= " ".((float) $this->qty).",";
3089 $sql .= " ".((float) $this->value_unit).",";
3090 $sql .= " ".((float) price2num($this->total_ht)).",";
3091 $sql .= " ".((float) price2num($this->total_tva)).",";
3092 $sql .= " ".((float) price2num($this->total_ttc)).",";
3093 $sql .= " ".((float) price2num($this->total_localtax1)).",";
3094 $sql .= " ".((float) price2num($this->total_localtax2)).",";
3095 $sql .= " '".$this->db->idate($this->date)."',";
3096 $sql .= " ".(empty($this->rule_warning_message) ? 'null' : "'".$this->db->escape($this->rule_warning_message)."'").",";
3097 $sql .= " ".((int) $this->fk_c_exp_tax_cat).",";
3098 $sql .= " ".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
3099 $sql .= ")";
3100
3101 $resql = $this->db->query($sql);
3102 if ($resql) {
3103 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'expensereport_det');
3104
3105
3106 if (!$error && !$notrigger) {
3107 // Call triggers
3108 $result = $this->call_trigger('EXPENSE_REPORT_DET_CREATE', $user);
3109 if ($result < 0) {
3110 $error++;
3111 }
3112 // End call triggers
3113 }
3114
3115
3116 if (!$fromaddline) {
3117 $tmpparent = new ExpenseReport($this->db);
3118 $tmpparent->fetch($this->fk_expensereport);
3119 $result = $tmpparent->update_price(1);
3120 if ($result < 0) {
3121 $error++;
3122 $this->error = $tmpparent->error;
3123 $this->errors = $tmpparent->errors;
3124 }
3125 }
3126 } else {
3127 $error++;
3128 }
3129
3130 if (!$error) {
3131 $this->db->commit();
3132 return $this->id;
3133 } else {
3134 $this->error = $this->db->lasterror();
3135 dol_syslog("ExpenseReportLine::insert Error ".$this->error, LOG_ERR);
3136 $this->db->rollback();
3137 return -2;
3138 }
3139 }
3140
3149 public function getExpAmount(ExpenseReportRule $rule, $fk_user, $mode = 'day')
3150 {
3151 $amount = 0;
3152
3153 $sql = 'SELECT SUM(d.total_ttc) as total_amount';
3154 $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det d';
3155 $sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'expensereport e ON (d.fk_expensereport = e.rowid)';
3156 $sql .= ' WHERE e.fk_user_author = '.((int) $fk_user);
3157 if (!empty($this->id)) {
3158 $sql .= ' AND d.rowid <> '.((int) $this->id);
3159 }
3160 $sql .= ' AND d.fk_c_type_fees = '.((int) $rule->fk_c_type_fees);
3161 if ($mode == 'day' || $mode == 'EX_DAY') {
3162 $sql .= " AND d.date = '".dol_print_date($this->date, '%Y-%m-%d')."'";
3163 } elseif ($mode == 'mon' || $mode == 'EX_MON') {
3164 $sql .= " AND DATE_FORMAT(d.date, '%Y-%m') = '".dol_print_date($this->date, '%Y-%m')."'"; // @todo DATE_FORMAT is forbidden
3165 } elseif ($mode == 'year' || $mode == 'EX_YEA') {
3166 $sql .= " AND DATE_FORMAT(d.date, '%Y') = '".dol_print_date($this->date, '%Y')."'"; // @todo DATE_FORMAT is forbidden
3167 }
3168
3169 dol_syslog('ExpenseReportLine::getExpAmount');
3170
3171 $resql = $this->db->query($sql);
3172 if ($resql) {
3173 $num = $this->db->num_rows($resql);
3174 if ($num > 0) {
3175 $obj = $this->db->fetch_object($resql);
3176 $amount = (float) $obj->total_amount;
3177 }
3178 } else {
3179 dol_print_error($this->db);
3180 }
3181
3182 return $amount + $this->total_ttc;
3183 }
3184
3191 public function update(User $user)
3192 {
3193 global $langs;
3194
3195 $error = 0;
3196
3197 // Clean parameters
3198 $this->comments = trim($this->comments);
3199 $this->vatrate = price2num($this->vatrate);
3200 $this->value_unit = price2num($this->value_unit);
3201 if (empty($this->fk_c_exp_tax_cat)) {
3202 $this->fk_c_exp_tax_cat = 0;
3203 }
3204
3205 $this->db->begin();
3206
3207 // Update line in database
3208 $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport_det SET";
3209 $sql .= " comments='".$this->db->escape($this->comments)."'";
3210 $sql .= ", value_unit = ".((float) $this->value_unit);
3211 $sql .= ", qty=".((float) $this->qty);
3212 $sql .= ", date='".$this->db->idate($this->date)."'";
3213 $sql .= ", total_ht=".((float) price2num($this->total_ht, 'MT'));
3214 $sql .= ", total_tva=".((float) price2num($this->total_tva, 'MT'));
3215 $sql .= ", total_ttc=".((float) price2num($this->total_ttc, 'MT'));
3216 $sql .= ", total_localtax1=".((float) price2num($this->total_localtax1, 'MT'));
3217 $sql .= ", total_localtax2=".((float) price2num($this->total_localtax2, 'MT'));
3218 $sql .= ", tva_tx=".((float) $this->vatrate);
3219 $sql .= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
3220 $sql .= ", localtax1_tx=".((float) $this->localtax1_tx);
3221 $sql .= ", localtax2_tx=".((float) $this->localtax2_tx);
3222 $sql .= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
3223 $sql .= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
3224 $sql .= ", rule_warning_message='".$this->db->escape($this->rule_warning_message)."'";
3225 $sql .= ", fk_c_exp_tax_cat=".$this->db->escape($this->fk_c_exp_tax_cat);
3226 $sql .= ", fk_ecm_files=".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
3227 if ($this->fk_c_type_fees) {
3228 $sql .= ", fk_c_type_fees = ".((int) $this->fk_c_type_fees);
3229 } else {
3230 $sql .= ", fk_c_type_fees=null";
3231 }
3232 if ($this->fk_project > 0) {
3233 $sql .= ", fk_projet=".((int) $this->fk_project);
3234 } else {
3235 $sql .= ", fk_projet=null";
3236 }
3237 $sql .= " WHERE rowid = ".((int) ($this->rowid ? $this->rowid : $this->id));
3238
3239 dol_syslog("ExpenseReportLine::update");
3240
3241 $resql = $this->db->query($sql);
3242 if ($resql) {
3243 $tmpparent = new ExpenseReport($this->db);
3244 $result = $tmpparent->fetch($this->fk_expensereport);
3245 if ($result > 0) {
3246 $result = $tmpparent->update_price(1);
3247 if ($result < 0) {
3248 $error++;
3249 $this->error = $tmpparent->error;
3250 $this->errors = $tmpparent->errors;
3251 }
3252 } else {
3253 $error++;
3254 $this->error = $tmpparent->error;
3255 $this->errors = $tmpparent->errors;
3256 }
3257 } else {
3258 $error++;
3259 dol_print_error($this->db);
3260 }
3261
3262 if (!$error) {
3263 $this->db->commit();
3264 return 1;
3265 } else {
3266 $this->error = $this->db->lasterror();
3267 dol_syslog("ExpenseReportLine::update Error ".$this->error, LOG_ERR);
3268 $this->db->rollback();
3269 return -2;
3270 }
3271 }
3272
3273 // ajouter ici comput_ ...
3274}
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:2010