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