dolibarr 19.0.3
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-2023 Frédéric France <frederic.france@netlogic.fr>
7 * Copyright (C) 2016-2020 Ferran Marcet <fmarcet@2byte.es>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
28require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
29require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
30require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport_ik.class.php';
31require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport_rule.class.php';
32
33
38{
42 public $element = 'expensereport';
43
47 public $table_element = 'expensereport';
48
52 public $table_element_line = 'expensereport_det';
53
57 public $fk_element = 'fk_expensereport';
58
62 public $picto = 'trip';
63
67 public $lines = array();
68
72 public $line;
73
74 public $date_debut;
75
76 public $date_fin;
77
81 public $date_approbation;
82
86 public $fk_user;
87
88 public $user_approve_id;
89
95 public $status;
96
103 public $fk_statut;
104
105 public $fk_c_paiement;
106 public $modepaymentid;
107
108 public $paid;
109
110 public $user_author_infos;
111 public $user_validator_infos;
112
113 public $rule_warning_message;
114
115 // ACTIONS
116
117 // Create
118 public $date_create;
119
123 public $fk_user_creat;
124
128 public $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
129
130 // Update
131 public $date_modif;
132 public $fk_user_modif;
133
134 // Refus
135 public $date_refuse;
136 public $detail_refuse;
137 public $fk_user_refuse;
138
139 // Annulation
140 public $date_cancel;
141 public $detail_cancel;
142
146 public $fk_user_cancel;
147
151 public $fk_user_validator;
152
159 public $datevalid;
160
165 public $date_valid;
166
170 public $fk_user_valid;
171 public $user_valid_infos;
172
173 // Approve
174 public $date_approve;
175 public $fk_user_approve; // User that has approved
176
177 // Paiement
178 public $user_paid_infos;
179
180 public $localtax1; // for backward compatibility (real field should be total_localtax1 defined into CommonObject)
181 public $localtax2; // for backward compatibility (real field should be total_localtax2 defined into CommonObject)
182
183 public $labelStatus = array();
184 public $labelStatusShort = array();
185
186 // Multicurrency
190 public $fk_multicurrency;
191
195 public $multicurrency_code;
196 public $multicurrency_tx;
197 public $multicurrency_total_ht;
198 public $multicurrency_total_tva;
199 public $multicurrency_total_ttc;
200
201
205 const STATUS_DRAFT = 0;
206
211
216
221
225 const STATUS_CLOSED = 6;
226
230 const STATUS_REFUSED = 99;
231
232 public $fields = array(
233 'rowid' =>array('type'=>'integer', 'label'=>'ID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
234 'ref' =>array('type'=>'varchar(50)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>15),
235 'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>20),
236 'ref_number_int' =>array('type'=>'integer', 'label'=>'Ref number int', 'enabled'=>1, 'visible'=>-1, 'position'=>25),
237 'ref_ext' =>array('type'=>'integer', 'label'=>'Ref ext', 'enabled'=>1, 'visible'=>-1, 'position'=>30),
238 'total_ht' =>array('type'=>'double(24,8)', 'label'=>'Total ht', 'enabled'=>1, 'visible'=>-1, 'position'=>35),
239 'total_tva' =>array('type'=>'double(24,8)', 'label'=>'Total tva', 'enabled'=>1, 'visible'=>-1, 'position'=>40),
240 'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
241 'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>-1, 'position'=>50),
242 'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Total ttc', 'enabled'=>1, 'visible'=>-1, 'position'=>55),
243 'date_debut' =>array('type'=>'date', 'label'=>'Date debut', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>60),
244 'date_fin' =>array('type'=>'date', 'label'=>'Date fin', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>65),
245 'date_valid' =>array('type'=>'datetime', 'label'=>'Date valid', 'enabled'=>1, 'visible'=>-1, 'position'=>75),
246 'date_approve' =>array('type'=>'datetime', 'label'=>'Date approve', 'enabled'=>1, 'visible'=>-1, 'position'=>80),
247 'date_refuse' =>array('type'=>'datetime', 'label'=>'Date refuse', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
248 'date_cancel' =>array('type'=>'datetime', 'label'=>'Date cancel', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
249 'fk_user_author' =>array('type'=>'integer', 'label'=>'Fk user author', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>100),
250 'fk_user_modif' =>array('type'=>'integer', 'label'=>'Fk user modif', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
251 'fk_user_valid' =>array('type'=>'integer', 'label'=>'Fk user valid', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
252 'fk_user_validator' =>array('type'=>'integer', 'label'=>'Fk user validator', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
253 'fk_user_approve' =>array('type'=>'integer', 'label'=>'Fk user approve', 'enabled'=>1, 'visible'=>-1, 'position'=>120),
254 'fk_user_refuse' =>array('type'=>'integer', 'label'=>'Fk user refuse', 'enabled'=>1, 'visible'=>-1, 'position'=>125),
255 'fk_user_cancel' =>array('type'=>'integer', 'label'=>'Fk user cancel', 'enabled'=>1, 'visible'=>-1, 'position'=>130),
256 'fk_c_paiement' =>array('type'=>'integer', 'label'=>'Fk c paiement', 'enabled'=>1, 'visible'=>-1, 'position'=>140),
257 'paid' =>array('type'=>'integer', 'label'=>'Paid', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>145),
258 'note_public' =>array('type'=>'html', 'label'=>'Note public', 'enabled'=>1, 'visible'=>0, 'position'=>150),
259 'note_private' =>array('type'=>'html', 'label'=>'Note private', 'enabled'=>1, 'visible'=>0, 'position'=>155),
260 'detail_refuse' =>array('type'=>'varchar(255)', 'label'=>'Detail refuse', 'enabled'=>1, 'visible'=>-1, 'position'=>160),
261 'detail_cancel' =>array('type'=>'varchar(255)', 'label'=>'Detail cancel', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
262 'integration_compta' =>array('type'=>'integer', 'label'=>'Integration compta', 'enabled'=>1, 'visible'=>-1, 'position'=>170),
263 'fk_bank_account' =>array('type'=>'integer', 'label'=>'Fk bank account', 'enabled'=>1, 'visible'=>-1, 'position'=>175),
264 'fk_multicurrency' =>array('type'=>'integer', 'label'=>'Fk multicurrency', 'enabled'=>1, 'visible'=>-1, 'position'=>185),
265 'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'Multicurrency code', 'enabled'=>1, 'visible'=>-1, 'position'=>190),
266 'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency tx', 'enabled'=>1, 'visible'=>-1, 'position'=>195),
267 'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ht', 'enabled'=>1, 'visible'=>-1, 'position'=>200),
268 'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total tva', 'enabled'=>1, 'visible'=>-1, 'position'=>205),
269 'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ttc', 'enabled'=>1, 'visible'=>-1, 'position'=>210),
270 'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>220),
271 'date_create' =>array('type'=>'datetime', 'label'=>'Date create', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>300),
272 'tms' =>array('type'=>'timestamp', 'label'=>'Tms', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>305),
273 'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-1, 'position'=>1000),
274 'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>1010),
275 'fk_statut' =>array('type'=>'integer', 'label'=>'Fk statut', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>500),
276 );
277
283 public function __construct($db)
284 {
285 $this->db = $db;
286 $this->total_ht = 0;
287 $this->total_ttc = 0;
288 $this->total_tva = 0;
289 $this->total_localtax1 = 0;
290 $this->total_localtax2 = 0;
291 $this->localtax1 = 0; // For backward compatibility
292 $this->localtax2 = 0; // For backward compatibility
293 $this->modepaymentid = 0;
294
295 // List of language codes for status
296 $this->labelStatusShort = array(0 => 'Draft', 2 => 'Validated', 4 => 'Canceled', 5 => 'Approved', 6 => 'Paid', 99 => 'Refused');
297 $this->labelStatus = array(0 => 'Draft', 2 => 'ValidatedWaitingApproval', 4 => 'Canceled', 5 => 'Approved', 6 => 'Paid', 99 => 'Refused');
298 }
299
307 public function create($user, $notrigger = 0)
308 {
309 global $conf, $langs;
310
311 $now = dol_now();
312
313 $error = 0;
314
315 // Check parameters
316 if (empty($this->date_debut) || empty($this->date_fin)) {
317 $this->error = $langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Date'));
318 return -1;
319 }
320
321 $fuserid = $this->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
322 if (empty($fuserid)) {
323 $fuserid = $user->id;
324 }
325
326 $this->db->begin();
327
328 $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
329 $sql .= "ref";
330 $sql .= ",total_ht";
331 $sql .= ",total_ttc";
332 $sql .= ",total_tva";
333 $sql .= ",date_debut";
334 $sql .= ",date_fin";
335 $sql .= ",date_create";
336 $sql .= ",fk_user_creat";
337 $sql .= ",fk_user_author";
338 $sql .= ",fk_user_validator";
339 $sql .= ",fk_user_approve";
340 $sql .= ",fk_user_modif";
341 $sql .= ",fk_statut";
342 $sql .= ",fk_c_paiement";
343 $sql .= ",paid";
344 $sql .= ",note_public";
345 $sql .= ",note_private";
346 $sql .= ",entity";
347 $sql .= ") VALUES(";
348 $sql .= "'(PROV)'";
349 $sql .= ", ".price2num($this->total_ht, 'MT');
350 $sql .= ", ".price2num($this->total_ttc, 'MT');
351 $sql .= ", ".price2num($this->total_tva, 'MT');
352 $sql .= ", '".$this->db->idate($this->date_debut)."'";
353 $sql .= ", '".$this->db->idate($this->date_fin)."'";
354 $sql .= ", '".$this->db->idate($now)."'";
355 $sql .= ", ".((int) $user->id);
356 $sql .= ", ".((int) $fuserid);
357 $sql .= ", ".($this->fk_user_validator > 0 ? ((int) $this->fk_user_validator) : "null");
358 $sql .= ", ".($this->fk_user_approve > 0 ? ((int) $this->fk_user_approve) : "null");
359 $sql .= ", ".($this->fk_user_modif > 0 ? ((int) $this->fk_user_modif) : "null");
360 $sql .= ", ".($this->fk_statut > 1 ? ((int) $this->fk_statut) : 0);
361 $sql .= ", ".($this->modepaymentid ? ((int) $this->modepaymentid) : "null");
362 $sql .= ", 0";
363 $sql .= ", ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : "null");
364 $sql .= ", ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "null");
365 $sql .= ", ".((int) $conf->entity);
366 $sql .= ")";
367
368 $result = $this->db->query($sql);
369 if ($result) {
370 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
371 $this->ref = '(PROV'.$this->id.')';
372
373 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".((int) $this->id);
374 $resql = $this->db->query($sql);
375 if (!$resql) {
376 $this->error = $this->db->lasterror();
377 $error++;
378 }
379
380 if (!$error) {
381 if (is_array($this->lines) && count($this->lines) > 0) {
382 foreach ($this->lines as $line) {
383 // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
384 //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
385 if (!is_object($line)) {
386 $line = (object) $line;
387 $newndfline = new ExpenseReportLine($this->db);
388 $newndfline->fk_expensereport = $line->fk_expensereport;
389 $newndfline->fk_c_type_fees = $line->fk_c_type_fees;
390 $newndfline->fk_project = $line->fk_project;
391 $newndfline->vatrate = $line->vatrate;
392 $newndfline->vat_src_code = $line->vat_src_code;
393 $newndfline->localtax1_tx = $line->localtax1_tx;
394 $newndfline->localtax2_tx = $line->localtax2_tx;
395 $newndfline->localtax1_type = $line->localtax1_type;
396 $newndfline->localtax2_type = $line->localtax2_type;
397 $newndfline->comments = $line->comments;
398 $newndfline->qty = $line->qty;
399 $newndfline->value_unit = $line->value_unit;
400 $newndfline->total_ht = $line->total_ht;
401 $newndfline->total_ttc = $line->total_ttc;
402 $newndfline->total_tva = $line->total_tva;
403 $newndfline->total_localtax1 = $line->total_localtax1;
404 $newndfline->total_localtax2 = $line->total_localtax2;
405 $newndfline->date = $line->date;
406 $newndfline->rule_warning_message = $line->rule_warning_message;
407 $newndfline->fk_c_exp_tax_cat = $line->fk_c_exp_tax_cat;
408 $newndfline->fk_ecm_files = $line->fk_ecm_files;
409 } else {
410 $newndfline = $line;
411 }
412 //$newndfline=new ExpenseReportLine($this->db);
413 $newndfline->fk_expensereport = $this->id;
414 $result = $newndfline->insert();
415 if ($result < 0) {
416 $this->error = $newndfline->error;
417 $this->errors = $newndfline->errors;
418 $error++;
419 break;
420 }
421 }
422 }
423 }
424
425 if (!$error) {
426 $result = $this->insertExtraFields();
427 if ($result < 0) {
428 $error++;
429 }
430 }
431
432 if (!$error) {
433 $result = $this->update_price(1);
434 if ($result > 0) {
435 if (!$notrigger) {
436 // Call trigger
437 $result = $this->call_trigger('EXPENSE_REPORT_CREATE', $user);
438
439 if ($result < 0) {
440 $error++;
441 }
442 // End call triggers
443 }
444
445 if (empty($error)) {
446 $this->db->commit();
447 return $this->id;
448 } else {
449 $this->db->rollback();
450 return -4;
451 }
452 } else {
453 $this->db->rollback();
454 return -3;
455 }
456 } else {
457 dol_syslog(get_class($this)."::create error ".$this->error, LOG_ERR);
458 $this->db->rollback();
459 return -2;
460 }
461 } else {
462 $this->error = $this->db->lasterror()." sql=".$sql;
463 $this->db->rollback();
464 return -1;
465 }
466 }
467
475 public function createFromClone(User $user, $fk_user_author)
476 {
477 global $hookmanager;
478
479 $error = 0;
480
481 if (empty($fk_user_author)) {
482 $fk_user_author = $user->id;
483 }
484
485 $this->db->begin();
486
487 // get extrafields so they will be clone
488 //foreach($this->lines as $line)
489 //$line->fetch_optionals();
490
491 // Load source object
492 $objFrom = clone $this;
493
494 $this->id = 0;
495 $this->ref = '';
496 $this->status = 0;
497 $this->fk_statut = 0; // deprecated
498
499 // Clear fields
500 $this->fk_user_creat = $user->id;
501 $this->fk_user_author = $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
502 $this->fk_user_valid = '';
503 $this->date_create = '';
504 $this->date_creation = '';
505 $this->date_validation = '';
506
507 // Remove link on lines to a joined file
508 if (is_array($this->lines) && count($this->lines) > 0) {
509 foreach ($this->lines as $key => $line) {
510 $this->lines[$key]->fk_ecm_files = 0;
511 }
512 }
513
514 // Create clone
515 $this->context['createfromclone'] = 'createfromclone';
516 $result = $this->create($user);
517 if ($result < 0) {
518 $error++;
519 }
520
521 if (!$error) {
522 // Hook of thirdparty module
523 if (is_object($hookmanager)) {
524 $parameters = array('objFrom'=>$objFrom);
525 $action = '';
526 $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
527 if ($reshook < 0) {
528 $this->setErrorsFromObject($hookmanager);
529 $error++;
530 }
531 }
532 }
533
534 unset($this->context['createfromclone']);
535
536 // End
537 if (!$error) {
538 $this->db->commit();
539 return $this->id;
540 } else {
541 $this->db->rollback();
542 return -1;
543 }
544 }
545
546
555 public function update($user, $notrigger = 0, $userofexpensereport = null)
556 {
557 global $langs;
558
559 $error = 0;
560 $this->db->begin();
561
562 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
563 $sql .= " total_ht = ".$this->total_ht;
564 $sql .= " , total_ttc = ".$this->total_ttc;
565 $sql .= " , total_tva = ".$this->total_tva;
566 $sql .= " , date_debut = '".$this->db->idate($this->date_debut)."'";
567 $sql .= " , date_fin = '".$this->db->idate($this->date_fin)."'";
568 if ($userofexpensereport && is_object($userofexpensereport)) {
569 $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.
570 }
571 $sql .= " , fk_user_validator = ".($this->fk_user_validator > 0 ? $this->fk_user_validator : "null");
572 $sql .= " , fk_user_valid = ".($this->fk_user_valid > 0 ? $this->fk_user_valid : "null");
573 $sql .= " , fk_user_approve = ".($this->fk_user_approve > 0 ? $this->fk_user_approve : "null");
574 $sql .= " , fk_user_modif = ".$user->id;
575 $sql .= " , fk_statut = ".($this->fk_statut >= 0 ? $this->fk_statut : '0');
576 $sql .= " , fk_c_paiement = ".($this->fk_c_paiement > 0 ? $this->fk_c_paiement : "null");
577 $sql .= " , note_public = ".(!empty($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "''");
578 $sql .= " , note_private = ".(!empty($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "''");
579 $sql .= " , detail_refuse = ".(!empty($this->detail_refuse) ? "'".$this->db->escape($this->detail_refuse)."'" : "''");
580 $sql .= " WHERE rowid = ".((int) $this->id);
581
582 dol_syslog(get_class($this)."::update", LOG_DEBUG);
583 $result = $this->db->query($sql);
584 if ($result) {
585 if (!$notrigger) {
586 // Call trigger
587 $result = $this->call_trigger('EXPENSE_REPORT_MODIFY', $user);
588
589 if ($result < 0) {
590 $error++;
591 }
592 // End call triggers
593 }
594
595 if (empty($error)) {
596 $this->db->commit();
597 return 1;
598 } else {
599 $this->db->rollback();
600 $this->error = $this->db->error();
601 return -2;
602 }
603 } else {
604 $this->db->rollback();
605 $this->error = $this->db->error();
606 return -1;
607 }
608 }
609
617 public function fetch($id, $ref = '')
618 {
619 global $conf;
620
621 $sql = "SELECT d.rowid, d.entity, d.ref, d.note_public, d.note_private,"; // DEFAULT
622 $sql .= " d.detail_refuse, d.detail_cancel, d.fk_user_refuse, d.fk_user_cancel,"; // ACTIONS
623 $sql .= " d.date_refuse, d.date_cancel,"; // ACTIONS
624 $sql .= " d.total_ht, d.total_ttc, d.total_tva,";
625 $sql .= " d.localtax1 as total_localtax1, d.localtax2 as total_localtax2,";
626 $sql .= " d.date_debut, d.date_fin, d.date_create, d.tms as date_modif, d.date_valid, d.date_approve,"; // DATES (datetime)
627 $sql .= " d.fk_user_creat, d.fk_user_author, d.fk_user_modif, d.fk_user_validator,";
628 $sql .= " d.fk_user_valid, d.fk_user_approve,";
629 $sql .= " d.fk_statut as status, d.fk_c_paiement, d.paid";
630 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as d";
631 if ($ref) {
632 $sql .= " WHERE d.ref = '".$this->db->escape($ref)."'";
633 } else {
634 $sql .= " WHERE d.rowid = ".((int) $id);
635 }
636 //$sql.= $restrict;
637
638 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
639 $resql = $this->db->query($sql);
640 if ($resql) {
641 $obj = $this->db->fetch_object($resql);
642 if ($obj) {
643 $this->id = $obj->rowid;
644 $this->ref = $obj->ref;
645
646 $this->entity = $obj->entity;
647
648 $this->total_ht = $obj->total_ht;
649 $this->total_tva = $obj->total_tva;
650 $this->total_ttc = $obj->total_ttc;
651 $this->localtax1 = $obj->total_localtax1; // For backward compatibility
652 $this->localtax2 = $obj->total_localtax2; // For backward compatibility
653 $this->total_localtax1 = $obj->total_localtax1;
654 $this->total_localtax2 = $obj->total_localtax2;
655
656 $this->note_public = $obj->note_public;
657 $this->note_private = $obj->note_private;
658 $this->detail_refuse = $obj->detail_refuse;
659 $this->detail_cancel = $obj->detail_cancel;
660
661 $this->date_debut = $this->db->jdate($obj->date_debut);
662 $this->date_fin = $this->db->jdate($obj->date_fin);
663 $this->date_valid = $this->db->jdate($obj->date_valid);
664 $this->date_approve = $this->db->jdate($obj->date_approve);
665 $this->date_create = $this->db->jdate($obj->date_create);
666 $this->date_modif = $this->db->jdate($obj->date_modif);
667 $this->date_refuse = $this->db->jdate($obj->date_refuse);
668 $this->date_cancel = $this->db->jdate($obj->date_cancel);
669
670 $this->fk_user_creat = $obj->fk_user_creat;
671 $this->fk_user_author = $obj->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
672 $this->fk_user_modif = $obj->fk_user_modif;
673 $this->fk_user_validator = $obj->fk_user_validator;
674 $this->fk_user_valid = $obj->fk_user_valid;
675 $this->fk_user_refuse = $obj->fk_user_refuse;
676 $this->fk_user_cancel = $obj->fk_user_cancel;
677 $this->fk_user_approve = $obj->fk_user_approve;
678
679 $user_author = new User($this->db);
680 if ($this->fk_user_author > 0) {
681 $user_author->fetch($this->fk_user_author);
682 }
683
684 $this->user_author_infos = dolGetFirstLastname($user_author->firstname, $user_author->lastname);
685
686 $user_approver = new User($this->db);
687 if ($this->fk_user_approve > 0) {
688 $user_approver->fetch($this->fk_user_approve);
689 } elseif ($this->fk_user_validator > 0) {
690 $user_approver->fetch($this->fk_user_validator); // For backward compatibility
691 }
692 $this->user_validator_infos = dolGetFirstLastname($user_approver->firstname, $user_approver->lastname);
693
694 $this->fk_statut = $obj->status; // deprecated
695 $this->status = $obj->status;
696 $this->fk_c_paiement = $obj->fk_c_paiement;
697 $this->paid = $obj->paid;
698
699 if ($this->status == self::STATUS_APPROVED || $this->status == self::STATUS_CLOSED) {
700 $user_valid = new User($this->db);
701 if ($this->fk_user_valid > 0) {
702 $user_valid->fetch($this->fk_user_valid);
703 }
704 $this->user_valid_infos = dolGetFirstLastname($user_valid->firstname, $user_valid->lastname);
705 }
706
707 $this->fetch_optionals();
708
709 $result = $this->fetch_lines();
710
711 return $result;
712 } else {
713 return 0;
714 }
715 } else {
716 $this->error = $this->db->lasterror();
717 return -1;
718 }
719 }
720
721 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
732 public function set_paid($id, $fuser, $notrigger = 0)
733 {
734 // phpcs:enable
735 dol_syslog(get_class($this)."::set_paid is deprecated, use setPaid instead", LOG_NOTICE);
736 return $this->setPaid($id, $fuser, $notrigger);
737 }
738
747 public function setPaid($id, $fuser, $notrigger = 0)
748 {
749 $error = 0;
750 $this->db->begin();
751
752 $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport";
753 $sql .= " SET fk_statut = ".self::STATUS_CLOSED.", paid=1";
754 $sql .= " WHERE rowid = ".((int) $id)." AND fk_statut = ".self::STATUS_APPROVED;
755
756 dol_syslog(get_class($this)."::setPaid", LOG_DEBUG);
757 $resql = $this->db->query($sql);
758 if ($resql) {
759 if ($this->db->affected_rows($resql)) {
760 if (!$notrigger) {
761 // Call trigger
762 $result = $this->call_trigger('EXPENSE_REPORT_PAID', $fuser);
763
764 if ($result < 0) {
765 $error++;
766 }
767 // End call triggers
768 }
769
770 if (empty($error)) {
771 $this->db->commit();
772 return 1;
773 } else {
774 $this->db->rollback();
775 $this->error = $this->db->error();
776 return -2;
777 }
778 } else {
779 $this->db->commit();
780 return 0;
781 }
782 } else {
783 $this->db->rollback();
784 dol_print_error($this->db);
785 return -1;
786 }
787 }
788
795 public function getLibStatut($mode = 0)
796 {
797 return $this->LibStatut($this->status, $mode);
798 }
799
800 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
808 public function LibStatut($status, $mode = 0)
809 {
810 // phpcs:enable
811 global $langs;
812
813 $labelStatus = $langs->transnoentitiesnoconv($this->labelStatus[$status]);
814 $labelStatusShort = $langs->transnoentitiesnoconv($this->labelStatusShort[$status]);
815
816 $statuslogo = array(0 => 'status0', 2 => 'status1', 4 => 'status6', 5 => 'status4', 6 => 'status6', 99 => 'status5');
817
818 $statusType = $statuslogo[$status];
819
820 return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
821 }
822
823
830 public function info($id)
831 {
832 global $conf;
833
834 $sql = "SELECT f.rowid,";
835 $sql .= " f.date_create as datec,";
836 $sql .= " f.tms as date_modification,";
837 $sql .= " f.date_valid as datev,";
838 $sql .= " f.date_approve as datea,";
839 $sql .= " f.fk_user_creat as fk_user_creation,";
840 $sql .= " f.fk_user_author as fk_user_author,";
841 $sql .= " f.fk_user_modif as fk_user_modification,";
842 $sql .= " f.fk_user_valid,";
843 $sql .= " f.fk_user_approve";
844 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as f";
845 $sql .= " WHERE f.rowid = ".((int) $id);
846 $sql .= " AND f.entity = ".$conf->entity;
847
848 $resql = $this->db->query($sql);
849 if ($resql) {
850 if ($this->db->num_rows($resql)) {
851 $obj = $this->db->fetch_object($resql);
852
853 $this->id = $obj->rowid;
854
855 $this->date_creation = $this->db->jdate($obj->datec);
856 $this->date_modification = $this->db->jdate($obj->date_modification);
857 $this->date_validation = $this->db->jdate($obj->datev);
858 $this->date_approbation = $this->db->jdate($obj->datea);
859
860 $this->user_creation_id = $obj->fk_user_author;
861 $this->user_creation_id = $obj->fk_user_creation;
862 $this->user_validation_id = $obj->fk_user_valid;
863 $this->user_modification_id = $obj->fk_user_modification;
864 $this->user_approve_id = $obj->fk_user_approve;
865 }
866 $this->db->free($resql);
867 } else {
868 dol_print_error($this->db);
869 }
870 }
871
872
873
881 public function initAsSpecimen()
882 {
883 global $user, $langs, $conf;
884
885 $now = dol_now();
886
887 // Initialise parametres
888 $this->id = 0;
889 $this->ref = 'SPECIMEN';
890 $this->specimen = 1;
891 $this->entity = 1;
892 $this->date_create = $now;
893 $this->date_debut = $now;
894 $this->date_fin = $now;
895 $this->date_valid = $now;
896 $this->date_approve = $now;
897
898 $type_fees_id = 2; // TF_TRIP
899
900 $this->status = 5;
901 $this->fk_statut = 5;
902
903 $this->fk_user_author = $user->id;
904 $this->fk_user_validator = $user->id;
905 $this->fk_user_valid = $user->id;
906 $this->fk_user_approve = $user->id;
907
908 $this->note_private = 'Private note';
909 $this->note_public = 'SPECIMEN';
910 $nbp = 5;
911 $xnbp = 0;
912 while ($xnbp < $nbp) {
913 $line = new ExpenseReportLine($this->db);
914 $line->comments = $langs->trans("Comment")." ".$xnbp;
915 $line->date = ($now - 3600 * (1 + $xnbp));
916 $line->total_ht = 100;
917 $line->total_tva = 20;
918 $line->total_ttc = 120;
919 $line->qty = 1;
920 $line->vatrate = 20;
921 $line->value_unit = 120;
922 $line->fk_expensereport = 0;
923 $line->type_fees_code = 'TRA';
924 $line->fk_c_type_fees = $type_fees_id;
925
926 $line->projet_ref = 'ABC';
927
928 $this->lines[$xnbp] = $line;
929 $xnbp++;
930
931 $this->total_ht += $line->total_ht;
932 $this->total_tva += $line->total_tva;
933 $this->total_ttc += $line->total_ttc;
934 }
935 }
936
937 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
945 public function fetch_line_by_project($projectid, $user = '')
946 {
947 // phpcs:enable
948 global $conf, $db, $langs;
949
950 $langs->load('trips');
951
952 if ($user->hasRight('expensereport', 'lire')) {
953 $sql = "SELECT de.fk_expensereport, de.date, de.comments, de.total_ht, de.total_ttc";
954 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport_det as de";
955 $sql .= " WHERE de.fk_projet = ".((int) $projectid);
956
957 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
958 $result = $this->db->query($sql);
959 if ($result) {
960 $num = $this->db->num_rows($result);
961 $i = 0;
962 $total_HT = 0;
963 $total_TTC = 0;
964
965 while ($i < $num) {
966 $objp = $this->db->fetch_object($result);
967
968 $sql2 = "SELECT d.rowid, d.fk_user_author, d.ref, d.fk_statut as status";
969 $sql2 .= " FROM ".MAIN_DB_PREFIX."expensereport as d";
970 $sql2 .= " WHERE d.rowid = ".((int) $objp->fk_expensereport);
971
972 $result2 = $this->db->query($sql2);
973 $obj = $this->db->fetch_object($result2);
974
975 $objp->fk_user_author = $obj->fk_user_author;
976 $objp->ref = $obj->ref;
977 $objp->fk_c_expensereport_status = $obj->status;
978 $objp->rowid = $obj->rowid;
979
980 $total_HT = $total_HT + $objp->total_ht;
981 $total_TTC = $total_TTC + $objp->total_ttc;
982 $author = new User($this->db);
983 $author->fetch($objp->fk_user_author);
984
985 print '<tr>';
986 print '<td><a href="'.DOL_URL_ROOT.'/expensereport/card.php?id='.$objp->rowid.'">'.$objp->ref_num.'</a></td>';
987 print '<td class="center">'.dol_print_date($objp->date, 'day').'</td>';
988 print '<td>'.$author->getNomUrl(1).'</td>';
989 print '<td>'.$objp->comments.'</td>';
990 print '<td class="right">'.price($objp->total_ht).'</td>';
991 print '<td class="right">'.price($objp->total_ttc).'</td>';
992 print '<td class="right">';
993
994 switch ($objp->fk_c_expensereport_status) {
995 case 4:
996 print img_picto($langs->trans('StatusOrderCanceled'), 'statut5');
997 break;
998 case 1:
999 print $langs->trans('Draft').' '.img_picto($langs->trans('Draft'), 'statut0');
1000 break;
1001 case 2:
1002 print $langs->trans('TripForValid').' '.img_picto($langs->trans('TripForValid'), 'statut3');
1003 break;
1004 case 5:
1005 print $langs->trans('TripForPaid').' '.img_picto($langs->trans('TripForPaid'), 'statut3');
1006 break;
1007 case 6:
1008 print $langs->trans('TripPaid').' '.img_picto($langs->trans('TripPaid'), 'statut4');
1009 break;
1010 }
1011 /*
1012 if ($status==4) return img_picto($langs->trans('StatusOrderCanceled'),'statut5');
1013 if ($status==1) return img_picto($langs->trans('StatusOrderDraft'),'statut0');
1014 if ($status==2) return img_picto($langs->trans('StatusOrderValidated'),'statut1');
1015 if ($status==2) return img_picto($langs->trans('StatusOrderOnProcess'),'statut3');
1016 if ($status==5) return img_picto($langs->trans('StatusOrderToBill'),'statut4');
1017 if ($status==6) return img_picto($langs->trans('StatusOrderOnProcess'),'statut6');
1018 */
1019 print '</td>';
1020 print '</tr>';
1021
1022 $i++;
1023 }
1024
1025 print '<tr class="liste_total"><td colspan="4">'.$langs->trans("Number").': '.$i.'</td>';
1026 print '<td class="right" width="100">'.$langs->trans("TotalHT").' : '.price($total_HT).'</td>';
1027 print '<td class="right" width="100">'.$langs->trans("TotalTTC").' : '.price($total_TTC).'</td>';
1028 print '<td>&nbsp;</td>';
1029 print '</tr>';
1030 } else {
1031 $this->error = $this->db->lasterror();
1032 return -1;
1033 }
1034 }
1035
1036 return 0;
1037 }
1038
1039 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1045 public function fetch_lines()
1046 {
1047 // phpcs:enable
1048 global $conf;
1049
1050 $this->lines = array();
1051
1052 $sql = ' SELECT de.rowid, de.comments, de.qty, de.value_unit, de.date, de.rang,';
1053 $sql .= " de.".$this->fk_element.", de.fk_c_type_fees, de.fk_c_exp_tax_cat, de.fk_projet as fk_project,";
1054 $sql .= ' de.tva_tx, de.vat_src_code,';
1055 $sql .= ' de.localtax1_tx, de.localtax2_tx, de.localtax1_type, de.localtax2_type,';
1056 $sql .= ' de.fk_ecm_files,';
1057 $sql .= ' de.total_ht, de.total_tva, de.total_ttc,';
1058 $sql .= ' de.total_localtax1, de.total_localtax2, de.rule_warning_message,';
1059 $sql .= ' ctf.code as code_type_fees, ctf.label as label_type_fees, ctf.accountancy_code as accountancy_code_type_fees,';
1060 $sql .= ' p.ref as ref_projet, p.title as title_projet';
1061 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as de';
1062 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_type_fees as ctf ON de.fk_c_type_fees = ctf.id';
1063 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as p ON de.fk_projet = p.rowid';
1064 $sql .= " WHERE de.".$this->fk_element." = ".((int) $this->id);
1065 if (getDolGlobalString('EXPENSEREPORT_LINES_SORTED_BY_ROWID')) {
1066 $sql .= ' ORDER BY de.rang ASC, de.rowid ASC';
1067 } else {
1068 $sql .= ' ORDER BY de.rang ASC, de.date ASC';
1069 }
1070
1071 $resql = $this->db->query($sql);
1072 if ($resql) {
1073 $num = $this->db->num_rows($resql);
1074 $i = 0;
1075 while ($i < $num) {
1076 $objp = $this->db->fetch_object($resql);
1077
1078 $deplig = new ExpenseReportLine($this->db);
1079
1080 $deplig->rowid = $objp->rowid;
1081 $deplig->id = $objp->rowid;
1082 $deplig->comments = $objp->comments;
1083 $deplig->qty = $objp->qty;
1084 $deplig->value_unit = $objp->value_unit;
1085 $deplig->date = $objp->date;
1086 $deplig->dates = $this->db->jdate($objp->date);
1087
1088 $deplig->fk_expensereport = $objp->fk_expensereport;
1089 $deplig->fk_c_type_fees = $objp->fk_c_type_fees;
1090 $deplig->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
1091 $deplig->fk_projet = $objp->fk_project; // deprecated
1092 $deplig->fk_project = $objp->fk_project;
1093 $deplig->fk_ecm_files = $objp->fk_ecm_files;
1094
1095 $deplig->total_ht = $objp->total_ht;
1096 $deplig->total_tva = $objp->total_tva;
1097 $deplig->total_ttc = $objp->total_ttc;
1098 $deplig->total_localtax1 = $objp->total_localtax1;
1099 $deplig->total_localtax2 = $objp->total_localtax2;
1100
1101 $deplig->type_fees_code = empty($objp->code_type_fees) ? 'TF_OTHER' : $objp->code_type_fees;
1102 $deplig->type_fees_libelle = $objp->label_type_fees;
1103 $deplig->type_fees_accountancy_code = $objp->accountancy_code_type_fees;
1104
1105 $deplig->tva_tx = $objp->tva_tx;
1106 $deplig->vatrate = $objp->tva_tx;
1107 $deplig->vat_src_code = $objp->vat_src_code;
1108 $deplig->localtax1_tx = $objp->localtax1_tx;
1109 $deplig->localtax2_tx = $objp->localtax2_tx;
1110 $deplig->localtax1_type = $objp->localtax1_type;
1111 $deplig->localtax2_type = $objp->localtax2_type;
1112
1113 $deplig->projet_ref = $objp->ref_projet;
1114 $deplig->projet_title = $objp->title_projet;
1115
1116 $deplig->rule_warning_message = $objp->rule_warning_message;
1117
1118 $deplig->rang = $objp->rang;
1119
1120 $this->lines[$i] = $deplig;
1121
1122 $i++;
1123 }
1124 $this->db->free($resql);
1125 return 1;
1126 } else {
1127 $this->error = $this->db->lasterror();
1128 dol_syslog(get_class($this)."::fetch_lines: Error ".$this->error, LOG_ERR);
1129 return -3;
1130 }
1131 }
1132
1133
1141 public function delete(User $user = null, $notrigger = false)
1142 {
1143 global $conf;
1144 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1145
1146 $error = 0;
1147
1148 $this->db->begin();
1149
1150 if (!$notrigger) {
1151 // Call trigger
1152 $result = $this->call_trigger('EXPENSE_REPORT_DELETE', $user);
1153 if ($result < 0) {
1154 $error++;
1155 }
1156 // End call triggers
1157 }
1158
1159 // Delete extrafields of lines and lines
1160 if (!$error && !empty($this->table_element_line)) {
1161 $tabletodelete = $this->table_element_line;
1162 //$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).")";
1163 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id);
1164 if (!$this->db->query($sql)) {
1165 $error++;
1166 $this->error = $this->db->lasterror();
1167 $this->errors[] = $this->error;
1168 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1169 }
1170 }
1171
1172 if (!$error) {
1173 // Delete linked object
1174 $res = $this->deleteObjectLinked();
1175 if ($res < 0) {
1176 $error++;
1177 }
1178 }
1179
1180 if (!$error) {
1181 // Delete linked contacts
1182 $res = $this->delete_linked_contact();
1183 if ($res < 0) {
1184 $error++;
1185 }
1186 }
1187
1188 // Removed extrafields of object
1189 if (!$error) {
1190 $result = $this->deleteExtraFields();
1191 if ($result < 0) {
1192 $error++;
1193 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1194 }
1195 }
1196
1197 // Delete main record
1198 if (!$error) {
1199 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".((int) $this->id);
1200 $res = $this->db->query($sql);
1201 if (!$res) {
1202 $error++;
1203 $this->error = $this->db->lasterror();
1204 $this->errors[] = $this->error;
1205 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1206 }
1207 }
1208
1209 // Delete record into ECM index and physically
1210 if (!$error) {
1211 $res = $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
1212 $res = $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive
1213 if (!$res) {
1214 $error++;
1215 }
1216 }
1217
1218 if (!$error) {
1219 // We remove directory
1220 $ref = dol_sanitizeFileName($this->ref);
1221 if ($conf->expensereport->multidir_output[$this->entity] && !empty($this->ref)) {
1222 $dir = $conf->expensereport->multidir_output[$this->entity]."/".$ref;
1223 $file = $dir."/".$ref.".pdf";
1224 if (file_exists($file)) {
1225 dol_delete_preview($this);
1226
1227 if (!dol_delete_file($file, 0, 0, 0, $this)) {
1228 $this->error = 'ErrorFailToDeleteFile';
1229 $this->errors[] = $this->error;
1230 $this->db->rollback();
1231 return 0;
1232 }
1233 }
1234 if (file_exists($dir)) {
1235 $res = @dol_delete_dir_recursive($dir);
1236 if (!$res) {
1237 $this->error = 'ErrorFailToDeleteDir';
1238 $this->errors[] = $this->error;
1239 $this->db->rollback();
1240 return 0;
1241 }
1242 }
1243 }
1244 }
1245
1246 if (!$error) {
1247 dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
1248 $this->db->commit();
1249 return 1;
1250 } else {
1251 $this->db->rollback();
1252 return -1;
1253 }
1254 }
1255
1263 public function setValidate($fuser, $notrigger = 0)
1264 {
1265 global $conf, $langs, $user;
1266
1267 $error = 0;
1268 $now = dol_now();
1269
1270 // Protection
1271 if ($this->status == self::STATUS_VALIDATED) {
1272 dol_syslog(get_class($this)."::valid action abandonned: already validated", LOG_WARNING);
1273 return 0;
1274 }
1275
1276 $this->date_valid = $now; // Required for the getNextNum later.
1277
1278 // Define new ref
1279 if (!$error && (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
1280 $num = $this->getNextNumRef();
1281 } else {
1282 $num = $this->ref;
1283 }
1284 if (empty($num) || $num < 0) {
1285 return -1;
1286 }
1287
1288 $this->newref = dol_sanitizeFileName($num);
1289
1290 $this->db->begin();
1291
1292 // Validate
1293 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1294 $sql .= " SET ref = '".$this->db->escape($num)."',";
1295 $sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
1296 $sql .= " date_valid = '".$this->db->idate($this->date_valid)."',";
1297 $sql .= " fk_user_valid = ".((int) $user->id);
1298 $sql .= " WHERE rowid = ".((int) $this->id);
1299
1300 $resql = $this->db->query($sql);
1301 if ($resql) {
1302 if (!$error && !$notrigger) {
1303 // Call trigger
1304 $result = $this->call_trigger('EXPENSE_REPORT_VALIDATE', $fuser);
1305 if ($result < 0) {
1306 $error++;
1307 }
1308 // End call triggers
1309 }
1310
1311 if (!$error) {
1312 $this->oldref = $this->ref;
1313
1314 // Rename directory if dir was a temporary ref
1315 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
1316 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1317
1318 // Now we rename also files into index
1319 $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)."'";
1320 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'expensereport/".$this->db->escape($this->ref)."' AND entity = ".((int) $this->entity);
1321 $resql = $this->db->query($sql);
1322 if (!$resql) {
1323 $error++;
1324 $this->error = $this->db->lasterror();
1325 }
1326 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'expensereport/".$this->db->escape($this->newref)."'";
1327 $sql .= " WHERE filepath = 'expensereport/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1328 $resql = $this->db->query($sql);
1329 if (!$resql) {
1330 $error++;
1331 $this->error = $this->db->lasterror();
1332 }
1333
1334 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1335 $oldref = dol_sanitizeFileName($this->ref);
1336 $newref = dol_sanitizeFileName($num);
1337 $dirsource = $conf->expensereport->multidir_output[$this->entity].'/'.$oldref;
1338 $dirdest = $conf->expensereport->multidir_output[$this->entity].'/'.$newref;
1339 if (!$error && file_exists($dirsource)) {
1340 dol_syslog(get_class($this)."::setValidate() rename dir ".$dirsource." into ".$dirdest);
1341
1342 if (@rename($dirsource, $dirdest)) {
1343 dol_syslog("Rename ok");
1344 // Rename docs starting with $oldref with $newref
1345 $listoffiles = dol_dir_list($dirdest, 'files', 1, '^'.preg_quote($oldref, '/'));
1346 foreach ($listoffiles as $fileentry) {
1347 $dirsource = $fileentry['name'];
1348 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1349 $dirsource = $fileentry['path'].'/'.$dirsource;
1350 $dirdest = $fileentry['path'].'/'.$dirdest;
1351 @rename($dirsource, $dirdest);
1352 }
1353 }
1354 }
1355 }
1356 }
1357
1358 // Set new ref and current status
1359 if (!$error) {
1360 $this->ref = $num;
1362 }
1363
1364 if (empty($error)) {
1365 $this->db->commit();
1366 return 1;
1367 } else {
1368 $this->db->rollback();
1369 $this->error = $this->db->error();
1370 return -2;
1371 }
1372 } else {
1373 $this->db->rollback();
1374 $this->error = $this->db->lasterror();
1375 return -1;
1376 }
1377 }
1378
1379 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1386 public function set_save_from_refuse($fuser)
1387 {
1388 // phpcs:enable
1389 // Sélection de la date de début de la NDF
1390 $sql = 'SELECT date_debut';
1391 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
1392 $sql .= " WHERE rowid = ".((int) $this->id);
1393
1394 $result = $this->db->query($sql);
1395
1396 $objp = $this->db->fetch_object($result);
1397
1398 $this->date_debut = $this->db->jdate($objp->date_debut);
1399
1400 if ($this->status != self::STATUS_VALIDATED) {
1401 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1402 $sql .= " SET fk_statut = ".self::STATUS_VALIDATED;
1403 $sql .= " WHERE rowid = ".((int) $this->id);
1404
1405 dol_syslog(get_class($this)."::set_save_from_refuse", LOG_DEBUG);
1406
1407 if ($this->db->query($sql)) {
1408 return 1;
1409 } else {
1410 $this->error = $this->db->lasterror();
1411 return -1;
1412 }
1413 } else {
1414 dol_syslog(get_class($this)."::set_save_from_refuse expensereport already with save status", LOG_WARNING);
1415 }
1416
1417 return 0;
1418 }
1419
1427 public function setApproved($fuser, $notrigger = 0)
1428 {
1429 $now = dol_now();
1430 $error = 0;
1431
1432 // date approval
1433 $this->date_approve = $now;
1434 if ($this->status != self::STATUS_APPROVED) {
1435 $this->db->begin();
1436
1437 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1438 $sql .= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = ".self::STATUS_APPROVED.", fk_user_approve = ".((int) $fuser->id).",";
1439 $sql .= " date_approve='".$this->db->idate($this->date_approve)."'";
1440 $sql .= " WHERE rowid = ".((int) $this->id);
1441 if ($this->db->query($sql)) {
1442 if (!$notrigger) {
1443 // Call trigger
1444 $result = $this->call_trigger('EXPENSE_REPORT_APPROVE', $fuser);
1445
1446 if ($result < 0) {
1447 $error++;
1448 }
1449 // End call triggers
1450 }
1451
1452 if (empty($error)) {
1453 $this->db->commit();
1454 return 1;
1455 } else {
1456 $this->db->rollback();
1457 $this->error = $this->db->error();
1458 return -2;
1459 }
1460 } else {
1461 $this->db->rollback();
1462 $this->error = $this->db->lasterror();
1463 return -1;
1464 }
1465 } else {
1466 dol_syslog(get_class($this)."::setApproved expensereport already with approve status", LOG_WARNING);
1467 }
1468
1469 return 0;
1470 }
1471
1480 public function setDeny($fuser, $details, $notrigger = 0)
1481 {
1482 $now = dol_now();
1483 $error = 0;
1484
1485 // date de refus
1486 if ($this->status != self::STATUS_REFUSED) {
1487 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1488 $sql .= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = ".self::STATUS_REFUSED.", fk_user_refuse = ".((int) $fuser->id).",";
1489 $sql .= " date_refuse='".$this->db->idate($now)."',";
1490 $sql .= " detail_refuse='".$this->db->escape($details)."',";
1491 $sql .= " fk_user_approve = NULL";
1492 $sql .= " WHERE rowid = ".((int) $this->id);
1493 if ($this->db->query($sql)) {
1494 $this->fk_statut = 99; // deprecated
1495 $this->status = 99;
1496 $this->fk_user_refuse = $fuser->id;
1497 $this->detail_refuse = $details;
1498 $this->date_refuse = $now;
1499
1500 if (!$notrigger) {
1501 // Call trigger
1502 $result = $this->call_trigger('EXPENSE_REPORT_DENY', $fuser);
1503
1504 if ($result < 0) {
1505 $error++;
1506 }
1507 // End call triggers
1508 }
1509
1510 if (empty($error)) {
1511 $this->db->commit();
1512 return 1;
1513 } else {
1514 $this->db->rollback();
1515 $this->error = $this->db->error();
1516 return -2;
1517 }
1518 } else {
1519 $this->db->rollback();
1520 $this->error = $this->db->lasterror();
1521 return -1;
1522 }
1523 } else {
1524 dol_syslog(get_class($this)."::setDeny expensereport already with refuse status", LOG_WARNING);
1525 }
1526
1527 return 0;
1528 }
1529
1530 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1540 public function set_unpaid($fuser, $notrigger = 0)
1541 {
1542 // phpcs:enable
1543 dol_syslog(get_class($this)."::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE);
1544 return $this->setUnpaid($fuser, $notrigger);
1545 }
1546
1554 public function setUnpaid($fuser, $notrigger = 0)
1555 {
1556 $error = 0;
1557
1558 if ($this->paid) {
1559 $this->db->begin();
1560
1561 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1562 $sql .= " SET paid = 0, fk_statut = ".self::STATUS_APPROVED;
1563 $sql .= " WHERE rowid = ".((int) $this->id);
1564
1565 dol_syslog(get_class($this)."::set_unpaid", LOG_DEBUG);
1566
1567 if ($this->db->query($sql)) {
1568 if (!$notrigger) {
1569 // Call trigger
1570 $result = $this->call_trigger('EXPENSE_REPORT_UNPAID', $fuser);
1571
1572 if ($result < 0) {
1573 $error++;
1574 }
1575 // End call triggers
1576 }
1577
1578 if (empty($error)) {
1579 $this->db->commit();
1580 return 1;
1581 } else {
1582 $this->db->rollback();
1583 $this->error = $this->db->error();
1584 return -2;
1585 }
1586 } else {
1587 $this->db->rollback();
1588 $this->error = $this->db->error();
1589 return -1;
1590 }
1591 } else {
1592 dol_syslog(get_class($this)."::set_unpaid expensereport already with unpaid status", LOG_WARNING);
1593 }
1594
1595 return 0;
1596 }
1597
1598 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1607 public function set_cancel($fuser, $detail, $notrigger = 0)
1608 {
1609 // phpcs:enable
1610 $error = 0;
1611 $this->date_cancel = $this->db->idate(dol_now());
1612 if ($this->status != self::STATUS_CANCELED) {
1613 $this->db->begin();
1614
1615 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1616 $sql .= " SET fk_statut = ".self::STATUS_CANCELED.", fk_user_cancel = ".((int) $fuser->id);
1617 $sql .= ", date_cancel='".$this->db->idate($this->date_cancel)."'";
1618 $sql .= ", detail_cancel='".$this->db->escape($detail)."'";
1619 $sql .= " WHERE rowid = ".((int) $this->id);
1620
1621 dol_syslog(get_class($this)."::set_cancel", LOG_DEBUG);
1622
1623 if ($this->db->query($sql)) {
1624 if (!$notrigger) {
1625 // Call trigger
1626 $result = $this->call_trigger('EXPENSE_REPORT_CANCEL', $fuser);
1627
1628 if ($result < 0) {
1629 $error++;
1630 }
1631 // End call triggers
1632 }
1633
1634 if (empty($error)) {
1635 $this->db->commit();
1636 return 1;
1637 } else {
1638 $this->db->rollback();
1639 $this->error = $this->db->error();
1640 return -2;
1641 }
1642 } else {
1643 $this->db->rollback();
1644 $this->error = $this->db->error();
1645 return -1;
1646 }
1647 } else {
1648 dol_syslog(get_class($this)."::set_cancel expensereport already with cancel status", LOG_WARNING);
1649 }
1650 return 0;
1651 }
1652
1658 public function getNextNumRef()
1659 {
1660 global $langs, $conf;
1661 $langs->load("trips");
1662
1663 if (getDolGlobalString('EXPENSEREPORT_ADDON')) {
1664 $mybool = false;
1665
1666 $file = getDolGlobalString('EXPENSEREPORT_ADDON') . ".php";
1667 $classname = $conf->global->EXPENSEREPORT_ADDON;
1668
1669 // Include file with class
1670 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1671 foreach ($dirmodels as $reldir) {
1672 $dir = dol_buildpath($reldir."core/modules/expensereport/");
1673
1674 // Load file with numbering class (if found)
1675 $mybool |= @include_once $dir.$file;
1676 }
1677
1678 if ($mybool === false) {
1679 dol_print_error('', "Failed to include file ".$file);
1680 return '';
1681 }
1682
1683 $obj = new $classname();
1684 $numref = $obj->getNextValue($this);
1685
1686 if ($numref != "") {
1687 return $numref;
1688 } else {
1689 $this->error = $obj->error;
1690 $this->errors = $obj->errors;
1691 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1692 return -1;
1693 }
1694 } else {
1695 $this->error = "Error_EXPENSEREPORT_ADDON_NotDefined";
1696 return -2;
1697 }
1698 }
1699
1707 public function getTooltipContentArray($params)
1708 {
1709 global $conf, $langs;
1710
1711 $langs->load('expensereport');
1712
1713 $nofetch = !empty($params['nofetch']);
1714 $moretitle = $params['moretitle'] ?? '';
1715
1716 $datas = array();
1717 $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("ExpenseReport").'</u>';
1718 if (isset($this->status)) {
1719 $datas['picto'] .= ' '.$this->getLibStatut(5);
1720 }
1721 if ($moretitle) {
1722 $datas['picto'] .= ' - '.$moretitle;
1723 }
1724 if (!empty($this->ref)) {
1725 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1726 }
1727 if (!empty($this->total_ht)) {
1728 $datas['total_ht'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
1729 }
1730 if (!empty($this->total_tva)) {
1731 $datas['total_tva'] = '<br><b>'.$langs->trans('VAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
1732 }
1733 if (!empty($this->total_ttc)) {
1734 $datas['total_ttc'] = '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
1735 }
1736
1737 return $datas;
1738 }
1739
1752 public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1)
1753 {
1754 global $langs, $conf, $hookmanager;
1755
1756 $result = '';
1757
1758 $url = DOL_URL_ROOT.'/expensereport/card.php?id='.$this->id;
1759
1760 if ($short) {
1761 return $url;
1762 }
1763
1764 $params = [
1765 'id' => $this->id,
1766 'objecttype' => $this->element,
1767 'option' => $option,
1768 'moretitle' => $moretitle,
1769 'nofetch' => 1,
1770 ];
1771 $classfortooltip = 'classfortooltip';
1772 $dataparams = '';
1773 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1774 $classfortooltip = 'classforajaxtooltip';
1775 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1776 $label = '';
1777 } else {
1778 $label = implode($this->getTooltipContentArray($params));
1779 }
1780
1781 if ($option != 'nolink') {
1782 // Add param to save lastsearch_values or not
1783 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1784 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1785 $add_save_lastsearch_values = 1;
1786 }
1787 if ($add_save_lastsearch_values) {
1788 $url .= '&save_lastsearch_values=1';
1789 }
1790 }
1791
1792 $ref = $this->ref;
1793 if (empty($ref)) {
1794 $ref = $this->id;
1795 }
1796
1797 $linkclose = '';
1798 if (empty($notooltip)) {
1799 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1800 $label = $langs->trans("ShowExpenseReport");
1801 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1802 }
1803 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1804 $linkclose .= $dataparams.' class="'.$classfortooltip.'"';
1805 }
1806
1807 $linkstart = '<a href="'.$url.'"';
1808 $linkstart .= $linkclose.'>';
1809 $linkend = '</a>';
1810
1811 $result .= $linkstart;
1812 if ($withpicto) {
1813 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'"'), 0, 0, $notooltip ? 0 : 1);
1814 }
1815 if ($withpicto != 2) {
1816 $result .= ($max ? dol_trunc($ref, $max) : $ref);
1817 }
1818 $result .= $linkend;
1819
1820 global $action;
1821 $hookmanager->initHooks(array($this->element . 'dao'));
1822 $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1823 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1824 if ($reshook > 0) {
1825 $result = $hookmanager->resPrint;
1826 } else {
1827 $result .= $hookmanager->resPrint;
1828 }
1829 return $result;
1830 }
1831
1832 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1840 public function update_totaux_add($ligne_total_ht, $ligne_total_tva)
1841 {
1842 // phpcs:enable
1843 $this->total_ht = $this->total_ht + $ligne_total_ht;
1844 $this->total_tva = $this->total_tva + $ligne_total_tva;
1845 $this->total_ttc = $this->total_ht + $this->total_tva;
1846
1847 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
1848 $sql .= " total_ht = ".$this->total_ht;
1849 $sql .= " , total_ttc = ".$this->total_ttc;
1850 $sql .= " , total_tva = ".$this->total_tva;
1851 $sql .= " WHERE rowid = ".((int) $this->id);
1852
1853 $result = $this->db->query($sql);
1854 if ($result) {
1855 return 1;
1856 } else {
1857 $this->error = $this->db->error();
1858 return -1;
1859 }
1860 }
1861
1877 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)
1878 {
1879 global $conf, $langs, $mysoc;
1880
1881 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);
1882
1883 if ($this->status == self::STATUS_DRAFT) {
1884 if (empty($qty)) {
1885 $qty = 0;
1886 }
1887 if (empty($fk_c_type_fees) || $fk_c_type_fees < 0) {
1888 $fk_c_type_fees = 0;
1889 }
1890 if (empty($fk_c_exp_tax_cat) || $fk_c_exp_tax_cat < 0) {
1891 $fk_c_exp_tax_cat = 0;
1892 }
1893 if (empty($vatrate) || $vatrate < 0) {
1894 $vatrate = 0;
1895 }
1896 if (empty($date)) {
1897 $date = '';
1898 }
1899 if (empty($fk_project)) {
1900 $fk_project = 0;
1901 }
1902
1903 $qty = price2num($qty);
1904 if (!preg_match('/\s*\‍((.*)\‍)/', $vatrate)) {
1905 $vatrate = price2num($vatrate); // $txtva can have format '5.0 (XXX)' or '5'
1906 }
1907 $up = price2num($up);
1908
1909 $this->db->begin();
1910
1911 $this->line = new ExpenseReportLine($this->db);
1912
1913 // We don't know seller and buyer for expense reports
1914 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
1915 $seller->tva_assuj = 1; // Most seller uses vat
1916 $buyer = new Societe($this->db);
1917
1918 $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller);
1919
1920 $vat_src_code = '';
1921 $reg = array();
1922 if (preg_match('/\s*\‍((.*)\‍)/', $vatrate, $reg)) {
1923 $vat_src_code = $reg[1];
1924 $vatrate = preg_replace('/\s*\‍(.*\‍)/', '', $vatrate); // Remove code into vatrate.
1925 }
1926 $vatrate = preg_replace('/\*/', '', $vatrate);
1927
1928 $tmp = calcul_price_total($qty, $up, 0, $vatrate, -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
1929
1930 $this->line->value_unit = $up;
1931
1932 $this->line->vat_src_code = $vat_src_code;
1933 $this->line->vatrate = price2num($vatrate);
1934 $this->line->localtax1_tx = $localtaxes_type[1];
1935 $this->line->localtax2_tx = $localtaxes_type[3];
1936 $this->line->localtax1_type = $localtaxes_type[0];
1937 $this->line->localtax2_type = $localtaxes_type[2];
1938
1939 $this->line->total_ttc = $tmp[2];
1940 $this->line->total_ht = $tmp[0];
1941 $this->line->total_tva = $tmp[1];
1942 $this->line->total_localtax1 = $tmp[9];
1943 $this->line->total_localtax2 = $tmp[10];
1944
1945 $this->line->fk_expensereport = $this->id;
1946 $this->line->qty = $qty;
1947 $this->line->date = $date;
1948 $this->line->fk_c_type_fees = $fk_c_type_fees;
1949 $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
1950 $this->line->comments = $comments;
1951 $this->line->fk_projet = $fk_project; // deprecated
1952 $this->line->fk_project = $fk_project;
1953
1954 $this->line->fk_ecm_files = $fk_ecm_files;
1955
1956 $this->applyOffset();
1957 $this->checkRules($type, $seller);
1958
1959 $result = $this->line->insert(0, true);
1960 if ($result > 0) {
1961 $result = $this->update_price(1); // This method is designed to add line from user input so total calculation must be done using 'auto' mode.
1962 if ($result > 0) {
1963 $this->db->commit();
1964 return $this->line->id;
1965 } else {
1966 $this->db->rollback();
1967 return -1;
1968 }
1969 } else {
1970 $this->error = $this->line->error;
1971 dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1972 $this->db->rollback();
1973 return -2;
1974 }
1975 } else {
1976 dol_syslog(get_class($this)."::addline status of expense report must be Draft to allow use of ->addline()", LOG_ERR);
1977 $this->error = 'ErrorExpenseNotDraft';
1978 return -3;
1979 }
1980 }
1981
1989 public function checkRules($type = 0, $seller = '')
1990 {
1991 global $user, $conf, $db, $langs, $mysoc;
1992
1993 $langs->load('trips');
1994
1995 // We don't know seller and buyer for expense reports
1996 if (!is_object($seller)) {
1997 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
1998 $seller->tva_assuj = 1; // Most seller uses vat
1999 }
2000
2001 $expensereportrule = new ExpenseReportRule($db);
2002 $rulestocheck = $expensereportrule->getAllRule($this->line->fk_c_type_fees, $this->line->date, $this->fk_user_author);
2003
2004 $violation = 0;
2005 $rule_warning_message_tab = array();
2006
2007 $current_total_ttc = $this->line->total_ttc;
2008 $new_current_total_ttc = $this->line->total_ttc;
2009
2010 // check if one is violated
2011 foreach ($rulestocheck as $rule) {
2012 if (in_array($rule->code_expense_rules_type, array('EX_DAY', 'EX_MON', 'EX_YEA'))) {
2013 $amount_to_test = $this->line->getExpAmount($rule, $this->fk_user_author, $rule->code_expense_rules_type);
2014 } else {
2015 $amount_to_test = $current_total_ttc; // EX_EXP
2016 }
2017
2018 $amount_to_test = $amount_to_test - $current_total_ttc + $new_current_total_ttc; // if amount as been modified by a previous rule
2019
2020 if ($amount_to_test > $rule->amount) {
2021 $violation++;
2022
2023 if ($rule->restrictive) {
2024 $this->error = 'ExpenseReportConstraintViolationError';
2025 $this->errors[] = $this->error;
2026
2027 $new_current_total_ttc -= $amount_to_test - $rule->amount; // ex, entered 16€, limit 12€, subtracts 4€;
2028 $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));
2029 } else {
2030 $this->error = 'ExpenseReportConstraintViolationWarning';
2031 $this->errors[] = $this->error;
2032
2033 $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));
2034 }
2035
2036 // No break, we sould test if another rule is violated
2037 }
2038 }
2039
2040 $this->line->rule_warning_message = implode('\n', $rule_warning_message_tab);
2041
2042 if ($violation > 0) {
2043 $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);
2044
2045 $this->line->value_unit = $tmp[5];
2046 $this->line->total_ttc = $tmp[2];
2047 $this->line->total_ht = $tmp[0];
2048 $this->line->total_tva = $tmp[1];
2049 $this->line->total_localtax1 = $tmp[9];
2050 $this->line->total_localtax2 = $tmp[10];
2051
2052 return false;
2053 } else {
2054 return true;
2055 }
2056 }
2057
2065 public function applyOffset($type = 0, $seller = '')
2066 {
2067 global $conf, $mysoc;
2068
2069 if (!getDolGlobalString('MAIN_USE_EXPENSE_IK')) {
2070 return false;
2071 }
2072
2073 $userauthor = new User($this->db);
2074 if ($userauthor->fetch($this->fk_user_author) <= 0) {
2075 $this->error = 'ErrorCantFetchUser';
2076 $this->errors[] = 'ErrorCantFetchUser';
2077 return false;
2078 }
2079
2080 // We don't know seller and buyer for expense reports
2081 if (!is_object($seller)) {
2082 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
2083 $seller->tva_assuj = 1; // Most seller uses vat
2084 }
2085
2086 $expenseik = new ExpenseReportIk($this->db);
2087 $range = $expenseik->getRangeByUser($userauthor, $this->line->fk_c_exp_tax_cat);
2088
2089 if (empty($range)) {
2090 $this->error = 'ErrorNoRangeAvailable';
2091 $this->errors[] = 'ErrorNoRangeAvailable';
2092 return false;
2093 }
2094
2095 if (getDolGlobalString('MAIN_EXPENSE_APPLY_ENTIRE_OFFSET')) {
2096 $ikoffset = $range->ikoffset;
2097 } else {
2098 $ikoffset = $range->ikoffset / 12; // The amount of offset is a global value for the year
2099 }
2100
2101 // Test if ikoffset has been applied for the current month
2102 if (!$this->offsetAlreadyGiven()) {
2103 $new_up = $range->coef + ($ikoffset / $this->line->qty);
2104 $tmp = calcul_price_total($this->line->qty, $new_up, 0, $this->line->vatrate, 0, 0, 0, 'TTC', 0, $type, $seller);
2105
2106 $this->line->value_unit = $tmp[5];
2107 $this->line->total_ttc = $tmp[2];
2108 $this->line->total_ht = $tmp[0];
2109 $this->line->total_tva = $tmp[1];
2110 $this->line->total_localtax1 = $tmp[9];
2111 $this->line->total_localtax2 = $tmp[10];
2112
2113 return true;
2114 }
2115
2116 return false;
2117 }
2118
2124 public function offsetAlreadyGiven()
2125 {
2126 $sql = 'SELECT e.rowid FROM '.MAIN_DB_PREFIX.'expensereport e';
2127 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."expensereport_det d ON (e.rowid = d.fk_expensereport)";
2128 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."c_type_fees f ON (d.fk_c_type_fees = f.id AND f.code = 'EX_KME')";
2129 $sql .= " WHERE e.fk_user_author = ".(int) $this->fk_user_author;
2130 $sql .= " AND YEAR(d.date) = '".dol_print_date($this->line->date, '%Y')."' AND MONTH(d.date) = '".dol_print_date($this->line->date, '%m')."'";
2131 if (!empty($this->line->id)) {
2132 $sql .= ' AND d.rowid <> '.((int) $this->line->id);
2133 }
2134
2135 dol_syslog(get_class($this)."::offsetAlreadyGiven");
2136 $resql = $this->db->query($sql);
2137 if ($resql) {
2138 $num = $this->db->num_rows($resql);
2139 if ($num > 0) {
2140 return true;
2141 }
2142 } else {
2143 dol_print_error($this->db);
2144 }
2145
2146 return false;
2147 }
2148
2166 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)
2167 {
2168 global $user, $mysoc;
2169
2170 if ($this->status == self::STATUS_DRAFT || $this->status == self::STATUS_REFUSED) {
2171 $this->db->begin();
2172
2173 $error = 0;
2174 $type = 0; // TODO What if type is service ?
2175
2176 // We don't know seller and buyer for expense reports
2177 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
2178 $seller->tva_assuj = 1; // Most seller uses vat
2179 $seller->localtax1_assuj = $mysoc->localtax1_assuj; // We don't know, we reuse the state of company
2180 $seller->localtax2_assuj = $mysoc->localtax1_assuj; // We don't know, we reuse the state of company
2181 $buyer = new Societe($this->db);
2182
2183 $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller);
2184
2185 // Clean vat code
2186 $reg = array();
2187 $vat_src_code = '';
2188 if (preg_match('/\‍((.*)\‍)/', $vatrate, $reg)) {
2189 $vat_src_code = $reg[1];
2190 $vatrate = preg_replace('/\s*\‍(.*\‍)/', '', $vatrate); // Remove code into vatrate.
2191 }
2192 $vatrate = preg_replace('/\*/', '', $vatrate);
2193
2194 $tmp = calcul_price_total($qty, $value_unit, 0, $vatrate, -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
2195 //var_dump($vatrate);var_dump($localtaxes_type);var_dump($tmp);exit;
2196 // calcul total of line
2197 //$total_ttc = price2num($qty*$value_unit, 'MT');
2198
2199 $tx_tva = $vatrate / 100;
2200 $tx_tva = $tx_tva + 1;
2201
2202 $this->line = new ExpenseReportLine($this->db);
2203 $this->line->comments = $comments;
2204 $this->line->qty = $qty;
2205 $this->line->value_unit = $value_unit;
2206 $this->line->date = $date;
2207
2208 $this->line->fk_expensereport = $expensereport_id;
2209 $this->line->fk_c_type_fees = $type_fees_id;
2210 $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
2211 $this->line->fk_projet = $projet_id; // deprecated
2212 $this->line->fk_project = $projet_id;
2213
2214 $this->line->vat_src_code = $vat_src_code;
2215 $this->line->vatrate = price2num($vatrate);
2216 $this->line->localtax1_tx = $localtaxes_type[1];
2217 $this->line->localtax2_tx = $localtaxes_type[3];
2218 $this->line->localtax1_type = $localtaxes_type[0];
2219 $this->line->localtax2_type = $localtaxes_type[2];
2220
2221 $this->line->total_ttc = $tmp[2];
2222 $this->line->total_ht = $tmp[0];
2223 $this->line->total_tva = $tmp[1];
2224 $this->line->total_localtax1 = $tmp[9];
2225 $this->line->total_localtax2 = $tmp[10];
2226
2227 $this->line->fk_ecm_files = $fk_ecm_files;
2228
2229 $this->line->id = ((int) $rowid);
2230
2231 // Select des infos sur le type fees
2232 $sql = "SELECT c.code as code_type_fees, c.label as label_type_fees";
2233 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
2234 $sql .= " WHERE c.id = ".((int) $type_fees_id);
2235 $resql = $this->db->query($sql);
2236 if ($resql) {
2237 $objp_fees = $this->db->fetch_object($resql);
2238 $this->line->type_fees_code = $objp_fees->code_type_fees;
2239 $this->line->type_fees_libelle = $objp_fees->label_type_fees;
2240 $this->db->free($resql);
2241 }
2242
2243 // Select des informations du projet
2244 $sql = "SELECT p.ref as ref_projet, p.title as title_projet";
2245 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
2246 $sql .= " WHERE p.rowid = ".((int) $projet_id);
2247 $resql = $this->db->query($sql);
2248 if ($resql) {
2249 $objp_projet = $this->db->fetch_object($resql);
2250 $this->line->projet_ref = $objp_projet->ref_projet;
2251 $this->line->projet_title = $objp_projet->title_projet;
2252 $this->db->free($resql);
2253 }
2254
2255 $this->applyOffset();
2256 $this->checkRules();
2257
2258 $result = $this->line->update($user);
2259 if ($result < 0) {
2260 $error++;
2261 }
2262
2263 if (!$error && !$notrigger) {
2264 // Call triggers
2265 $result = $this->call_trigger('EXPENSE_REPORT_DET_MODIFY', $user);
2266 if ($result < 0) {
2267 $error++;
2268 }
2269 // End call triggers
2270 }
2271
2272 if (!$error) {
2273 $this->db->commit();
2274 return 1;
2275 } else {
2276 $this->error = $this->line->error;
2277 $this->errors = $this->line->errors;
2278 $this->db->rollback();
2279 return -2;
2280 }
2281 }
2282
2283 return 0;
2284 }
2285
2294 public function deleteline($rowid, $fuser = '', $notrigger = 0)
2295 {
2296 $error=0;
2297
2298 $this->db->begin();
2299
2300 if (!$notrigger) {
2301 // Call triggers
2302 $result = $this->call_trigger('EXPENSE_REPORT_DET_DELETE', $fuser);
2303 if ($result < 0) {
2304 $error++;
2305 }
2306 // End call triggers
2307 }
2308
2309 $sql = ' DELETE FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2310 $sql .= ' WHERE rowid = '.((int) $rowid);
2311
2312 dol_syslog(get_class($this)."::deleteline sql=".$sql);
2313 $result = $this->db->query($sql);
2314
2315 if (!$result || $error > 0) {
2316 $this->error = $this->db->error();
2317 dol_syslog(get_class($this)."::deleteline Error ".$this->error, LOG_ERR);
2318 $this->db->rollback();
2319 return -1;
2320 }
2321
2322 $this->update_price(1);
2323
2324 $this->db->commit();
2325
2326 return 1;
2327 }
2328
2329 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2338 public function periode_existe($fuser, $date_debut, $date_fin)
2339 {
2340 global $conf;
2341
2342 // phpcs:enable
2343 $sql = "SELECT rowid, date_debut, date_fin";
2344 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
2345 $sql .= " WHERE entity = ".((int) $conf->entity); // not shared, only for the current entity
2346 $sql .= " AND fk_user_author = ".((int) $fuser->id);
2347
2348 dol_syslog(get_class($this)."::periode_existe sql=".$sql);
2349 $result = $this->db->query($sql);
2350 if ($result) {
2351 $num_rows = $this->db->num_rows($result);
2352 $i = 0;
2353
2354 if ($num_rows > 0) {
2355 $date_d_form = $date_debut;
2356 $date_f_form = $date_fin;
2357
2358 while ($i < $num_rows) {
2359 $objp = $this->db->fetch_object($result);
2360
2361 $date_d_req = $this->db->jdate($objp->date_debut); // 3
2362 $date_f_req = $this->db->jdate($objp->date_fin); // 4
2363
2364 if (!($date_f_form < $date_d_req || $date_d_form > $date_f_req)) {
2365 return $objp->rowid;
2366 }
2367
2368 $i++;
2369 }
2370
2371 return 0;
2372 } else {
2373 return 0;
2374 }
2375 } else {
2376 $this->error = $this->db->lasterror();
2377 dol_syslog(get_class($this)."::periode_existe Error ".$this->error, LOG_ERR);
2378 return -1;
2379 }
2380 }
2381
2382
2383 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2391 {
2392 // phpcs:enable
2393 $users_validator = array();
2394
2395 $sql = "SELECT DISTINCT ur.fk_user";
2396 $sql .= " FROM ".MAIN_DB_PREFIX."user_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2397 $sql .= " WHERE ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2398 $sql .= " UNION";
2399 $sql .= " SELECT DISTINCT ugu.fk_user";
2400 $sql .= " FROM ".MAIN_DB_PREFIX."usergroup_user as ugu, ".MAIN_DB_PREFIX."usergroup_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2401 $sql .= " WHERE ugu.fk_usergroup = ur.fk_usergroup AND ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2402 //print $sql;
2403
2404 dol_syslog(get_class($this)."::fetch_users_approver_expensereport sql=".$sql);
2405 $result = $this->db->query($sql);
2406 if ($result) {
2407 $num_rows = $this->db->num_rows($result);
2408 $i = 0;
2409 while ($i < $num_rows) {
2410 $objp = $this->db->fetch_object($result);
2411 array_push($users_validator, $objp->fk_user);
2412 $i++;
2413 }
2414 return $users_validator;
2415 } else {
2416 $this->error = $this->db->lasterror();
2417 dol_syslog(get_class($this)."::fetch_users_approver_expensereport Error ".$this->error, LOG_ERR);
2418 return -1;
2419 }
2420 }
2421
2433 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
2434 {
2435 global $conf;
2436
2437 $outputlangs->load("trips");
2438
2439 if (!dol_strlen($modele)) {
2440 if (!empty($this->model_pdf)) {
2441 $modele = $this->model_pdf;
2442 } elseif (getDolGlobalString('EXPENSEREPORT_ADDON_PDF')) {
2443 $modele = $conf->global->EXPENSEREPORT_ADDON_PDF;
2444 }
2445 }
2446
2447 if (!empty($modele)) {
2448 $modelpath = "core/modules/expensereport/doc/";
2449
2450 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2451 } else {
2452 return 0;
2453 }
2454 }
2455
2462 public function listOfTypes($active = 1)
2463 {
2464 global $langs;
2465 $ret = array();
2466 $sql = "SELECT id, code, label";
2467 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees";
2468 $sql .= " WHERE active = ".((int) $active);
2469 dol_syslog(get_class($this)."::listOfTypes", LOG_DEBUG);
2470 $result = $this->db->query($sql);
2471 if ($result) {
2472 $num = $this->db->num_rows($result);
2473 $i = 0;
2474 while ($i < $num) {
2475 $obj = $this->db->fetch_object($result);
2476 $ret[$obj->code] = (($langs->transnoentitiesnoconv($obj->code) != $obj->code) ? $langs->transnoentitiesnoconv($obj->code) : $obj->label);
2477 $i++;
2478 }
2479 } else {
2480 dol_print_error($this->db);
2481 }
2482 return $ret;
2483 }
2484
2485 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2491 public function load_state_board()
2492 {
2493 // phpcs:enable
2494 global $conf, $user;
2495
2496 $this->nb = array();
2497
2498 $sql = "SELECT count(ex.rowid) as nb";
2499 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2500 $sql .= " WHERE ex.fk_statut > 0";
2501 $sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2502 if (!$user->hasRight('expensereport', 'readall')) {
2503 $userchildids = $user->getAllChildIds(1);
2504 $sql .= " AND (ex.fk_user_author IN (".$this->db->sanitize(join(',', $userchildids)).")";
2505 $sql .= " OR ex.fk_user_validator IN (".$this->db->sanitize(join(',', $userchildids))."))";
2506 }
2507
2508 $resql = $this->db->query($sql);
2509 if ($resql) {
2510 while ($obj = $this->db->fetch_object($resql)) {
2511 $this->nb["expensereports"] = $obj->nb;
2512 }
2513 $this->db->free($resql);
2514 return 1;
2515 } else {
2516 dol_print_error($this->db);
2517 $this->error = $this->db->error();
2518 return -1;
2519 }
2520 }
2521
2522 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2530 public function load_board($user, $option = 'topay')
2531 {
2532 // phpcs:enable
2533 global $conf, $langs;
2534
2535 if ($user->socid) {
2536 return -1; // protection pour eviter appel par utilisateur externe
2537 }
2538
2539 $now = dol_now();
2540
2541 $sql = "SELECT ex.rowid, ex.date_valid";
2542 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2543 if ($option == 'toapprove') {
2544 $sql .= " WHERE ex.fk_statut = ".self::STATUS_VALIDATED;
2545 } else {
2546 $sql .= " WHERE ex.fk_statut = ".self::STATUS_APPROVED;
2547 }
2548 $sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2549 if (!$user->hasRight('expensereport', 'readall')) {
2550 $userchildids = $user->getAllChildIds(1);
2551 $sql .= " AND (ex.fk_user_author IN (".$this->db->sanitize(join(',', $userchildids)).")";
2552 $sql .= " OR ex.fk_user_validator IN (".$this->db->sanitize(join(',', $userchildids))."))";
2553 }
2554
2555 $resql = $this->db->query($sql);
2556 if ($resql) {
2557 $langs->load("trips");
2558
2559 $response = new WorkboardResponse();
2560 if ($option == 'toapprove') {
2561 $response->warning_delay = $conf->expensereport->approve->warning_delay / 60 / 60 / 24;
2562 $response->label = $langs->trans("ExpenseReportsToApprove");
2563 $response->labelShort = $langs->trans("ToApprove");
2564 $response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_VALIDATED;
2565 } else {
2566 $response->warning_delay = $conf->expensereport->payment->warning_delay / 60 / 60 / 24;
2567 $response->label = $langs->trans("ExpenseReportsToPay");
2568 $response->labelShort = $langs->trans("StatusToPay");
2569 $response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_APPROVED;
2570 }
2571 $response->img = img_object('', "trip");
2572
2573 while ($obj = $this->db->fetch_object($resql)) {
2574 $response->nbtodo++;
2575
2576 if ($option == 'toapprove') {
2577 if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->approve->warning_delay)) {
2578 $response->nbtodolate++;
2579 }
2580 } else {
2581 if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->payment->warning_delay)) {
2582 $response->nbtodolate++;
2583 }
2584 }
2585 }
2586
2587 return $response;
2588 } else {
2589 dol_print_error($this->db);
2590 $this->error = $this->db->error();
2591 return -1;
2592 }
2593 }
2594
2601 public function hasDelay($option)
2602 {
2603 global $conf;
2604
2605 // Only valid expenses reports
2606 if ($option == 'toapprove' && $this->status != 2) {
2607 return false;
2608 }
2609 if ($option == 'topay' && $this->status != 5) {
2610 return false;
2611 }
2612
2613 $now = dol_now();
2614 if ($option == 'toapprove') {
2615 return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->approve->warning_delay);
2616 } else {
2617 return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->payment->warning_delay);
2618 }
2619 }
2620
2626 public function getVentilExportCompta()
2627 {
2628 $alreadydispatched = 0;
2629
2630 $type = 'expense_report';
2631
2632 $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);
2633 $resql = $this->db->query($sql);
2634 if ($resql) {
2635 $obj = $this->db->fetch_object($resql);
2636 if ($obj) {
2637 $alreadydispatched = $obj->nb;
2638 }
2639 } else {
2640 $this->error = $this->db->lasterror();
2641 return -1;
2642 }
2643
2644 if ($alreadydispatched) {
2645 return 1;
2646 }
2647 return 0;
2648 }
2649
2655 public function getSumPayments()
2656 {
2657 $table = 'payment_expensereport';
2658 $field = 'fk_expensereport';
2659
2660 $sql = 'SELECT sum(amount) as amount';
2661 $sql .= ' FROM '.MAIN_DB_PREFIX.$table;
2662 $sql .= " WHERE ".$field." = ".((int) $this->id);
2663
2664 dol_syslog(get_class($this)."::getSumPayments", LOG_DEBUG);
2665 $resql = $this->db->query($sql);
2666 if ($resql) {
2667 $obj = $this->db->fetch_object($resql);
2668 $this->db->free($resql);
2669 return (empty($obj->amount) ? 0 : $obj->amount);
2670 } else {
2671 $this->error = $this->db->lasterror();
2672 return -1;
2673 }
2674 }
2675
2684 public function computeTotalKm($fk_cat, $qty, $tva)
2685 {
2686 global $langs, $db, $conf;
2687
2688 $cumulYearQty = 0;
2689 $ranges = array();
2690 $coef = 0;
2691
2692
2693 if ($fk_cat < 0) {
2694 $this->error = $langs->trans('ErrorBadParameterCat');
2695 return -1;
2696 }
2697
2698 if ($qty <= 0) {
2699 $this->error = $langs->trans('ErrorBadParameterQty');
2700 return -1;
2701 }
2702
2703 $currentUser = new User($db);
2704 $currentUser->fetch($this->fk_user);
2705 $currentUser->getrights('expensereport');
2706 //Clean
2707 $qty = price2num($qty);
2708
2709 $sql = " SELECT r.range_ik, t.ikoffset, t.coef";
2710 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport_ik t";
2711 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_exp_tax_range r ON r.rowid = t.fk_range";
2712 $sql .= " WHERE t.fk_c_exp_tax_cat = ".(int) $fk_cat;
2713 $sql .= " ORDER BY r.range_ik ASC";
2714
2715 dol_syslog("expenseReport::computeTotalkm sql=".$sql, LOG_DEBUG);
2716
2717 $result = $this->db->query($sql);
2718
2719 if ($result) {
2720 if ($conf->global->EXPENSEREPORT_CALCULATE_MILEAGE_EXPENSE_COEFFICIENT_ON_CURRENT_YEAR) {
2721 $arrayDate = dol_getdate(dol_now());
2722 $sql = " SELECT count(n.qty) as cumul FROM ".MAIN_DB_PREFIX."expensereport_det n";
2723 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expensereport e ON e.rowid = n.fk_expensereport";
2724 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_type_fees tf ON tf.id = n.fk_c_type_fees";
2725 $sql.= " WHERE e.fk_user_author = ".(int) $this->fk_user_author;
2726 $sql.= " AND YEAR(n.date) = ".(int) $arrayDate['year'];
2727 $sql.= " AND tf.code = 'EX_KME' ";
2728 $sql.= " AND e.fk_statut = ".(int) ExpenseReport::STATUS_VALIDATED;
2729
2730 $resql = $this->db->query($sql);
2731
2732 if ($resql) {
2733 $obj = $this->db->fetch_object($resql);
2734 $cumulYearQty = $obj->cumul;
2735 }
2736
2737 $qty = $cumulYearQty + $qty;
2738 }
2739
2740 $num = $this->db->num_rows($result);
2741
2742 if ($num) {
2743 for ($i = 0; $i < $num; $i++) {
2744 $obj = $this->db->fetch_object($result);
2745
2746 $ranges[$i] = $obj;
2747 }
2748
2749
2750 for ($i = 0; $i < $num; $i++) {
2751 if ($i < ($num - 1)) {
2752 if ($qty > $ranges[$i]->range_ik && $qty < $ranges[$i+1]->range_ik) {
2753 $coef = $ranges[$i]->coef;
2754 $offset = $ranges[$i]->ikoffset;
2755 }
2756 } else {
2757 if ($qty > $ranges[$i]->range_ik) {
2758 $coef = $ranges[$i]->coef;
2759 $offset = $ranges[$i]->ikoffset;
2760 }
2761 }
2762 }
2763 $total_ht = $coef;
2764 return $total_ht;
2765 } else {
2766 $this->error = $langs->trans('TaxUndefinedForThisCategory');
2767 return 0;
2768 }
2769 } else {
2770 $this->error = $this->db->error()." sql=".$sql;
2771
2772 return -1;
2773 }
2774 }
2775
2783 public function getKanbanView($option = '', $arraydata = null)
2784 {
2785 global $langs;
2786
2787 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
2788
2789 $return = '<div class="box-flex-item box-flex-grow-zero">';
2790 $return .= '<div class="info-box info-box-sm">';
2791 $return .= '<span class="info-box-icon bg-infobox-action">';
2792 $return .= img_picto('', $this->picto);
2793 $return .= '</span>';
2794 $return .= '<div class="info-box-content">';
2795 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
2796 if ($selected >= 0) {
2797 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
2798 }
2799 if (array_key_exists('userauthor', $arraydata)) {
2800 $return .= '<br><span class="info-box-label">'.$arraydata['userauthor']->getNomUrl(-1).'</span>';
2801 }
2802 if (property_exists($this, 'date_debut') && property_exists($this, 'date_fin')) {
2803 $return .= '<br><span class="info-box-label">'.dol_print_date($this->date_debut, 'day').'</span>';
2804 $return .= ' <span class="opacitymedium">'.$langs->trans("To").'</span> ';
2805 $return .= '<span class="info-box-label">'.dol_print_date($this->date_fin, 'day').'</span>';
2806 }
2807 if (method_exists($this, 'getLibStatut')) {
2808 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
2809 }
2810 $return .= '</div>';
2811 $return .= '</div>';
2812 $return .= '</div>';
2813 return $return;
2814 }
2815}
2816
2817
2822{
2826 public $db;
2827
2831 public $table_element = 'expensereport_det';
2832
2836 public $error = '';
2837
2841 public $rowid;
2842
2843 public $comments;
2844 public $qty;
2845 public $value_unit;
2846 public $date;
2847
2851 public $dates;
2852
2856 public $fk_c_type_fees;
2857
2861 public $fk_c_exp_tax_cat;
2862
2866 public $fk_projet;
2867
2871 public $fk_expensereport;
2872
2873 public $type_fees_code;
2874 public $type_fees_libelle;
2875 public $type_fees_accountancy_code;
2876
2877 public $projet_ref;
2878 public $projet_title;
2879 public $rang;
2880
2881 public $vatrate;
2882 public $vat_src_code;
2883 public $tva_tx;
2884 public $localtax1_tx;
2885 public $localtax2_tx;
2886 public $localtax1_type;
2887 public $localtax2_type;
2888
2889 public $total_ht;
2890 public $total_tva;
2891 public $total_ttc;
2892 public $total_localtax1;
2893 public $total_localtax2;
2894
2895 // Multicurrency
2899 public $fk_multicurrency;
2900
2904 public $multicurrency_code;
2905 public $multicurrency_tx;
2906 public $multicurrency_total_ht;
2907 public $multicurrency_total_tva;
2908 public $multicurrency_total_ttc;
2909
2913 public $fk_ecm_files;
2914
2915 public $rule_warning_message;
2916
2917
2923 public function __construct($db)
2924 {
2925 $this->db = $db;
2926 }
2927
2934 public function fetch($rowid)
2935 {
2936 $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,';
2937 $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,';
2938 $sql .= ' fde.localtax1_tx, fde.localtax2_tx, fde.localtax1_type, fde.localtax2_type, fde.total_localtax1, fde.total_localtax2, fde.rule_warning_message,';
2939 $sql .= ' ctf.code as type_fees_code, ctf.label as type_fees_libelle,';
2940 $sql .= ' pjt.rowid as projet_id, pjt.title as projet_title, pjt.ref as projet_ref';
2941 $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det as fde';
2942 $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.
2943 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as pjt ON fde.fk_projet=pjt.rowid';
2944 $sql .= ' WHERE fde.rowid = '.((int) $rowid);
2945
2946 $result = $this->db->query($sql);
2947
2948 if ($result) {
2949 $objp = $this->db->fetch_object($result);
2950
2951 $this->rowid = $objp->rowid;
2952 $this->id = $objp->rowid;
2953 $this->ref = $objp->ref;
2954 $this->fk_expensereport = $objp->fk_expensereport;
2955 $this->comments = $objp->comments;
2956 $this->qty = $objp->qty;
2957 $this->date = $objp->date;
2958 $this->dates = $this->db->jdate($objp->date);
2959 $this->value_unit = $objp->value_unit;
2960 $this->fk_c_type_fees = $objp->fk_c_type_fees;
2961 $this->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
2962 $this->fk_projet = $objp->fk_project; // deprecated
2963 $this->fk_project = $objp->fk_project;
2964 $this->type_fees_code = $objp->type_fees_code;
2965 $this->type_fees_libelle = $objp->type_fees_libelle;
2966 $this->projet_ref = $objp->projet_ref;
2967 $this->projet_title = $objp->projet_title;
2968
2969 $this->vatrate = $objp->vatrate;
2970 $this->vat_src_code = $objp->vat_src_code;
2971 $this->localtax1_tx = $objp->localtax1_tx;
2972 $this->localtax2_tx = $objp->localtax2_tx;
2973 $this->localtax1_type = $objp->localtax1_type;
2974 $this->localtax2_type = $objp->localtax2_type;
2975
2976 $this->total_ht = $objp->total_ht;
2977 $this->total_tva = $objp->total_tva;
2978 $this->total_ttc = $objp->total_ttc;
2979 $this->total_localtax1 = $objp->total_localtax1;
2980 $this->total_localtax2 = $objp->total_localtax2;
2981
2982 $this->fk_ecm_files = $objp->fk_ecm_files;
2983
2984 $this->rule_warning_message = $objp->rule_warning_message;
2985
2986 $this->db->free($result);
2987
2988 return $this->id;
2989 } else {
2990 dol_print_error($this->db);
2991 return -1;
2992 }
2993 }
2994
3002 public function insert($notrigger = 0, $fromaddline = false)
3003 {
3004 global $user, $conf;
3005
3006 $error = 0;
3007
3008 dol_syslog("ExpenseReportLine::Insert", LOG_DEBUG);
3009
3010 // Clean parameters
3011 $this->comments = trim($this->comments);
3012 if (empty($this->value_unit)) {
3013 $this->value_unit = 0;
3014 }
3015 $this->qty = price2num($this->qty);
3016 $this->vatrate = price2num($this->vatrate);
3017 if (empty($this->fk_c_exp_tax_cat)) {
3018 $this->fk_c_exp_tax_cat = 0;
3019 }
3020
3021 $this->db->begin();
3022
3023 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'expensereport_det';
3024 $sql .= ' (fk_expensereport, fk_c_type_fees, fk_projet,';
3025 $sql .= ' tva_tx, vat_src_code,';
3026 $sql .= ' localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3027 $sql .= ' comments, qty, value_unit,';
3028 $sql .= ' total_ht, total_tva, total_ttc,';
3029 $sql .= ' total_localtax1, total_localtax2,';
3030 $sql .= ' date, rule_warning_message, fk_c_exp_tax_cat, fk_ecm_files)';
3031 $sql .= " VALUES (".$this->db->escape($this->fk_expensereport).",";
3032 $sql .= " ".((int) $this->fk_c_type_fees).",";
3033 $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')).",";
3034 $sql .= " ".((float) $this->vatrate).",";
3035 $sql .= " '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."',";
3036 $sql .= " ".((float) price2num($this->localtax1_tx)).",";
3037 $sql .= " ".((float) price2num($this->localtax2_tx)).",";
3038 $sql .= " '".$this->db->escape($this->localtax1_type)."',";
3039 $sql .= " '".$this->db->escape($this->localtax2_type)."',";
3040 $sql .= " '".$this->db->escape($this->comments)."',";
3041 $sql .= " ".((float) $this->qty).",";
3042 $sql .= " ".((float) $this->value_unit).",";
3043 $sql .= " ".((float) price2num($this->total_ht)).",";
3044 $sql .= " ".((float) price2num($this->total_tva)).",";
3045 $sql .= " ".((float) price2num($this->total_ttc)).",";
3046 $sql .= " ".((float) price2num($this->total_localtax1)).",";
3047 $sql .= " ".((float) price2num($this->total_localtax2)).",";
3048 $sql .= " '".$this->db->idate($this->date)."',";
3049 $sql .= " ".(empty($this->rule_warning_message) ? 'null' : "'".$this->db->escape($this->rule_warning_message)."'").",";
3050 $sql .= " ".((int) $this->fk_c_exp_tax_cat).",";
3051 $sql .= " ".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
3052 $sql .= ")";
3053
3054 $resql = $this->db->query($sql);
3055 if ($resql) {
3056 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'expensereport_det');
3057
3058
3059 if (!$error && !$notrigger) {
3060 // Call triggers
3061 $result = $this->call_trigger('EXPENSE_REPORT_DET_CREATE', $user);
3062 if ($result < 0) {
3063 $error++;
3064 }
3065 // End call triggers
3066 }
3067
3068
3069 if (!$fromaddline) {
3070 $tmpparent = new ExpenseReport($this->db);
3071 $tmpparent->fetch($this->fk_expensereport);
3072 $result = $tmpparent->update_price(1);
3073 if ($result < 0) {
3074 $error++;
3075 $this->error = $tmpparent->error;
3076 $this->errors = $tmpparent->errors;
3077 }
3078 }
3079 } else {
3080 $error++;
3081 }
3082
3083 if (!$error) {
3084 $this->db->commit();
3085 return $this->id;
3086 } else {
3087 $this->error = $this->db->lasterror();
3088 dol_syslog("ExpenseReportLine::insert Error ".$this->error, LOG_ERR);
3089 $this->db->rollback();
3090 return -2;
3091 }
3092 }
3093
3102 public function getExpAmount(ExpenseReportRule $rule, $fk_user, $mode = 'day')
3103 {
3104 $amount = 0;
3105
3106 $sql = 'SELECT SUM(d.total_ttc) as total_amount';
3107 $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det d';
3108 $sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'expensereport e ON (d.fk_expensereport = e.rowid)';
3109 $sql .= ' WHERE e.fk_user_author = '.((int) $fk_user);
3110 if (!empty($this->id)) {
3111 $sql .= ' AND d.rowid <> '.((int) $this->id);
3112 }
3113 $sql .= ' AND d.fk_c_type_fees = '.((int) $rule->fk_c_type_fees);
3114 if ($mode == 'day' || $mode == 'EX_DAY') {
3115 $sql .= " AND d.date = '".dol_print_date($this->date, '%Y-%m-%d')."'";
3116 } elseif ($mode == 'mon' || $mode == 'EX_MON') {
3117 $sql .= " AND DATE_FORMAT(d.date, '%Y-%m') = '".dol_print_date($this->date, '%Y-%m')."'"; // @todo DATE_FORMAT is forbidden
3118 } elseif ($mode == 'year' || $mode == 'EX_YEA') {
3119 $sql .= " AND DATE_FORMAT(d.date, '%Y') = '".dol_print_date($this->date, '%Y')."'"; // @todo DATE_FORMAT is forbidden
3120 }
3121
3122 dol_syslog('ExpenseReportLine::getExpAmount');
3123
3124 $resql = $this->db->query($sql);
3125 if ($resql) {
3126 $num = $this->db->num_rows($resql);
3127 if ($num > 0) {
3128 $obj = $this->db->fetch_object($resql);
3129 $amount = (float) $obj->total_amount;
3130 }
3131 } else {
3132 dol_print_error($this->db);
3133 }
3134
3135 return $amount + $this->total_ttc;
3136 }
3137
3144 public function update(User $user)
3145 {
3146 global $langs, $conf;
3147
3148 $error = 0;
3149
3150 // Clean parameters
3151 $this->comments = trim($this->comments);
3152 $this->vatrate = price2num($this->vatrate);
3153 $this->value_unit = price2num($this->value_unit);
3154 if (empty($this->fk_c_exp_tax_cat)) {
3155 $this->fk_c_exp_tax_cat = 0;
3156 }
3157
3158 $this->db->begin();
3159
3160 // Update line in database
3161 $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport_det SET";
3162 $sql .= " comments='".$this->db->escape($this->comments)."'";
3163 $sql .= ", value_unit = ".((float) $this->value_unit);
3164 $sql .= ", qty=".((float) $this->qty);
3165 $sql .= ", date='".$this->db->idate($this->date)."'";
3166 $sql .= ", total_ht=".((float) price2num($this->total_ht, 'MT'));
3167 $sql .= ", total_tva=".((float) price2num($this->total_tva, 'MT'));
3168 $sql .= ", total_ttc=".((float) price2num($this->total_ttc, 'MT'));
3169 $sql .= ", total_localtax1=".((float) price2num($this->total_localtax1, 'MT'));
3170 $sql .= ", total_localtax2=".((float) price2num($this->total_localtax2, 'MT'));
3171 $sql .= ", tva_tx=".((float) $this->vatrate);
3172 $sql .= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
3173 $sql .= ", localtax1_tx=".((float) $this->localtax1_tx);
3174 $sql .= ", localtax2_tx=".((float) $this->localtax2_tx);
3175 $sql .= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
3176 $sql .= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
3177 $sql .= ", rule_warning_message='".$this->db->escape($this->rule_warning_message)."'";
3178 $sql .= ", fk_c_exp_tax_cat=".$this->db->escape($this->fk_c_exp_tax_cat);
3179 $sql .= ", fk_ecm_files=".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
3180 if ($this->fk_c_type_fees) {
3181 $sql .= ", fk_c_type_fees = ".((int) $this->fk_c_type_fees);
3182 } else {
3183 $sql .= ", fk_c_type_fees=null";
3184 }
3185 if ($this->fk_project > 0) {
3186 $sql .= ", fk_projet=".((int) $this->fk_project);
3187 } else {
3188 $sql .= ", fk_projet=null";
3189 }
3190 $sql .= " WHERE rowid = ".((int) ($this->rowid ? $this->rowid : $this->id));
3191
3192 dol_syslog("ExpenseReportLine::update");
3193
3194 $resql = $this->db->query($sql);
3195 if ($resql) {
3196 $tmpparent = new ExpenseReport($this->db);
3197 $result = $tmpparent->fetch($this->fk_expensereport);
3198 if ($result > 0) {
3199 $result = $tmpparent->update_price(1);
3200 if ($result < 0) {
3201 $error++;
3202 $this->error = $tmpparent->error;
3203 $this->errors = $tmpparent->errors;
3204 }
3205 } else {
3206 $error++;
3207 $this->error = $tmpparent->error;
3208 $this->errors = $tmpparent->errors;
3209 }
3210 } else {
3211 $error++;
3212 dol_print_error($this->db);
3213 }
3214
3215 if (!$error) {
3216 $this->db->commit();
3217 return 1;
3218 } else {
3219 $this->error = $this->db->lasterror();
3220 dol_syslog("ExpenseReportLine::update Error ".$this->error, LOG_ERR);
3221 $this->db->rollback();
3222 return -2;
3223 }
3224 }
3225
3226 // ajouter ici comput_ ...
3227}
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Definition security.php:604
$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.
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
update_price($exclspec=0, $roundingadjust='none', $nodatabaseupdate=0, $seller=null)
Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
deleteExtraFields()
Delete all extra fields values for the current object.
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.
__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 vehicule categor...
load_state_board()
Charge indicateurs this->nb pour le tableau de bord.
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.
deleteline($rowid, $fuser='', $notrigger=0)
deleteline
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.
setDeny($fuser, $details, $notrigger=0)
setDeny
getVentilExportCompta()
Return if object was dispatched into bookkeeping.
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually 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 accordign 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.
fetch_line_by_project($projectid, $user='')
fetch_line_by_project
setUnpaid($fuser, $notrigger=0)
set_unpaid
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($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:62
dol_delete_preview($object)
Delete all preview files linked to object instance.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
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_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.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1907
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller='', $localtaxes_array='', $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code='')
Calculate totals (net, vat, ...) of a line.
Definition price.lib.php:86