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