dolibarr 19.0.4
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 $sql .= " AND d.entity IN (".getEntity('expensereport').")";
634 } else {
635 $sql .= " WHERE d.rowid = ".((int) $id);
636 }
637 //$sql.= $restrict;
638
639 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
640 $resql = $this->db->query($sql);
641 if ($resql) {
642 $obj = $this->db->fetch_object($resql);
643 if ($obj) {
644 $this->id = $obj->rowid;
645 $this->ref = $obj->ref;
646
647 $this->entity = $obj->entity;
648
649 $this->total_ht = $obj->total_ht;
650 $this->total_tva = $obj->total_tva;
651 $this->total_ttc = $obj->total_ttc;
652 $this->localtax1 = $obj->total_localtax1; // For backward compatibility
653 $this->localtax2 = $obj->total_localtax2; // For backward compatibility
654 $this->total_localtax1 = $obj->total_localtax1;
655 $this->total_localtax2 = $obj->total_localtax2;
656
657 $this->note_public = $obj->note_public;
658 $this->note_private = $obj->note_private;
659 $this->detail_refuse = $obj->detail_refuse;
660 $this->detail_cancel = $obj->detail_cancel;
661
662 $this->date_debut = $this->db->jdate($obj->date_debut);
663 $this->date_fin = $this->db->jdate($obj->date_fin);
664 $this->date_valid = $this->db->jdate($obj->date_valid);
665 $this->date_approve = $this->db->jdate($obj->date_approve);
666 $this->date_create = $this->db->jdate($obj->date_create);
667 $this->date_modif = $this->db->jdate($obj->date_modif);
668 $this->date_refuse = $this->db->jdate($obj->date_refuse);
669 $this->date_cancel = $this->db->jdate($obj->date_cancel);
670
671 $this->fk_user_creat = $obj->fk_user_creat;
672 $this->fk_user_author = $obj->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
673 $this->fk_user_modif = $obj->fk_user_modif;
674 $this->fk_user_validator = $obj->fk_user_validator;
675 $this->fk_user_valid = $obj->fk_user_valid;
676 $this->fk_user_refuse = $obj->fk_user_refuse;
677 $this->fk_user_cancel = $obj->fk_user_cancel;
678 $this->fk_user_approve = $obj->fk_user_approve;
679
680 $user_author = new User($this->db);
681 if ($this->fk_user_author > 0) {
682 $user_author->fetch($this->fk_user_author);
683 }
684
685 $this->user_author_infos = dolGetFirstLastname($user_author->firstname, $user_author->lastname);
686
687 $user_approver = new User($this->db);
688 if ($this->fk_user_approve > 0) {
689 $user_approver->fetch($this->fk_user_approve);
690 } elseif ($this->fk_user_validator > 0) {
691 $user_approver->fetch($this->fk_user_validator); // For backward compatibility
692 }
693 $this->user_validator_infos = dolGetFirstLastname($user_approver->firstname, $user_approver->lastname);
694
695 $this->fk_statut = $obj->status; // deprecated
696 $this->status = $obj->status;
697 $this->fk_c_paiement = $obj->fk_c_paiement;
698 $this->paid = $obj->paid;
699
700 if ($this->status == self::STATUS_APPROVED || $this->status == self::STATUS_CLOSED) {
701 $user_valid = new User($this->db);
702 if ($this->fk_user_valid > 0) {
703 $user_valid->fetch($this->fk_user_valid);
704 }
705 $this->user_valid_infos = dolGetFirstLastname($user_valid->firstname, $user_valid->lastname);
706 }
707
708 $this->fetch_optionals();
709
710 $result = $this->fetch_lines();
711
712 return $result;
713 } else {
714 return 0;
715 }
716 } else {
717 $this->error = $this->db->lasterror();
718 return -1;
719 }
720 }
721
722 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
733 public function set_paid($id, $fuser, $notrigger = 0)
734 {
735 // phpcs:enable
736 dol_syslog(get_class($this)."::set_paid is deprecated, use setPaid instead", LOG_NOTICE);
737 return $this->setPaid($id, $fuser, $notrigger);
738 }
739
748 public function setPaid($id, $fuser, $notrigger = 0)
749 {
750 $error = 0;
751 $this->db->begin();
752
753 $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport";
754 $sql .= " SET fk_statut = ".self::STATUS_CLOSED.", paid=1";
755 $sql .= " WHERE rowid = ".((int) $id)." AND fk_statut = ".self::STATUS_APPROVED;
756
757 dol_syslog(get_class($this)."::setPaid", LOG_DEBUG);
758 $resql = $this->db->query($sql);
759 if ($resql) {
760 if ($this->db->affected_rows($resql)) {
761 if (!$notrigger) {
762 // Call trigger
763 $result = $this->call_trigger('EXPENSE_REPORT_PAID', $fuser);
764
765 if ($result < 0) {
766 $error++;
767 }
768 // End call triggers
769 }
770
771 if (empty($error)) {
772 $this->db->commit();
773 return 1;
774 } else {
775 $this->db->rollback();
776 $this->error = $this->db->error();
777 return -2;
778 }
779 } else {
780 $this->db->commit();
781 return 0;
782 }
783 } else {
784 $this->db->rollback();
785 dol_print_error($this->db);
786 return -1;
787 }
788 }
789
796 public function getLibStatut($mode = 0)
797 {
798 return $this->LibStatut($this->status, $mode);
799 }
800
801 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
809 public function LibStatut($status, $mode = 0)
810 {
811 // phpcs:enable
812 global $langs;
813
814 $labelStatus = $langs->transnoentitiesnoconv($this->labelStatus[$status]);
815 $labelStatusShort = $langs->transnoentitiesnoconv($this->labelStatusShort[$status]);
816
817 $statuslogo = array(0 => 'status0', 2 => 'status1', 4 => 'status6', 5 => 'status4', 6 => 'status6', 99 => 'status5');
818
819 $statusType = $statuslogo[$status];
820
821 return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
822 }
823
824
831 public function info($id)
832 {
833 global $conf;
834
835 $sql = "SELECT f.rowid,";
836 $sql .= " f.date_create as datec,";
837 $sql .= " f.tms as date_modification,";
838 $sql .= " f.date_valid as datev,";
839 $sql .= " f.date_approve as datea,";
840 $sql .= " f.fk_user_creat as fk_user_creation,";
841 $sql .= " f.fk_user_author as fk_user_author,";
842 $sql .= " f.fk_user_modif as fk_user_modification,";
843 $sql .= " f.fk_user_valid,";
844 $sql .= " f.fk_user_approve";
845 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as f";
846 $sql .= " WHERE f.rowid = ".((int) $id);
847 $sql .= " AND f.entity = ".$conf->entity;
848
849 $resql = $this->db->query($sql);
850 if ($resql) {
851 if ($this->db->num_rows($resql)) {
852 $obj = $this->db->fetch_object($resql);
853
854 $this->id = $obj->rowid;
855
856 $this->date_creation = $this->db->jdate($obj->datec);
857 $this->date_modification = $this->db->jdate($obj->date_modification);
858 $this->date_validation = $this->db->jdate($obj->datev);
859 $this->date_approbation = $this->db->jdate($obj->datea);
860
861 $this->user_creation_id = $obj->fk_user_author;
862 $this->user_creation_id = $obj->fk_user_creation;
863 $this->user_validation_id = $obj->fk_user_valid;
864 $this->user_modification_id = $obj->fk_user_modification;
865 $this->user_approve_id = $obj->fk_user_approve;
866 }
867 $this->db->free($resql);
868 } else {
869 dol_print_error($this->db);
870 }
871 }
872
873
874
882 public function initAsSpecimen()
883 {
884 global $user, $langs, $conf;
885
886 $now = dol_now();
887
888 // Initialise parametres
889 $this->id = 0;
890 $this->ref = 'SPECIMEN';
891 $this->specimen = 1;
892 $this->entity = 1;
893 $this->date_create = $now;
894 $this->date_debut = $now;
895 $this->date_fin = $now;
896 $this->date_valid = $now;
897 $this->date_approve = $now;
898
899 $type_fees_id = 2; // TF_TRIP
900
901 $this->status = 5;
902 $this->fk_statut = 5;
903
904 $this->fk_user_author = $user->id;
905 $this->fk_user_validator = $user->id;
906 $this->fk_user_valid = $user->id;
907 $this->fk_user_approve = $user->id;
908
909 $this->note_private = 'Private note';
910 $this->note_public = 'SPECIMEN';
911 $nbp = 5;
912 $xnbp = 0;
913 while ($xnbp < $nbp) {
914 $line = new ExpenseReportLine($this->db);
915 $line->comments = $langs->trans("Comment")." ".$xnbp;
916 $line->date = ($now - 3600 * (1 + $xnbp));
917 $line->total_ht = 100;
918 $line->total_tva = 20;
919 $line->total_ttc = 120;
920 $line->qty = 1;
921 $line->vatrate = 20;
922 $line->value_unit = 120;
923 $line->fk_expensereport = 0;
924 $line->type_fees_code = 'TRA';
925 $line->fk_c_type_fees = $type_fees_id;
926
927 $line->projet_ref = 'ABC';
928
929 $this->lines[$xnbp] = $line;
930 $xnbp++;
931
932 $this->total_ht += $line->total_ht;
933 $this->total_tva += $line->total_tva;
934 $this->total_ttc += $line->total_ttc;
935 }
936 }
937
938 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
946 public function fetch_line_by_project($projectid, $user = '')
947 {
948 // phpcs:enable
949 global $conf, $db, $langs;
950
951 $langs->load('trips');
952
953 if ($user->hasRight('expensereport', 'lire')) {
954 $sql = "SELECT de.fk_expensereport, de.date, de.comments, de.total_ht, de.total_ttc";
955 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport_det as de";
956 $sql .= " WHERE de.fk_projet = ".((int) $projectid);
957
958 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
959 $result = $this->db->query($sql);
960 if ($result) {
961 $num = $this->db->num_rows($result);
962 $i = 0;
963 $total_HT = 0;
964 $total_TTC = 0;
965
966 while ($i < $num) {
967 $objp = $this->db->fetch_object($result);
968
969 $sql2 = "SELECT d.rowid, d.fk_user_author, d.ref, d.fk_statut as status";
970 $sql2 .= " FROM ".MAIN_DB_PREFIX."expensereport as d";
971 $sql2 .= " WHERE d.rowid = ".((int) $objp->fk_expensereport);
972
973 $result2 = $this->db->query($sql2);
974 $obj = $this->db->fetch_object($result2);
975
976 $objp->fk_user_author = $obj->fk_user_author;
977 $objp->ref = $obj->ref;
978 $objp->fk_c_expensereport_status = $obj->status;
979 $objp->rowid = $obj->rowid;
980
981 $total_HT = $total_HT + $objp->total_ht;
982 $total_TTC = $total_TTC + $objp->total_ttc;
983 $author = new User($this->db);
984 $author->fetch($objp->fk_user_author);
985
986 print '<tr>';
987 print '<td><a href="'.DOL_URL_ROOT.'/expensereport/card.php?id='.$objp->rowid.'">'.$objp->ref_num.'</a></td>';
988 print '<td class="center">'.dol_print_date($objp->date, 'day').'</td>';
989 print '<td>'.$author->getNomUrl(1).'</td>';
990 print '<td>'.$objp->comments.'</td>';
991 print '<td class="right">'.price($objp->total_ht).'</td>';
992 print '<td class="right">'.price($objp->total_ttc).'</td>';
993 print '<td class="right">';
994
995 switch ($objp->fk_c_expensereport_status) {
996 case 4:
997 print img_picto($langs->trans('StatusOrderCanceled'), 'statut5');
998 break;
999 case 1:
1000 print $langs->trans('Draft').' '.img_picto($langs->trans('Draft'), 'statut0');
1001 break;
1002 case 2:
1003 print $langs->trans('TripForValid').' '.img_picto($langs->trans('TripForValid'), 'statut3');
1004 break;
1005 case 5:
1006 print $langs->trans('TripForPaid').' '.img_picto($langs->trans('TripForPaid'), 'statut3');
1007 break;
1008 case 6:
1009 print $langs->trans('TripPaid').' '.img_picto($langs->trans('TripPaid'), 'statut4');
1010 break;
1011 }
1012 /*
1013 if ($status==4) return img_picto($langs->trans('StatusOrderCanceled'),'statut5');
1014 if ($status==1) return img_picto($langs->trans('StatusOrderDraft'),'statut0');
1015 if ($status==2) return img_picto($langs->trans('StatusOrderValidated'),'statut1');
1016 if ($status==2) return img_picto($langs->trans('StatusOrderOnProcess'),'statut3');
1017 if ($status==5) return img_picto($langs->trans('StatusOrderToBill'),'statut4');
1018 if ($status==6) return img_picto($langs->trans('StatusOrderOnProcess'),'statut6');
1019 */
1020 print '</td>';
1021 print '</tr>';
1022
1023 $i++;
1024 }
1025
1026 print '<tr class="liste_total"><td colspan="4">'.$langs->trans("Number").': '.$i.'</td>';
1027 print '<td class="right" width="100">'.$langs->trans("TotalHT").' : '.price($total_HT).'</td>';
1028 print '<td class="right" width="100">'.$langs->trans("TotalTTC").' : '.price($total_TTC).'</td>';
1029 print '<td>&nbsp;</td>';
1030 print '</tr>';
1031 } else {
1032 $this->error = $this->db->lasterror();
1033 return -1;
1034 }
1035 }
1036
1037 return 0;
1038 }
1039
1040 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1046 public function fetch_lines()
1047 {
1048 // phpcs:enable
1049 global $conf;
1050
1051 $this->lines = array();
1052
1053 $sql = ' SELECT de.rowid, de.comments, de.qty, de.value_unit, de.date, de.rang,';
1054 $sql .= " de.".$this->fk_element.", de.fk_c_type_fees, de.fk_c_exp_tax_cat, de.fk_projet as fk_project,";
1055 $sql .= ' de.tva_tx, de.vat_src_code,';
1056 $sql .= ' de.localtax1_tx, de.localtax2_tx, de.localtax1_type, de.localtax2_type,';
1057 $sql .= ' de.fk_ecm_files,';
1058 $sql .= ' de.total_ht, de.total_tva, de.total_ttc,';
1059 $sql .= ' de.total_localtax1, de.total_localtax2, de.rule_warning_message,';
1060 $sql .= ' ctf.code as code_type_fees, ctf.label as label_type_fees, ctf.accountancy_code as accountancy_code_type_fees,';
1061 $sql .= ' p.ref as ref_projet, p.title as title_projet';
1062 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as de';
1063 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_type_fees as ctf ON de.fk_c_type_fees = ctf.id';
1064 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as p ON de.fk_projet = p.rowid';
1065 $sql .= " WHERE de.".$this->fk_element." = ".((int) $this->id);
1066 if (getDolGlobalString('EXPENSEREPORT_LINES_SORTED_BY_ROWID')) {
1067 $sql .= ' ORDER BY de.rang ASC, de.rowid ASC';
1068 } else {
1069 $sql .= ' ORDER BY de.rang ASC, de.date ASC';
1070 }
1071
1072 $resql = $this->db->query($sql);
1073 if ($resql) {
1074 $num = $this->db->num_rows($resql);
1075 $i = 0;
1076 while ($i < $num) {
1077 $objp = $this->db->fetch_object($resql);
1078
1079 $deplig = new ExpenseReportLine($this->db);
1080
1081 $deplig->rowid = $objp->rowid;
1082 $deplig->id = $objp->rowid;
1083 $deplig->comments = $objp->comments;
1084 $deplig->qty = $objp->qty;
1085 $deplig->value_unit = $objp->value_unit;
1086 $deplig->date = $objp->date;
1087 $deplig->dates = $this->db->jdate($objp->date);
1088
1089 $deplig->fk_expensereport = $objp->fk_expensereport;
1090 $deplig->fk_c_type_fees = $objp->fk_c_type_fees;
1091 $deplig->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
1092 $deplig->fk_projet = $objp->fk_project; // deprecated
1093 $deplig->fk_project = $objp->fk_project;
1094 $deplig->fk_ecm_files = $objp->fk_ecm_files;
1095
1096 $deplig->total_ht = $objp->total_ht;
1097 $deplig->total_tva = $objp->total_tva;
1098 $deplig->total_ttc = $objp->total_ttc;
1099 $deplig->total_localtax1 = $objp->total_localtax1;
1100 $deplig->total_localtax2 = $objp->total_localtax2;
1101
1102 $deplig->type_fees_code = empty($objp->code_type_fees) ? 'TF_OTHER' : $objp->code_type_fees;
1103 $deplig->type_fees_libelle = $objp->label_type_fees;
1104 $deplig->type_fees_accountancy_code = $objp->accountancy_code_type_fees;
1105
1106 $deplig->tva_tx = $objp->tva_tx;
1107 $deplig->vatrate = $objp->tva_tx;
1108 $deplig->vat_src_code = $objp->vat_src_code;
1109 $deplig->localtax1_tx = $objp->localtax1_tx;
1110 $deplig->localtax2_tx = $objp->localtax2_tx;
1111 $deplig->localtax1_type = $objp->localtax1_type;
1112 $deplig->localtax2_type = $objp->localtax2_type;
1113
1114 $deplig->projet_ref = $objp->ref_projet;
1115 $deplig->projet_title = $objp->title_projet;
1116
1117 $deplig->rule_warning_message = $objp->rule_warning_message;
1118
1119 $deplig->rang = $objp->rang;
1120
1121 $this->lines[$i] = $deplig;
1122
1123 $i++;
1124 }
1125 $this->db->free($resql);
1126 return 1;
1127 } else {
1128 $this->error = $this->db->lasterror();
1129 dol_syslog(get_class($this)."::fetch_lines: Error ".$this->error, LOG_ERR);
1130 return -3;
1131 }
1132 }
1133
1134
1142 public function delete(User $user = null, $notrigger = false)
1143 {
1144 global $conf;
1145 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1146
1147 $error = 0;
1148
1149 $this->db->begin();
1150
1151 if (!$notrigger) {
1152 // Call trigger
1153 $result = $this->call_trigger('EXPENSE_REPORT_DELETE', $user);
1154 if ($result < 0) {
1155 $error++;
1156 }
1157 // End call triggers
1158 }
1159
1160 // Delete extrafields of lines and lines
1161 if (!$error && !empty($this->table_element_line)) {
1162 $tabletodelete = $this->table_element_line;
1163 //$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).")";
1164 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id);
1165 if (!$this->db->query($sql)) {
1166 $error++;
1167 $this->error = $this->db->lasterror();
1168 $this->errors[] = $this->error;
1169 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1170 }
1171 }
1172
1173 if (!$error) {
1174 // Delete linked object
1175 $res = $this->deleteObjectLinked();
1176 if ($res < 0) {
1177 $error++;
1178 }
1179 }
1180
1181 if (!$error) {
1182 // Delete linked contacts
1183 $res = $this->delete_linked_contact();
1184 if ($res < 0) {
1185 $error++;
1186 }
1187 }
1188
1189 // Removed extrafields of object
1190 if (!$error) {
1191 $result = $this->deleteExtraFields();
1192 if ($result < 0) {
1193 $error++;
1194 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1195 }
1196 }
1197
1198 // Delete main record
1199 if (!$error) {
1200 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".((int) $this->id);
1201 $res = $this->db->query($sql);
1202 if (!$res) {
1203 $error++;
1204 $this->error = $this->db->lasterror();
1205 $this->errors[] = $this->error;
1206 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1207 }
1208 }
1209
1210 // Delete record into ECM index and physically
1211 if (!$error) {
1212 $res = $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
1213 $res = $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive
1214 if (!$res) {
1215 $error++;
1216 }
1217 }
1218
1219 if (!$error) {
1220 // We remove directory
1221 $ref = dol_sanitizeFileName($this->ref);
1222 if ($conf->expensereport->multidir_output[$this->entity] && !empty($this->ref)) {
1223 $dir = $conf->expensereport->multidir_output[$this->entity]."/".$ref;
1224 $file = $dir."/".$ref.".pdf";
1225 if (file_exists($file)) {
1226 dol_delete_preview($this);
1227
1228 if (!dol_delete_file($file, 0, 0, 0, $this)) {
1229 $this->error = 'ErrorFailToDeleteFile';
1230 $this->errors[] = $this->error;
1231 $this->db->rollback();
1232 return 0;
1233 }
1234 }
1235 if (file_exists($dir)) {
1236 $res = @dol_delete_dir_recursive($dir);
1237 if (!$res) {
1238 $this->error = 'ErrorFailToDeleteDir';
1239 $this->errors[] = $this->error;
1240 $this->db->rollback();
1241 return 0;
1242 }
1243 }
1244 }
1245 }
1246
1247 if (!$error) {
1248 dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
1249 $this->db->commit();
1250 return 1;
1251 } else {
1252 $this->db->rollback();
1253 return -1;
1254 }
1255 }
1256
1264 public function setValidate($fuser, $notrigger = 0)
1265 {
1266 global $conf, $langs, $user;
1267
1268 $error = 0;
1269 $now = dol_now();
1270
1271 // Protection
1272 if ($this->status == self::STATUS_VALIDATED) {
1273 dol_syslog(get_class($this)."::valid action abandonned: already validated", LOG_WARNING);
1274 return 0;
1275 }
1276
1277 $this->date_valid = $now; // Required for the getNextNum later.
1278
1279 // Define new ref
1280 if (!$error && (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
1281 $num = $this->getNextNumRef();
1282 } else {
1283 $num = $this->ref;
1284 }
1285 if (empty($num) || $num < 0) {
1286 return -1;
1287 }
1288
1289 $this->newref = dol_sanitizeFileName($num);
1290
1291 $this->db->begin();
1292
1293 // Validate
1294 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1295 $sql .= " SET ref = '".$this->db->escape($num)."',";
1296 $sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
1297 $sql .= " date_valid = '".$this->db->idate($this->date_valid)."',";
1298 $sql .= " fk_user_valid = ".((int) $user->id);
1299 $sql .= " WHERE rowid = ".((int) $this->id);
1300
1301 $resql = $this->db->query($sql);
1302 if ($resql) {
1303 if (!$error && !$notrigger) {
1304 // Call trigger
1305 $result = $this->call_trigger('EXPENSE_REPORT_VALIDATE', $fuser);
1306 if ($result < 0) {
1307 $error++;
1308 }
1309 // End call triggers
1310 }
1311
1312 if (!$error) {
1313 $this->oldref = $this->ref;
1314
1315 // Rename directory if dir was a temporary ref
1316 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
1317 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1318
1319 // Now we rename also files into index
1320 $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)."'";
1321 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'expensereport/".$this->db->escape($this->ref)."' AND entity = ".((int) $this->entity);
1322 $resql = $this->db->query($sql);
1323 if (!$resql) {
1324 $error++;
1325 $this->error = $this->db->lasterror();
1326 }
1327 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'expensereport/".$this->db->escape($this->newref)."'";
1328 $sql .= " WHERE filepath = 'expensereport/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1329 $resql = $this->db->query($sql);
1330 if (!$resql) {
1331 $error++;
1332 $this->error = $this->db->lasterror();
1333 }
1334
1335 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1336 $oldref = dol_sanitizeFileName($this->ref);
1337 $newref = dol_sanitizeFileName($num);
1338 $dirsource = $conf->expensereport->multidir_output[$this->entity].'/'.$oldref;
1339 $dirdest = $conf->expensereport->multidir_output[$this->entity].'/'.$newref;
1340 if (!$error && file_exists($dirsource)) {
1341 dol_syslog(get_class($this)."::setValidate() rename dir ".$dirsource." into ".$dirdest);
1342
1343 if (@rename($dirsource, $dirdest)) {
1344 dol_syslog("Rename ok");
1345 // Rename docs starting with $oldref with $newref
1346 $listoffiles = dol_dir_list($dirdest, 'files', 1, '^'.preg_quote($oldref, '/'));
1347 foreach ($listoffiles as $fileentry) {
1348 $dirsource = $fileentry['name'];
1349 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1350 $dirsource = $fileentry['path'].'/'.$dirsource;
1351 $dirdest = $fileentry['path'].'/'.$dirdest;
1352 @rename($dirsource, $dirdest);
1353 }
1354 }
1355 }
1356 }
1357 }
1358
1359 // Set new ref and current status
1360 if (!$error) {
1361 $this->ref = $num;
1363 }
1364
1365 if (empty($error)) {
1366 $this->db->commit();
1367 return 1;
1368 } else {
1369 $this->db->rollback();
1370 $this->error = $this->db->error();
1371 return -2;
1372 }
1373 } else {
1374 $this->db->rollback();
1375 $this->error = $this->db->lasterror();
1376 return -1;
1377 }
1378 }
1379
1380 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1387 public function set_save_from_refuse($fuser)
1388 {
1389 // phpcs:enable
1390 // Sélection de la date de début de la NDF
1391 $sql = 'SELECT date_debut';
1392 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
1393 $sql .= " WHERE rowid = ".((int) $this->id);
1394
1395 $result = $this->db->query($sql);
1396
1397 $objp = $this->db->fetch_object($result);
1398
1399 $this->date_debut = $this->db->jdate($objp->date_debut);
1400
1401 if ($this->status != self::STATUS_VALIDATED) {
1402 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1403 $sql .= " SET fk_statut = ".self::STATUS_VALIDATED;
1404 $sql .= " WHERE rowid = ".((int) $this->id);
1405
1406 dol_syslog(get_class($this)."::set_save_from_refuse", LOG_DEBUG);
1407
1408 if ($this->db->query($sql)) {
1409 return 1;
1410 } else {
1411 $this->error = $this->db->lasterror();
1412 return -1;
1413 }
1414 } else {
1415 dol_syslog(get_class($this)."::set_save_from_refuse expensereport already with save status", LOG_WARNING);
1416 }
1417
1418 return 0;
1419 }
1420
1428 public function setApproved($fuser, $notrigger = 0)
1429 {
1430 $now = dol_now();
1431 $error = 0;
1432
1433 // date approval
1434 $this->date_approve = $now;
1435 if ($this->status != self::STATUS_APPROVED) {
1436 $this->db->begin();
1437
1438 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1439 $sql .= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = ".self::STATUS_APPROVED.", fk_user_approve = ".((int) $fuser->id).",";
1440 $sql .= " date_approve='".$this->db->idate($this->date_approve)."'";
1441 $sql .= " WHERE rowid = ".((int) $this->id);
1442 if ($this->db->query($sql)) {
1443 if (!$notrigger) {
1444 // Call trigger
1445 $result = $this->call_trigger('EXPENSE_REPORT_APPROVE', $fuser);
1446
1447 if ($result < 0) {
1448 $error++;
1449 }
1450 // End call triggers
1451 }
1452
1453 if (empty($error)) {
1454 $this->db->commit();
1455 return 1;
1456 } else {
1457 $this->db->rollback();
1458 $this->error = $this->db->error();
1459 return -2;
1460 }
1461 } else {
1462 $this->db->rollback();
1463 $this->error = $this->db->lasterror();
1464 return -1;
1465 }
1466 } else {
1467 dol_syslog(get_class($this)."::setApproved expensereport already with approve status", LOG_WARNING);
1468 }
1469
1470 return 0;
1471 }
1472
1481 public function setDeny($fuser, $details, $notrigger = 0)
1482 {
1483 $now = dol_now();
1484 $error = 0;
1485
1486 // date de refus
1487 if ($this->status != self::STATUS_REFUSED) {
1488 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1489 $sql .= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = ".self::STATUS_REFUSED.", fk_user_refuse = ".((int) $fuser->id).",";
1490 $sql .= " date_refuse='".$this->db->idate($now)."',";
1491 $sql .= " detail_refuse='".$this->db->escape($details)."',";
1492 $sql .= " fk_user_approve = NULL";
1493 $sql .= " WHERE rowid = ".((int) $this->id);
1494 if ($this->db->query($sql)) {
1495 $this->fk_statut = 99; // deprecated
1496 $this->status = 99;
1497 $this->fk_user_refuse = $fuser->id;
1498 $this->detail_refuse = $details;
1499 $this->date_refuse = $now;
1500
1501 if (!$notrigger) {
1502 // Call trigger
1503 $result = $this->call_trigger('EXPENSE_REPORT_DENY', $fuser);
1504
1505 if ($result < 0) {
1506 $error++;
1507 }
1508 // End call triggers
1509 }
1510
1511 if (empty($error)) {
1512 $this->db->commit();
1513 return 1;
1514 } else {
1515 $this->db->rollback();
1516 $this->error = $this->db->error();
1517 return -2;
1518 }
1519 } else {
1520 $this->db->rollback();
1521 $this->error = $this->db->lasterror();
1522 return -1;
1523 }
1524 } else {
1525 dol_syslog(get_class($this)."::setDeny expensereport already with refuse status", LOG_WARNING);
1526 }
1527
1528 return 0;
1529 }
1530
1531 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1541 public function set_unpaid($fuser, $notrigger = 0)
1542 {
1543 // phpcs:enable
1544 dol_syslog(get_class($this)."::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE);
1545 return $this->setUnpaid($fuser, $notrigger);
1546 }
1547
1555 public function setUnpaid($fuser, $notrigger = 0)
1556 {
1557 $error = 0;
1558
1559 if ($this->paid) {
1560 $this->db->begin();
1561
1562 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1563 $sql .= " SET paid = 0, fk_statut = ".self::STATUS_APPROVED;
1564 $sql .= " WHERE rowid = ".((int) $this->id);
1565
1566 dol_syslog(get_class($this)."::set_unpaid", LOG_DEBUG);
1567
1568 if ($this->db->query($sql)) {
1569 if (!$notrigger) {
1570 // Call trigger
1571 $result = $this->call_trigger('EXPENSE_REPORT_UNPAID', $fuser);
1572
1573 if ($result < 0) {
1574 $error++;
1575 }
1576 // End call triggers
1577 }
1578
1579 if (empty($error)) {
1580 $this->db->commit();
1581 return 1;
1582 } else {
1583 $this->db->rollback();
1584 $this->error = $this->db->error();
1585 return -2;
1586 }
1587 } else {
1588 $this->db->rollback();
1589 $this->error = $this->db->error();
1590 return -1;
1591 }
1592 } else {
1593 dol_syslog(get_class($this)."::set_unpaid expensereport already with unpaid status", LOG_WARNING);
1594 }
1595
1596 return 0;
1597 }
1598
1599 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1608 public function set_cancel($fuser, $detail, $notrigger = 0)
1609 {
1610 // phpcs:enable
1611 $error = 0;
1612 $this->date_cancel = $this->db->idate(dol_now());
1613 if ($this->status != self::STATUS_CANCELED) {
1614 $this->db->begin();
1615
1616 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1617 $sql .= " SET fk_statut = ".self::STATUS_CANCELED.", fk_user_cancel = ".((int) $fuser->id);
1618 $sql .= ", date_cancel='".$this->db->idate($this->date_cancel)."'";
1619 $sql .= ", detail_cancel='".$this->db->escape($detail)."'";
1620 $sql .= " WHERE rowid = ".((int) $this->id);
1621
1622 dol_syslog(get_class($this)."::set_cancel", LOG_DEBUG);
1623
1624 if ($this->db->query($sql)) {
1625 if (!$notrigger) {
1626 // Call trigger
1627 $result = $this->call_trigger('EXPENSE_REPORT_CANCEL', $fuser);
1628
1629 if ($result < 0) {
1630 $error++;
1631 }
1632 // End call triggers
1633 }
1634
1635 if (empty($error)) {
1636 $this->db->commit();
1637 return 1;
1638 } else {
1639 $this->db->rollback();
1640 $this->error = $this->db->error();
1641 return -2;
1642 }
1643 } else {
1644 $this->db->rollback();
1645 $this->error = $this->db->error();
1646 return -1;
1647 }
1648 } else {
1649 dol_syslog(get_class($this)."::set_cancel expensereport already with cancel status", LOG_WARNING);
1650 }
1651 return 0;
1652 }
1653
1659 public function getNextNumRef()
1660 {
1661 global $langs, $conf;
1662 $langs->load("trips");
1663
1664 if (getDolGlobalString('EXPENSEREPORT_ADDON')) {
1665 $mybool = false;
1666
1667 $file = getDolGlobalString('EXPENSEREPORT_ADDON') . ".php";
1668 $classname = $conf->global->EXPENSEREPORT_ADDON;
1669
1670 // Include file with class
1671 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1672 foreach ($dirmodels as $reldir) {
1673 $dir = dol_buildpath($reldir."core/modules/expensereport/");
1674
1675 // Load file with numbering class (if found)
1676 $mybool |= @include_once $dir.$file;
1677 }
1678
1679 if ($mybool === false) {
1680 dol_print_error('', "Failed to include file ".$file);
1681 return '';
1682 }
1683
1684 $obj = new $classname();
1685 $numref = $obj->getNextValue($this);
1686
1687 if ($numref != "") {
1688 return $numref;
1689 } else {
1690 $this->error = $obj->error;
1691 $this->errors = $obj->errors;
1692 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1693 return -1;
1694 }
1695 } else {
1696 $this->error = "Error_EXPENSEREPORT_ADDON_NotDefined";
1697 return -2;
1698 }
1699 }
1700
1708 public function getTooltipContentArray($params)
1709 {
1710 global $conf, $langs;
1711
1712 $langs->load('expensereport');
1713
1714 $nofetch = !empty($params['nofetch']);
1715 $moretitle = $params['moretitle'] ?? '';
1716
1717 $datas = array();
1718 $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("ExpenseReport").'</u>';
1719 if (isset($this->status)) {
1720 $datas['picto'] .= ' '.$this->getLibStatut(5);
1721 }
1722 if ($moretitle) {
1723 $datas['picto'] .= ' - '.$moretitle;
1724 }
1725 if (!empty($this->ref)) {
1726 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1727 }
1728 if (!empty($this->total_ht)) {
1729 $datas['total_ht'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
1730 }
1731 if (!empty($this->total_tva)) {
1732 $datas['total_tva'] = '<br><b>'.$langs->trans('VAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
1733 }
1734 if (!empty($this->total_ttc)) {
1735 $datas['total_ttc'] = '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
1736 }
1737
1738 return $datas;
1739 }
1740
1753 public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1)
1754 {
1755 global $langs, $conf, $hookmanager;
1756
1757 $result = '';
1758
1759 $url = DOL_URL_ROOT.'/expensereport/card.php?id='.$this->id;
1760
1761 if ($short) {
1762 return $url;
1763 }
1764
1765 $params = [
1766 'id' => $this->id,
1767 'objecttype' => $this->element,
1768 'option' => $option,
1769 'moretitle' => $moretitle,
1770 'nofetch' => 1,
1771 ];
1772 $classfortooltip = 'classfortooltip';
1773 $dataparams = '';
1774 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1775 $classfortooltip = 'classforajaxtooltip';
1776 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1777 $label = '';
1778 } else {
1779 $label = implode($this->getTooltipContentArray($params));
1780 }
1781
1782 if ($option != 'nolink') {
1783 // Add param to save lastsearch_values or not
1784 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1785 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1786 $add_save_lastsearch_values = 1;
1787 }
1788 if ($add_save_lastsearch_values) {
1789 $url .= '&save_lastsearch_values=1';
1790 }
1791 }
1792
1793 $ref = $this->ref;
1794 if (empty($ref)) {
1795 $ref = $this->id;
1796 }
1797
1798 $linkclose = '';
1799 if (empty($notooltip)) {
1800 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1801 $label = $langs->trans("ShowExpenseReport");
1802 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1803 }
1804 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1805 $linkclose .= $dataparams.' class="'.$classfortooltip.'"';
1806 }
1807
1808 $linkstart = '<a href="'.$url.'"';
1809 $linkstart .= $linkclose.'>';
1810 $linkend = '</a>';
1811
1812 $result .= $linkstart;
1813 if ($withpicto) {
1814 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'"'), 0, 0, $notooltip ? 0 : 1);
1815 }
1816 if ($withpicto != 2) {
1817 $result .= ($max ? dol_trunc($ref, $max) : $ref);
1818 }
1819 $result .= $linkend;
1820
1821 global $action;
1822 $hookmanager->initHooks(array($this->element . 'dao'));
1823 $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1824 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1825 if ($reshook > 0) {
1826 $result = $hookmanager->resPrint;
1827 } else {
1828 $result .= $hookmanager->resPrint;
1829 }
1830 return $result;
1831 }
1832
1833 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1841 public function update_totaux_add($ligne_total_ht, $ligne_total_tva)
1842 {
1843 // phpcs:enable
1844 $this->total_ht = $this->total_ht + $ligne_total_ht;
1845 $this->total_tva = $this->total_tva + $ligne_total_tva;
1846 $this->total_ttc = $this->total_ht + $this->total_tva;
1847
1848 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
1849 $sql .= " total_ht = ".$this->total_ht;
1850 $sql .= " , total_ttc = ".$this->total_ttc;
1851 $sql .= " , total_tva = ".$this->total_tva;
1852 $sql .= " WHERE rowid = ".((int) $this->id);
1853
1854 $result = $this->db->query($sql);
1855 if ($result) {
1856 return 1;
1857 } else {
1858 $this->error = $this->db->error();
1859 return -1;
1860 }
1861 }
1862
1878 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)
1879 {
1880 global $conf, $langs, $mysoc;
1881
1882 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);
1883
1884 if ($this->status == self::STATUS_DRAFT) {
1885 if (empty($qty)) {
1886 $qty = 0;
1887 }
1888 if (empty($fk_c_type_fees) || $fk_c_type_fees < 0) {
1889 $fk_c_type_fees = 0;
1890 }
1891 if (empty($fk_c_exp_tax_cat) || $fk_c_exp_tax_cat < 0) {
1892 $fk_c_exp_tax_cat = 0;
1893 }
1894 if (empty($vatrate) || $vatrate < 0) {
1895 $vatrate = 0;
1896 }
1897 if (empty($date)) {
1898 $date = '';
1899 }
1900 if (empty($fk_project)) {
1901 $fk_project = 0;
1902 }
1903
1904 $qty = price2num($qty);
1905 if (!preg_match('/\s*\‍((.*)\‍)/', $vatrate)) {
1906 $vatrate = price2num($vatrate); // $txtva can have format '5.0 (XXX)' or '5'
1907 }
1908 $up = price2num($up);
1909
1910 $this->db->begin();
1911
1912 $this->line = new ExpenseReportLine($this->db);
1913
1914 // We don't know seller and buyer for expense reports
1915 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
1916 $seller->tva_assuj = 1; // Most seller uses vat
1917 $buyer = new Societe($this->db);
1918
1919 $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller);
1920
1921 $vat_src_code = '';
1922 $reg = array();
1923 if (preg_match('/\s*\‍((.*)\‍)/', $vatrate, $reg)) {
1924 $vat_src_code = $reg[1];
1925 $vatrate = preg_replace('/\s*\‍(.*\‍)/', '', $vatrate); // Remove code into vatrate.
1926 }
1927 $vatrate = preg_replace('/\*/', '', $vatrate);
1928
1929 $tmp = calcul_price_total($qty, $up, 0, $vatrate, -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
1930
1931 $this->line->value_unit = $up;
1932
1933 $this->line->vat_src_code = $vat_src_code;
1934 $this->line->vatrate = price2num($vatrate);
1935 $this->line->localtax1_tx = $localtaxes_type[1];
1936 $this->line->localtax2_tx = $localtaxes_type[3];
1937 $this->line->localtax1_type = $localtaxes_type[0];
1938 $this->line->localtax2_type = $localtaxes_type[2];
1939
1940 $this->line->total_ttc = $tmp[2];
1941 $this->line->total_ht = $tmp[0];
1942 $this->line->total_tva = $tmp[1];
1943 $this->line->total_localtax1 = $tmp[9];
1944 $this->line->total_localtax2 = $tmp[10];
1945
1946 $this->line->fk_expensereport = $this->id;
1947 $this->line->qty = $qty;
1948 $this->line->date = $date;
1949 $this->line->fk_c_type_fees = $fk_c_type_fees;
1950 $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
1951 $this->line->comments = $comments;
1952 $this->line->fk_projet = $fk_project; // deprecated
1953 $this->line->fk_project = $fk_project;
1954
1955 $this->line->fk_ecm_files = $fk_ecm_files;
1956
1957 $this->applyOffset();
1958 $this->checkRules($type, $seller);
1959
1960 $result = $this->line->insert(0, true);
1961 if ($result > 0) {
1962 $result = $this->update_price(1); // This method is designed to add line from user input so total calculation must be done using 'auto' mode.
1963 if ($result > 0) {
1964 $this->db->commit();
1965 return $this->line->id;
1966 } else {
1967 $this->db->rollback();
1968 return -1;
1969 }
1970 } else {
1971 $this->error = $this->line->error;
1972 dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1973 $this->db->rollback();
1974 return -2;
1975 }
1976 } else {
1977 dol_syslog(get_class($this)."::addline status of expense report must be Draft to allow use of ->addline()", LOG_ERR);
1978 $this->error = 'ErrorExpenseNotDraft';
1979 return -3;
1980 }
1981 }
1982
1990 public function checkRules($type = 0, $seller = '')
1991 {
1992 global $user, $conf, $db, $langs, $mysoc;
1993
1994 $langs->load('trips');
1995
1996 // We don't know seller and buyer for expense reports
1997 if (!is_object($seller)) {
1998 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
1999 $seller->tva_assuj = 1; // Most seller uses vat
2000 }
2001
2002 $expensereportrule = new ExpenseReportRule($db);
2003 $rulestocheck = $expensereportrule->getAllRule($this->line->fk_c_type_fees, $this->line->date, $this->fk_user_author);
2004
2005 $violation = 0;
2006 $rule_warning_message_tab = array();
2007
2008 $current_total_ttc = $this->line->total_ttc;
2009 $new_current_total_ttc = $this->line->total_ttc;
2010
2011 // check if one is violated
2012 foreach ($rulestocheck as $rule) {
2013 if (in_array($rule->code_expense_rules_type, array('EX_DAY', 'EX_MON', 'EX_YEA'))) {
2014 $amount_to_test = $this->line->getExpAmount($rule, $this->fk_user_author, $rule->code_expense_rules_type);
2015 } else {
2016 $amount_to_test = $current_total_ttc; // EX_EXP
2017 }
2018
2019 $amount_to_test = $amount_to_test - $current_total_ttc + $new_current_total_ttc; // if amount as been modified by a previous rule
2020
2021 if ($amount_to_test > $rule->amount) {
2022 $violation++;
2023
2024 if ($rule->restrictive) {
2025 $this->error = 'ExpenseReportConstraintViolationError';
2026 $this->errors[] = $this->error;
2027
2028 $new_current_total_ttc -= $amount_to_test - $rule->amount; // ex, entered 16€, limit 12€, subtracts 4€;
2029 $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));
2030 } else {
2031 $this->error = 'ExpenseReportConstraintViolationWarning';
2032 $this->errors[] = $this->error;
2033
2034 $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));
2035 }
2036
2037 // No break, we sould test if another rule is violated
2038 }
2039 }
2040
2041 $this->line->rule_warning_message = implode('\n', $rule_warning_message_tab);
2042
2043 if ($violation > 0) {
2044 $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);
2045
2046 $this->line->value_unit = $tmp[5];
2047 $this->line->total_ttc = $tmp[2];
2048 $this->line->total_ht = $tmp[0];
2049 $this->line->total_tva = $tmp[1];
2050 $this->line->total_localtax1 = $tmp[9];
2051 $this->line->total_localtax2 = $tmp[10];
2052
2053 return false;
2054 } else {
2055 return true;
2056 }
2057 }
2058
2066 public function applyOffset($type = 0, $seller = '')
2067 {
2068 global $conf, $mysoc;
2069
2070 if (!getDolGlobalString('MAIN_USE_EXPENSE_IK')) {
2071 return false;
2072 }
2073
2074 $userauthor = new User($this->db);
2075 if ($userauthor->fetch($this->fk_user_author) <= 0) {
2076 $this->error = 'ErrorCantFetchUser';
2077 $this->errors[] = 'ErrorCantFetchUser';
2078 return false;
2079 }
2080
2081 // We don't know seller and buyer for expense reports
2082 if (!is_object($seller)) {
2083 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
2084 $seller->tva_assuj = 1; // Most seller uses vat
2085 }
2086
2087 $expenseik = new ExpenseReportIk($this->db);
2088 $range = $expenseik->getRangeByUser($userauthor, $this->line->fk_c_exp_tax_cat);
2089
2090 if (empty($range)) {
2091 $this->error = 'ErrorNoRangeAvailable';
2092 $this->errors[] = 'ErrorNoRangeAvailable';
2093 return false;
2094 }
2095
2096 if (getDolGlobalString('MAIN_EXPENSE_APPLY_ENTIRE_OFFSET')) {
2097 $ikoffset = $range->ikoffset;
2098 } else {
2099 $ikoffset = $range->ikoffset / 12; // The amount of offset is a global value for the year
2100 }
2101
2102 // Test if ikoffset has been applied for the current month
2103 if (!$this->offsetAlreadyGiven()) {
2104 $new_up = $range->coef + ($ikoffset / $this->line->qty);
2105 $tmp = calcul_price_total($this->line->qty, $new_up, 0, $this->line->vatrate, 0, 0, 0, 'TTC', 0, $type, $seller);
2106
2107 $this->line->value_unit = $tmp[5];
2108 $this->line->total_ttc = $tmp[2];
2109 $this->line->total_ht = $tmp[0];
2110 $this->line->total_tva = $tmp[1];
2111 $this->line->total_localtax1 = $tmp[9];
2112 $this->line->total_localtax2 = $tmp[10];
2113
2114 return true;
2115 }
2116
2117 return false;
2118 }
2119
2125 public function offsetAlreadyGiven()
2126 {
2127 $sql = 'SELECT e.rowid FROM '.MAIN_DB_PREFIX.'expensereport e';
2128 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."expensereport_det d ON (e.rowid = d.fk_expensereport)";
2129 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."c_type_fees f ON (d.fk_c_type_fees = f.id AND f.code = 'EX_KME')";
2130 $sql .= " WHERE e.fk_user_author = ".(int) $this->fk_user_author;
2131 $sql .= " AND YEAR(d.date) = '".dol_print_date($this->line->date, '%Y')."' AND MONTH(d.date) = '".dol_print_date($this->line->date, '%m')."'";
2132 if (!empty($this->line->id)) {
2133 $sql .= ' AND d.rowid <> '.((int) $this->line->id);
2134 }
2135
2136 dol_syslog(get_class($this)."::offsetAlreadyGiven");
2137 $resql = $this->db->query($sql);
2138 if ($resql) {
2139 $num = $this->db->num_rows($resql);
2140 if ($num > 0) {
2141 return true;
2142 }
2143 } else {
2144 dol_print_error($this->db);
2145 }
2146
2147 return false;
2148 }
2149
2167 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)
2168 {
2169 global $user, $mysoc;
2170
2171 if ($this->status == self::STATUS_DRAFT || $this->status == self::STATUS_REFUSED) {
2172 $this->db->begin();
2173
2174 $error = 0;
2175 $type = 0; // TODO What if type is service ?
2176
2177 // We don't know seller and buyer for expense reports
2178 $seller = $mysoc; // We use same than current company (expense report are often done in same country)
2179 $seller->tva_assuj = 1; // Most seller uses vat
2180 $seller->localtax1_assuj = $mysoc->localtax1_assuj; // We don't know, we reuse the state of company
2181 $seller->localtax2_assuj = $mysoc->localtax1_assuj; // We don't know, we reuse the state of company
2182 $buyer = new Societe($this->db);
2183
2184 $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller);
2185
2186 // Clean vat code
2187 $reg = array();
2188 $vat_src_code = '';
2189 if (preg_match('/\‍((.*)\‍)/', $vatrate, $reg)) {
2190 $vat_src_code = $reg[1];
2191 $vatrate = preg_replace('/\s*\‍(.*\‍)/', '', $vatrate); // Remove code into vatrate.
2192 }
2193 $vatrate = preg_replace('/\*/', '', $vatrate);
2194
2195 $tmp = calcul_price_total($qty, $value_unit, 0, $vatrate, -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
2196 //var_dump($vatrate);var_dump($localtaxes_type);var_dump($tmp);exit;
2197 // calcul total of line
2198 //$total_ttc = price2num($qty*$value_unit, 'MT');
2199
2200 $tx_tva = $vatrate / 100;
2201 $tx_tva = $tx_tva + 1;
2202
2203 $this->line = new ExpenseReportLine($this->db);
2204 $this->line->comments = $comments;
2205 $this->line->qty = $qty;
2206 $this->line->value_unit = $value_unit;
2207 $this->line->date = $date;
2208
2209 $this->line->fk_expensereport = $expensereport_id;
2210 $this->line->fk_c_type_fees = $type_fees_id;
2211 $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
2212 $this->line->fk_projet = $projet_id; // deprecated
2213 $this->line->fk_project = $projet_id;
2214
2215 $this->line->vat_src_code = $vat_src_code;
2216 $this->line->vatrate = price2num($vatrate);
2217 $this->line->localtax1_tx = $localtaxes_type[1];
2218 $this->line->localtax2_tx = $localtaxes_type[3];
2219 $this->line->localtax1_type = $localtaxes_type[0];
2220 $this->line->localtax2_type = $localtaxes_type[2];
2221
2222 $this->line->total_ttc = $tmp[2];
2223 $this->line->total_ht = $tmp[0];
2224 $this->line->total_tva = $tmp[1];
2225 $this->line->total_localtax1 = $tmp[9];
2226 $this->line->total_localtax2 = $tmp[10];
2227
2228 $this->line->fk_ecm_files = $fk_ecm_files;
2229
2230 $this->line->id = ((int) $rowid);
2231
2232 // Select des infos sur le type fees
2233 $sql = "SELECT c.code as code_type_fees, c.label as label_type_fees";
2234 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
2235 $sql .= " WHERE c.id = ".((int) $type_fees_id);
2236 $resql = $this->db->query($sql);
2237 if ($resql) {
2238 $objp_fees = $this->db->fetch_object($resql);
2239 $this->line->type_fees_code = $objp_fees->code_type_fees;
2240 $this->line->type_fees_libelle = $objp_fees->label_type_fees;
2241 $this->db->free($resql);
2242 }
2243
2244 // Select des informations du projet
2245 $sql = "SELECT p.ref as ref_projet, p.title as title_projet";
2246 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
2247 $sql .= " WHERE p.rowid = ".((int) $projet_id);
2248 $resql = $this->db->query($sql);
2249 if ($resql) {
2250 $objp_projet = $this->db->fetch_object($resql);
2251 $this->line->projet_ref = $objp_projet->ref_projet;
2252 $this->line->projet_title = $objp_projet->title_projet;
2253 $this->db->free($resql);
2254 }
2255
2256 $this->applyOffset();
2257 $this->checkRules();
2258
2259 $result = $this->line->update($user);
2260 if ($result < 0) {
2261 $error++;
2262 }
2263
2264 if (!$error && !$notrigger) {
2265 // Call triggers
2266 $result = $this->call_trigger('EXPENSE_REPORT_DET_MODIFY', $user);
2267 if ($result < 0) {
2268 $error++;
2269 }
2270 // End call triggers
2271 }
2272
2273 if (!$error) {
2274 $this->db->commit();
2275 return 1;
2276 } else {
2277 $this->error = $this->line->error;
2278 $this->errors = $this->line->errors;
2279 $this->db->rollback();
2280 return -2;
2281 }
2282 }
2283
2284 return 0;
2285 }
2286
2295 public function deleteline($rowid, $fuser = '', $notrigger = 0)
2296 {
2297 $error=0;
2298
2299 $this->db->begin();
2300
2301 if (!$notrigger) {
2302 // Call triggers
2303 $result = $this->call_trigger('EXPENSE_REPORT_DET_DELETE', $fuser);
2304 if ($result < 0) {
2305 $error++;
2306 }
2307 // End call triggers
2308 }
2309
2310 $sql = ' DELETE FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2311 $sql .= ' WHERE rowid = '.((int) $rowid);
2312
2313 dol_syslog(get_class($this)."::deleteline sql=".$sql);
2314 $result = $this->db->query($sql);
2315
2316 if (!$result || $error > 0) {
2317 $this->error = $this->db->error();
2318 dol_syslog(get_class($this)."::deleteline Error ".$this->error, LOG_ERR);
2319 $this->db->rollback();
2320 return -1;
2321 }
2322
2323 $this->update_price(1);
2324
2325 $this->db->commit();
2326
2327 return 1;
2328 }
2329
2330 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2339 public function periode_existe($fuser, $date_debut, $date_fin)
2340 {
2341 global $conf;
2342
2343 // phpcs:enable
2344 $sql = "SELECT rowid, date_debut, date_fin";
2345 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
2346 $sql .= " WHERE entity = ".((int) $conf->entity); // not shared, only for the current entity
2347 $sql .= " AND fk_user_author = ".((int) $fuser->id);
2348
2349 dol_syslog(get_class($this)."::periode_existe sql=".$sql);
2350 $result = $this->db->query($sql);
2351 if ($result) {
2352 $num_rows = $this->db->num_rows($result);
2353 $i = 0;
2354
2355 if ($num_rows > 0) {
2356 $date_d_form = $date_debut;
2357 $date_f_form = $date_fin;
2358
2359 while ($i < $num_rows) {
2360 $objp = $this->db->fetch_object($result);
2361
2362 $date_d_req = $this->db->jdate($objp->date_debut); // 3
2363 $date_f_req = $this->db->jdate($objp->date_fin); // 4
2364
2365 if (!($date_f_form < $date_d_req || $date_d_form > $date_f_req)) {
2366 return $objp->rowid;
2367 }
2368
2369 $i++;
2370 }
2371
2372 return 0;
2373 } else {
2374 return 0;
2375 }
2376 } else {
2377 $this->error = $this->db->lasterror();
2378 dol_syslog(get_class($this)."::periode_existe Error ".$this->error, LOG_ERR);
2379 return -1;
2380 }
2381 }
2382
2383
2384 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2392 {
2393 // phpcs:enable
2394 $users_validator = array();
2395
2396 $sql = "SELECT DISTINCT ur.fk_user";
2397 $sql .= " FROM ".MAIN_DB_PREFIX."user_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2398 $sql .= " WHERE ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2399 $sql .= " UNION";
2400 $sql .= " SELECT DISTINCT ugu.fk_user";
2401 $sql .= " FROM ".MAIN_DB_PREFIX."usergroup_user as ugu, ".MAIN_DB_PREFIX."usergroup_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2402 $sql .= " WHERE ugu.fk_usergroup = ur.fk_usergroup AND ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2403 //print $sql;
2404
2405 dol_syslog(get_class($this)."::fetch_users_approver_expensereport sql=".$sql);
2406 $result = $this->db->query($sql);
2407 if ($result) {
2408 $num_rows = $this->db->num_rows($result);
2409 $i = 0;
2410 while ($i < $num_rows) {
2411 $objp = $this->db->fetch_object($result);
2412 array_push($users_validator, $objp->fk_user);
2413 $i++;
2414 }
2415 return $users_validator;
2416 } else {
2417 $this->error = $this->db->lasterror();
2418 dol_syslog(get_class($this)."::fetch_users_approver_expensereport Error ".$this->error, LOG_ERR);
2419 return -1;
2420 }
2421 }
2422
2434 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
2435 {
2436 global $conf;
2437
2438 $outputlangs->load("trips");
2439
2440 if (!dol_strlen($modele)) {
2441 if (!empty($this->model_pdf)) {
2442 $modele = $this->model_pdf;
2443 } elseif (getDolGlobalString('EXPENSEREPORT_ADDON_PDF')) {
2444 $modele = $conf->global->EXPENSEREPORT_ADDON_PDF;
2445 }
2446 }
2447
2448 if (!empty($modele)) {
2449 $modelpath = "core/modules/expensereport/doc/";
2450
2451 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2452 } else {
2453 return 0;
2454 }
2455 }
2456
2463 public function listOfTypes($active = 1)
2464 {
2465 global $langs;
2466 $ret = array();
2467 $sql = "SELECT id, code, label";
2468 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees";
2469 $sql .= " WHERE active = ".((int) $active);
2470 dol_syslog(get_class($this)."::listOfTypes", LOG_DEBUG);
2471 $result = $this->db->query($sql);
2472 if ($result) {
2473 $num = $this->db->num_rows($result);
2474 $i = 0;
2475 while ($i < $num) {
2476 $obj = $this->db->fetch_object($result);
2477 $ret[$obj->code] = (($langs->transnoentitiesnoconv($obj->code) != $obj->code) ? $langs->transnoentitiesnoconv($obj->code) : $obj->label);
2478 $i++;
2479 }
2480 } else {
2481 dol_print_error($this->db);
2482 }
2483 return $ret;
2484 }
2485
2486 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2492 public function load_state_board()
2493 {
2494 // phpcs:enable
2495 global $conf, $user;
2496
2497 $this->nb = array();
2498
2499 $sql = "SELECT count(ex.rowid) as nb";
2500 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2501 $sql .= " WHERE ex.fk_statut > 0";
2502 $sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2503 if (!$user->hasRight('expensereport', 'readall')) {
2504 $userchildids = $user->getAllChildIds(1);
2505 $sql .= " AND (ex.fk_user_author IN (".$this->db->sanitize(join(',', $userchildids)).")";
2506 $sql .= " OR ex.fk_user_validator IN (".$this->db->sanitize(join(',', $userchildids))."))";
2507 }
2508
2509 $resql = $this->db->query($sql);
2510 if ($resql) {
2511 while ($obj = $this->db->fetch_object($resql)) {
2512 $this->nb["expensereports"] = $obj->nb;
2513 }
2514 $this->db->free($resql);
2515 return 1;
2516 } else {
2517 dol_print_error($this->db);
2518 $this->error = $this->db->error();
2519 return -1;
2520 }
2521 }
2522
2523 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2531 public function load_board($user, $option = 'topay')
2532 {
2533 // phpcs:enable
2534 global $conf, $langs;
2535
2536 if ($user->socid) {
2537 return -1; // protection pour eviter appel par utilisateur externe
2538 }
2539
2540 $now = dol_now();
2541
2542 $sql = "SELECT ex.rowid, ex.date_valid";
2543 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2544 if ($option == 'toapprove') {
2545 $sql .= " WHERE ex.fk_statut = ".self::STATUS_VALIDATED;
2546 } else {
2547 $sql .= " WHERE ex.fk_statut = ".self::STATUS_APPROVED;
2548 }
2549 $sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2550 if (!$user->hasRight('expensereport', 'readall')) {
2551 $userchildids = $user->getAllChildIds(1);
2552 $sql .= " AND (ex.fk_user_author IN (".$this->db->sanitize(join(',', $userchildids)).")";
2553 $sql .= " OR ex.fk_user_validator IN (".$this->db->sanitize(join(',', $userchildids))."))";
2554 }
2555
2556 $resql = $this->db->query($sql);
2557 if ($resql) {
2558 $langs->load("trips");
2559
2560 $response = new WorkboardResponse();
2561 if ($option == 'toapprove') {
2562 $response->warning_delay = $conf->expensereport->approve->warning_delay / 60 / 60 / 24;
2563 $response->label = $langs->trans("ExpenseReportsToApprove");
2564 $response->labelShort = $langs->trans("ToApprove");
2565 $response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_VALIDATED;
2566 } else {
2567 $response->warning_delay = $conf->expensereport->payment->warning_delay / 60 / 60 / 24;
2568 $response->label = $langs->trans("ExpenseReportsToPay");
2569 $response->labelShort = $langs->trans("StatusToPay");
2570 $response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_APPROVED;
2571 }
2572 $response->img = img_object('', "trip");
2573
2574 while ($obj = $this->db->fetch_object($resql)) {
2575 $response->nbtodo++;
2576
2577 if ($option == 'toapprove') {
2578 if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->approve->warning_delay)) {
2579 $response->nbtodolate++;
2580 }
2581 } else {
2582 if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->payment->warning_delay)) {
2583 $response->nbtodolate++;
2584 }
2585 }
2586 }
2587
2588 return $response;
2589 } else {
2590 dol_print_error($this->db);
2591 $this->error = $this->db->error();
2592 return -1;
2593 }
2594 }
2595
2602 public function hasDelay($option)
2603 {
2604 global $conf;
2605
2606 // Only valid expenses reports
2607 if ($option == 'toapprove' && $this->status != 2) {
2608 return false;
2609 }
2610 if ($option == 'topay' && $this->status != 5) {
2611 return false;
2612 }
2613
2614 $now = dol_now();
2615 if ($option == 'toapprove') {
2616 return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->approve->warning_delay);
2617 } else {
2618 return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->payment->warning_delay);
2619 }
2620 }
2621
2627 public function getVentilExportCompta()
2628 {
2629 $alreadydispatched = 0;
2630
2631 $type = 'expense_report';
2632
2633 $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);
2634 $resql = $this->db->query($sql);
2635 if ($resql) {
2636 $obj = $this->db->fetch_object($resql);
2637 if ($obj) {
2638 $alreadydispatched = $obj->nb;
2639 }
2640 } else {
2641 $this->error = $this->db->lasterror();
2642 return -1;
2643 }
2644
2645 if ($alreadydispatched) {
2646 return 1;
2647 }
2648 return 0;
2649 }
2650
2656 public function getSumPayments()
2657 {
2658 $table = 'payment_expensereport';
2659 $field = 'fk_expensereport';
2660
2661 $sql = 'SELECT sum(amount) as amount';
2662 $sql .= ' FROM '.MAIN_DB_PREFIX.$table;
2663 $sql .= " WHERE ".$field." = ".((int) $this->id);
2664
2665 dol_syslog(get_class($this)."::getSumPayments", LOG_DEBUG);
2666 $resql = $this->db->query($sql);
2667 if ($resql) {
2668 $obj = $this->db->fetch_object($resql);
2669 $this->db->free($resql);
2670 return (empty($obj->amount) ? 0 : $obj->amount);
2671 } else {
2672 $this->error = $this->db->lasterror();
2673 return -1;
2674 }
2675 }
2676
2685 public function computeTotalKm($fk_cat, $qty, $tva)
2686 {
2687 global $langs, $db, $conf;
2688
2689 $cumulYearQty = 0;
2690 $ranges = array();
2691 $coef = 0;
2692
2693
2694 if ($fk_cat < 0) {
2695 $this->error = $langs->trans('ErrorBadParameterCat');
2696 return -1;
2697 }
2698
2699 if ($qty <= 0) {
2700 $this->error = $langs->trans('ErrorBadParameterQty');
2701 return -1;
2702 }
2703
2704 $currentUser = new User($db);
2705 $currentUser->fetch($this->fk_user);
2706 $currentUser->getrights('expensereport');
2707 //Clean
2708 $qty = price2num($qty);
2709
2710 $sql = " SELECT r.range_ik, t.ikoffset, t.coef";
2711 $sql .= " FROM ".MAIN_DB_PREFIX."expensereport_ik t";
2712 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_exp_tax_range r ON r.rowid = t.fk_range";
2713 $sql .= " WHERE t.fk_c_exp_tax_cat = ".(int) $fk_cat;
2714 $sql .= " ORDER BY r.range_ik ASC";
2715
2716 dol_syslog("expenseReport::computeTotalkm sql=".$sql, LOG_DEBUG);
2717
2718 $result = $this->db->query($sql);
2719
2720 if ($result) {
2721 if ($conf->global->EXPENSEREPORT_CALCULATE_MILEAGE_EXPENSE_COEFFICIENT_ON_CURRENT_YEAR) {
2722 $arrayDate = dol_getdate(dol_now());
2723 $sql = " SELECT count(n.qty) as cumul FROM ".MAIN_DB_PREFIX."expensereport_det n";
2724 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expensereport e ON e.rowid = n.fk_expensereport";
2725 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_type_fees tf ON tf.id = n.fk_c_type_fees";
2726 $sql.= " WHERE e.fk_user_author = ".(int) $this->fk_user_author;
2727 $sql.= " AND YEAR(n.date) = ".(int) $arrayDate['year'];
2728 $sql.= " AND tf.code = 'EX_KME' ";
2729 $sql.= " AND e.fk_statut = ".(int) ExpenseReport::STATUS_VALIDATED;
2730
2731 $resql = $this->db->query($sql);
2732
2733 if ($resql) {
2734 $obj = $this->db->fetch_object($resql);
2735 $cumulYearQty = $obj->cumul;
2736 }
2737
2738 $qty = $cumulYearQty + $qty;
2739 }
2740
2741 $num = $this->db->num_rows($result);
2742
2743 if ($num) {
2744 for ($i = 0; $i < $num; $i++) {
2745 $obj = $this->db->fetch_object($result);
2746
2747 $ranges[$i] = $obj;
2748 }
2749
2750
2751 for ($i = 0; $i < $num; $i++) {
2752 if ($i < ($num - 1)) {
2753 if ($qty > $ranges[$i]->range_ik && $qty < $ranges[$i+1]->range_ik) {
2754 $coef = $ranges[$i]->coef;
2755 $offset = $ranges[$i]->ikoffset;
2756 }
2757 } else {
2758 if ($qty > $ranges[$i]->range_ik) {
2759 $coef = $ranges[$i]->coef;
2760 $offset = $ranges[$i]->ikoffset;
2761 }
2762 }
2763 }
2764 $total_ht = $coef;
2765 return $total_ht;
2766 } else {
2767 $this->error = $langs->trans('TaxUndefinedForThisCategory');
2768 return 0;
2769 }
2770 } else {
2771 $this->error = $this->db->error()." sql=".$sql;
2772
2773 return -1;
2774 }
2775 }
2776
2784 public function getKanbanView($option = '', $arraydata = null)
2785 {
2786 global $langs;
2787
2788 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
2789
2790 $return = '<div class="box-flex-item box-flex-grow-zero">';
2791 $return .= '<div class="info-box info-box-sm">';
2792 $return .= '<span class="info-box-icon bg-infobox-action">';
2793 $return .= img_picto('', $this->picto);
2794 $return .= '</span>';
2795 $return .= '<div class="info-box-content">';
2796 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
2797 if ($selected >= 0) {
2798 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
2799 }
2800 if (array_key_exists('userauthor', $arraydata)) {
2801 $return .= '<br><span class="info-box-label">'.$arraydata['userauthor']->getNomUrl(-1).'</span>';
2802 }
2803 if (property_exists($this, 'date_debut') && property_exists($this, 'date_fin')) {
2804 $return .= '<br><span class="info-box-label">'.dol_print_date($this->date_debut, 'day').'</span>';
2805 $return .= ' <span class="opacitymedium">'.$langs->trans("To").'</span> ';
2806 $return .= '<span class="info-box-label">'.dol_print_date($this->date_fin, 'day').'</span>';
2807 }
2808 if (method_exists($this, 'getLibStatut')) {
2809 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
2810 }
2811 $return .= '</div>';
2812 $return .= '</div>';
2813 $return .= '</div>';
2814 return $return;
2815 }
2816}
2817
2818
2823{
2827 public $db;
2828
2832 public $table_element = 'expensereport_det';
2833
2837 public $error = '';
2838
2842 public $rowid;
2843
2844 public $comments;
2845 public $qty;
2846 public $value_unit;
2847 public $date;
2848
2852 public $dates;
2853
2857 public $fk_c_type_fees;
2858
2862 public $fk_c_exp_tax_cat;
2863
2867 public $fk_projet;
2868
2872 public $fk_expensereport;
2873
2874 public $type_fees_code;
2875 public $type_fees_libelle;
2876 public $type_fees_accountancy_code;
2877
2878 public $projet_ref;
2879 public $projet_title;
2880 public $rang;
2881
2882 public $vatrate;
2883 public $vat_src_code;
2884 public $tva_tx;
2885 public $localtax1_tx;
2886 public $localtax2_tx;
2887 public $localtax1_type;
2888 public $localtax2_type;
2889
2890 public $total_ht;
2891 public $total_tva;
2892 public $total_ttc;
2893 public $total_localtax1;
2894 public $total_localtax2;
2895
2896 // Multicurrency
2900 public $fk_multicurrency;
2901
2905 public $multicurrency_code;
2906 public $multicurrency_tx;
2907 public $multicurrency_total_ht;
2908 public $multicurrency_total_tva;
2909 public $multicurrency_total_ttc;
2910
2914 public $fk_ecm_files;
2915
2916 public $rule_warning_message;
2917
2918
2924 public function __construct($db)
2925 {
2926 $this->db = $db;
2927 }
2928
2935 public function fetch($rowid)
2936 {
2937 $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,';
2938 $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,';
2939 $sql .= ' fde.localtax1_tx, fde.localtax2_tx, fde.localtax1_type, fde.localtax2_type, fde.total_localtax1, fde.total_localtax2, fde.rule_warning_message,';
2940 $sql .= ' ctf.code as type_fees_code, ctf.label as type_fees_libelle,';
2941 $sql .= ' pjt.rowid as projet_id, pjt.title as projet_title, pjt.ref as projet_ref';
2942 $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det as fde';
2943 $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.
2944 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as pjt ON fde.fk_projet=pjt.rowid';
2945 $sql .= ' WHERE fde.rowid = '.((int) $rowid);
2946
2947 $result = $this->db->query($sql);
2948
2949 if ($result) {
2950 $objp = $this->db->fetch_object($result);
2951
2952 $this->rowid = $objp->rowid;
2953 $this->id = $objp->rowid;
2954 $this->ref = $objp->ref;
2955 $this->fk_expensereport = $objp->fk_expensereport;
2956 $this->comments = $objp->comments;
2957 $this->qty = $objp->qty;
2958 $this->date = $objp->date;
2959 $this->dates = $this->db->jdate($objp->date);
2960 $this->value_unit = $objp->value_unit;
2961 $this->fk_c_type_fees = $objp->fk_c_type_fees;
2962 $this->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
2963 $this->fk_projet = $objp->fk_project; // deprecated
2964 $this->fk_project = $objp->fk_project;
2965 $this->type_fees_code = $objp->type_fees_code;
2966 $this->type_fees_libelle = $objp->type_fees_libelle;
2967 $this->projet_ref = $objp->projet_ref;
2968 $this->projet_title = $objp->projet_title;
2969
2970 $this->vatrate = $objp->vatrate;
2971 $this->vat_src_code = $objp->vat_src_code;
2972 $this->localtax1_tx = $objp->localtax1_tx;
2973 $this->localtax2_tx = $objp->localtax2_tx;
2974 $this->localtax1_type = $objp->localtax1_type;
2975 $this->localtax2_type = $objp->localtax2_type;
2976
2977 $this->total_ht = $objp->total_ht;
2978 $this->total_tva = $objp->total_tva;
2979 $this->total_ttc = $objp->total_ttc;
2980 $this->total_localtax1 = $objp->total_localtax1;
2981 $this->total_localtax2 = $objp->total_localtax2;
2982
2983 $this->fk_ecm_files = $objp->fk_ecm_files;
2984
2985 $this->rule_warning_message = $objp->rule_warning_message;
2986
2987 $this->db->free($result);
2988
2989 return $this->id;
2990 } else {
2991 dol_print_error($this->db);
2992 return -1;
2993 }
2994 }
2995
3003 public function insert($notrigger = 0, $fromaddline = false)
3004 {
3005 global $user, $conf;
3006
3007 $error = 0;
3008
3009 dol_syslog("ExpenseReportLine::Insert", LOG_DEBUG);
3010
3011 // Clean parameters
3012 $this->comments = trim($this->comments);
3013 if (empty($this->value_unit)) {
3014 $this->value_unit = 0;
3015 }
3016 $this->qty = price2num($this->qty);
3017 $this->vatrate = price2num($this->vatrate);
3018 if (empty($this->fk_c_exp_tax_cat)) {
3019 $this->fk_c_exp_tax_cat = 0;
3020 }
3021
3022 $this->db->begin();
3023
3024 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'expensereport_det';
3025 $sql .= ' (fk_expensereport, fk_c_type_fees, fk_projet,';
3026 $sql .= ' tva_tx, vat_src_code,';
3027 $sql .= ' localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
3028 $sql .= ' comments, qty, value_unit,';
3029 $sql .= ' total_ht, total_tva, total_ttc,';
3030 $sql .= ' total_localtax1, total_localtax2,';
3031 $sql .= ' date, rule_warning_message, fk_c_exp_tax_cat, fk_ecm_files)';
3032 $sql .= " VALUES (".$this->db->escape($this->fk_expensereport).",";
3033 $sql .= " ".((int) $this->fk_c_type_fees).",";
3034 $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')).",";
3035 $sql .= " ".((float) $this->vatrate).",";
3036 $sql .= " '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."',";
3037 $sql .= " ".((float) price2num($this->localtax1_tx)).",";
3038 $sql .= " ".((float) price2num($this->localtax2_tx)).",";
3039 $sql .= " '".$this->db->escape($this->localtax1_type)."',";
3040 $sql .= " '".$this->db->escape($this->localtax2_type)."',";
3041 $sql .= " '".$this->db->escape($this->comments)."',";
3042 $sql .= " ".((float) $this->qty).",";
3043 $sql .= " ".((float) $this->value_unit).",";
3044 $sql .= " ".((float) price2num($this->total_ht)).",";
3045 $sql .= " ".((float) price2num($this->total_tva)).",";
3046 $sql .= " ".((float) price2num($this->total_ttc)).",";
3047 $sql .= " ".((float) price2num($this->total_localtax1)).",";
3048 $sql .= " ".((float) price2num($this->total_localtax2)).",";
3049 $sql .= " '".$this->db->idate($this->date)."',";
3050 $sql .= " ".(empty($this->rule_warning_message) ? 'null' : "'".$this->db->escape($this->rule_warning_message)."'").",";
3051 $sql .= " ".((int) $this->fk_c_exp_tax_cat).",";
3052 $sql .= " ".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
3053 $sql .= ")";
3054
3055 $resql = $this->db->query($sql);
3056 if ($resql) {
3057 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'expensereport_det');
3058
3059
3060 if (!$error && !$notrigger) {
3061 // Call triggers
3062 $result = $this->call_trigger('EXPENSE_REPORT_DET_CREATE', $user);
3063 if ($result < 0) {
3064 $error++;
3065 }
3066 // End call triggers
3067 }
3068
3069
3070 if (!$fromaddline) {
3071 $tmpparent = new ExpenseReport($this->db);
3072 $tmpparent->fetch($this->fk_expensereport);
3073 $result = $tmpparent->update_price(1);
3074 if ($result < 0) {
3075 $error++;
3076 $this->error = $tmpparent->error;
3077 $this->errors = $tmpparent->errors;
3078 }
3079 }
3080 } else {
3081 $error++;
3082 }
3083
3084 if (!$error) {
3085 $this->db->commit();
3086 return $this->id;
3087 } else {
3088 $this->error = $this->db->lasterror();
3089 dol_syslog("ExpenseReportLine::insert Error ".$this->error, LOG_ERR);
3090 $this->db->rollback();
3091 return -2;
3092 }
3093 }
3094
3103 public function getExpAmount(ExpenseReportRule $rule, $fk_user, $mode = 'day')
3104 {
3105 $amount = 0;
3106
3107 $sql = 'SELECT SUM(d.total_ttc) as total_amount';
3108 $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det d';
3109 $sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'expensereport e ON (d.fk_expensereport = e.rowid)';
3110 $sql .= ' WHERE e.fk_user_author = '.((int) $fk_user);
3111 if (!empty($this->id)) {
3112 $sql .= ' AND d.rowid <> '.((int) $this->id);
3113 }
3114 $sql .= ' AND d.fk_c_type_fees = '.((int) $rule->fk_c_type_fees);
3115 if ($mode == 'day' || $mode == 'EX_DAY') {
3116 $sql .= " AND d.date = '".dol_print_date($this->date, '%Y-%m-%d')."'";
3117 } elseif ($mode == 'mon' || $mode == 'EX_MON') {
3118 $sql .= " AND DATE_FORMAT(d.date, '%Y-%m') = '".dol_print_date($this->date, '%Y-%m')."'"; // @todo DATE_FORMAT is forbidden
3119 } elseif ($mode == 'year' || $mode == 'EX_YEA') {
3120 $sql .= " AND DATE_FORMAT(d.date, '%Y') = '".dol_print_date($this->date, '%Y')."'"; // @todo DATE_FORMAT is forbidden
3121 }
3122
3123 dol_syslog('ExpenseReportLine::getExpAmount');
3124
3125 $resql = $this->db->query($sql);
3126 if ($resql) {
3127 $num = $this->db->num_rows($resql);
3128 if ($num > 0) {
3129 $obj = $this->db->fetch_object($resql);
3130 $amount = (float) $obj->total_amount;
3131 }
3132 } else {
3133 dol_print_error($this->db);
3134 }
3135
3136 return $amount + $this->total_ttc;
3137 }
3138
3145 public function update(User $user)
3146 {
3147 global $langs, $conf;
3148
3149 $error = 0;
3150
3151 // Clean parameters
3152 $this->comments = trim($this->comments);
3153 $this->vatrate = price2num($this->vatrate);
3154 $this->value_unit = price2num($this->value_unit);
3155 if (empty($this->fk_c_exp_tax_cat)) {
3156 $this->fk_c_exp_tax_cat = 0;
3157 }
3158
3159 $this->db->begin();
3160
3161 // Update line in database
3162 $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport_det SET";
3163 $sql .= " comments='".$this->db->escape($this->comments)."'";
3164 $sql .= ", value_unit = ".((float) $this->value_unit);
3165 $sql .= ", qty=".((float) $this->qty);
3166 $sql .= ", date='".$this->db->idate($this->date)."'";
3167 $sql .= ", total_ht=".((float) price2num($this->total_ht, 'MT'));
3168 $sql .= ", total_tva=".((float) price2num($this->total_tva, 'MT'));
3169 $sql .= ", total_ttc=".((float) price2num($this->total_ttc, 'MT'));
3170 $sql .= ", total_localtax1=".((float) price2num($this->total_localtax1, 'MT'));
3171 $sql .= ", total_localtax2=".((float) price2num($this->total_localtax2, 'MT'));
3172 $sql .= ", tva_tx=".((float) $this->vatrate);
3173 $sql .= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
3174 $sql .= ", localtax1_tx=".((float) $this->localtax1_tx);
3175 $sql .= ", localtax2_tx=".((float) $this->localtax2_tx);
3176 $sql .= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
3177 $sql .= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
3178 $sql .= ", rule_warning_message='".$this->db->escape($this->rule_warning_message)."'";
3179 $sql .= ", fk_c_exp_tax_cat=".$this->db->escape($this->fk_c_exp_tax_cat);
3180 $sql .= ", fk_ecm_files=".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
3181 if ($this->fk_c_type_fees) {
3182 $sql .= ", fk_c_type_fees = ".((int) $this->fk_c_type_fees);
3183 } else {
3184 $sql .= ", fk_c_type_fees=null";
3185 }
3186 if ($this->fk_project > 0) {
3187 $sql .= ", fk_projet=".((int) $this->fk_project);
3188 } else {
3189 $sql .= ", fk_projet=null";
3190 }
3191 $sql .= " WHERE rowid = ".((int) ($this->rowid ? $this->rowid : $this->id));
3192
3193 dol_syslog("ExpenseReportLine::update");
3194
3195 $resql = $this->db->query($sql);
3196 if ($resql) {
3197 $tmpparent = new ExpenseReport($this->db);
3198 $result = $tmpparent->fetch($this->fk_expensereport);
3199 if ($result > 0) {
3200 $result = $tmpparent->update_price(1);
3201 if ($result < 0) {
3202 $error++;
3203 $this->error = $tmpparent->error;
3204 $this->errors = $tmpparent->errors;
3205 }
3206 } else {
3207 $error++;
3208 $this->error = $tmpparent->error;
3209 $this->errors = $tmpparent->errors;
3210 }
3211 } else {
3212 $error++;
3213 dol_print_error($this->db);
3214 }
3215
3216 if (!$error) {
3217 $this->db->commit();
3218 return 1;
3219 } else {
3220 $this->error = $this->db->lasterror();
3221 dol_syslog("ExpenseReportLine::update Error ".$this->error, LOG_ERR);
3222 $this->db->rollback();
3223 return -2;
3224 }
3225 }
3226
3227 // ajouter ici comput_ ...
3228}
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:1926
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