dolibarr  16.0.1
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-2021 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 
28 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
29 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
30 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport_ik.class.php';
31 require_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 
63  public $lines = array();
64 
65  public $date_debut;
66 
67  public $date_fin;
68 
74  public $status;
75 
82  public $fk_statut;
83 
84  public $fk_c_paiement;
85  public $paid;
86 
87  public $user_author_infos;
88  public $user_validator_infos;
89 
90  public $rule_warning_message;
91 
92  // ACTIONS
93 
94  // Create
95  public $date_create;
96  public $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
97 
98  // Update
99  public $date_modif;
100  public $fk_user_modif;
101 
102  // Refus
103  public $date_refuse;
104  public $detail_refuse;
105  public $fk_user_refuse;
106 
107  // Annulation
108  public $date_cancel;
109  public $detail_cancel;
110  public $fk_user_cancel;
111 
112  public $fk_user_validator; // User that is defined to approve
113 
114  // Validation
115  /* @deprecated */
116  public $datevalid;
117 
118  public $date_valid; // User making validation
119  public $fk_user_valid;
120  public $user_valid_infos;
121 
122  // Approve
123  public $date_approve;
124  public $fk_user_approve; // User that has approved
125 
126  // Paiement
127  public $user_paid_infos;
128 
129  public $localtax1; // for backward compatibility (real field should be total_localtax1 defined into CommonObject)
130  public $localtax2; // for backward compatibility (real field should be total_localtax2 defined into CommonObject)
131 
132  public $statuts = array();
133  public $statuts_short = array();
134  public $statuts_logo;
135 
136 
140  const STATUS_DRAFT = 0;
141 
145  const STATUS_VALIDATED = 2;
146 
150  const STATUS_CANCELED = 4;
151 
155  const STATUS_APPROVED = 5;
156 
160  const STATUS_REFUSED = 99;
161 
165  const STATUS_CLOSED = 6;
166 
167 
168  public $fields = array(
169  'rowid' =>array('type'=>'integer', 'label'=>'ID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
170  'ref' =>array('type'=>'varchar(50)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>15),
171  'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>20),
172  'ref_number_int' =>array('type'=>'integer', 'label'=>'Ref number int', 'enabled'=>1, 'visible'=>-1, 'position'=>25),
173  'ref_ext' =>array('type'=>'integer', 'label'=>'Ref ext', 'enabled'=>1, 'visible'=>-1, 'position'=>30),
174  'total_ht' =>array('type'=>'double(24,8)', 'label'=>'Total ht', 'enabled'=>1, 'visible'=>-1, 'position'=>35),
175  'total_tva' =>array('type'=>'double(24,8)', 'label'=>'Total tva', 'enabled'=>1, 'visible'=>-1, 'position'=>40),
176  'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
177  'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>-1, 'position'=>50),
178  'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Total ttc', 'enabled'=>1, 'visible'=>-1, 'position'=>55),
179  'date_debut' =>array('type'=>'date', 'label'=>'Date debut', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>60),
180  'date_fin' =>array('type'=>'date', 'label'=>'Date fin', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>65),
181  'date_valid' =>array('type'=>'datetime', 'label'=>'Date valid', 'enabled'=>1, 'visible'=>-1, 'position'=>75),
182  'date_approve' =>array('type'=>'datetime', 'label'=>'Date approve', 'enabled'=>1, 'visible'=>-1, 'position'=>80),
183  'date_refuse' =>array('type'=>'datetime', 'label'=>'Date refuse', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
184  'date_cancel' =>array('type'=>'datetime', 'label'=>'Date cancel', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
185  'fk_user_author' =>array('type'=>'integer', 'label'=>'Fk user author', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>100),
186  'fk_user_modif' =>array('type'=>'integer', 'label'=>'Fk user modif', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
187  'fk_user_valid' =>array('type'=>'integer', 'label'=>'Fk user valid', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
188  'fk_user_validator' =>array('type'=>'integer', 'label'=>'Fk user validator', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
189  'fk_user_approve' =>array('type'=>'integer', 'label'=>'Fk user approve', 'enabled'=>1, 'visible'=>-1, 'position'=>120),
190  'fk_user_refuse' =>array('type'=>'integer', 'label'=>'Fk user refuse', 'enabled'=>1, 'visible'=>-1, 'position'=>125),
191  'fk_user_cancel' =>array('type'=>'integer', 'label'=>'Fk user cancel', 'enabled'=>1, 'visible'=>-1, 'position'=>130),
192  'fk_c_paiement' =>array('type'=>'integer', 'label'=>'Fk c paiement', 'enabled'=>1, 'visible'=>-1, 'position'=>140),
193  'paid' =>array('type'=>'integer', 'label'=>'Paid', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>145),
194  'note_public' =>array('type'=>'text', 'label'=>'Note public', 'enabled'=>1, 'visible'=>0, 'position'=>150),
195  'note_private' =>array('type'=>'text', 'label'=>'Note private', 'enabled'=>1, 'visible'=>0, 'position'=>155),
196  'detail_refuse' =>array('type'=>'varchar(255)', 'label'=>'Detail refuse', 'enabled'=>1, 'visible'=>-1, 'position'=>160),
197  'detail_cancel' =>array('type'=>'varchar(255)', 'label'=>'Detail cancel', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
198  'integration_compta' =>array('type'=>'integer', 'label'=>'Integration compta', 'enabled'=>1, 'visible'=>-1, 'position'=>170),
199  'fk_bank_account' =>array('type'=>'integer', 'label'=>'Fk bank account', 'enabled'=>1, 'visible'=>-1, 'position'=>175),
200  'fk_multicurrency' =>array('type'=>'integer', 'label'=>'Fk multicurrency', 'enabled'=>1, 'visible'=>-1, 'position'=>185),
201  'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'Multicurrency code', 'enabled'=>1, 'visible'=>-1, 'position'=>190),
202  'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency tx', 'enabled'=>1, 'visible'=>-1, 'position'=>195),
203  'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ht', 'enabled'=>1, 'visible'=>-1, 'position'=>200),
204  'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total tva', 'enabled'=>1, 'visible'=>-1, 'position'=>205),
205  'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ttc', 'enabled'=>1, 'visible'=>-1, 'position'=>210),
206  'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>220),
207  'date_create' =>array('type'=>'datetime', 'label'=>'Date create', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>300),
208  'tms' =>array('type'=>'timestamp', 'label'=>'Tms', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>305),
209  'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-1, 'position'=>1000),
210  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>1010),
211  'fk_statut' =>array('type'=>'integer', 'label'=>'Fk statut', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>500),
212  );
213 
219  public function __construct($db)
220  {
221  $this->db = $db;
222  $this->total_ht = 0;
223  $this->total_ttc = 0;
224  $this->total_tva = 0;
225  $this->total_localtax1 = 0;
226  $this->total_localtax2 = 0;
227  $this->localtax1 = 0; // For backward compatibility
228  $this->localtax2 = 0; // For backward compatibility
229  $this->modepaymentid = 0;
230 
231  // List of language codes for status
232  $this->statuts_short = array(0 => 'Draft', 2 => 'Validated', 4 => 'Canceled', 5 => 'Approved', 6 => 'Paid', 99 => 'Refused');
233  $this->statuts = array(0 => 'Draft', 2 => 'ValidatedWaitingApproval', 4 => 'Canceled', 5 => 'Approved', 6 => 'Paid', 99 => 'Refused');
234  $this->statuts_logo = array(0 => 'status0', 2 => 'status1', 4 => 'status6', 5 => 'status4', 6 => 'status6', 99 => 'status5');
235  }
236 
244  public function create($user, $notrigger = 0)
245  {
246  global $conf, $langs;
247 
248  $now = dol_now();
249 
250  $error = 0;
251 
252  // Check parameters
253  if (empty($this->date_debut) || empty($this->date_fin)) {
254  $this->error = $langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Date'));
255  return -1;
256  }
257 
258  $fuserid = $this->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
259  if (empty($fuserid)) {
260  $fuserid = $user->id;
261  }
262 
263  $this->db->begin();
264 
265  $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
266  $sql .= "ref";
267  $sql .= ",total_ht";
268  $sql .= ",total_ttc";
269  $sql .= ",total_tva";
270  $sql .= ",date_debut";
271  $sql .= ",date_fin";
272  $sql .= ",date_create";
273  $sql .= ",fk_user_creat";
274  $sql .= ",fk_user_author";
275  $sql .= ",fk_user_validator";
276  $sql .= ",fk_user_approve";
277  $sql .= ",fk_user_modif";
278  $sql .= ",fk_statut";
279  $sql .= ",fk_c_paiement";
280  $sql .= ",paid";
281  $sql .= ",note_public";
282  $sql .= ",note_private";
283  $sql .= ",entity";
284  $sql .= ") VALUES(";
285  $sql .= "'(PROV)'";
286  $sql .= ", ".price2num($this->total_ht, 'MT');
287  $sql .= ", ".price2num($this->total_ttc, 'MT');
288  $sql .= ", ".price2num($this->total_tva, 'MT');
289  $sql .= ", '".$this->db->idate($this->date_debut)."'";
290  $sql .= ", '".$this->db->idate($this->date_fin)."'";
291  $sql .= ", '".$this->db->idate($now)."'";
292  $sql .= ", ".((int) $user->id);
293  $sql .= ", ".((int) $fuserid);
294  $sql .= ", ".($this->fk_user_validator > 0 ? ((int) $this->fk_user_validator) : "null");
295  $sql .= ", ".($this->fk_user_approve > 0 ? ((int) $this->fk_user_approve) : "null");
296  $sql .= ", ".($this->fk_user_modif > 0 ? ((int) $this->fk_user_modif) : "null");
297  $sql .= ", ".($this->fk_statut > 1 ? ((int) $this->fk_statut) : 0);
298  $sql .= ", ".($this->modepaymentid ? ((int) $this->modepaymentid) : "null");
299  $sql .= ", 0";
300  $sql .= ", ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : "null");
301  $sql .= ", ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "null");
302  $sql .= ", ".((int) $conf->entity);
303  $sql .= ")";
304 
305  $result = $this->db->query($sql);
306  if ($result) {
307  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
308  $this->ref = '(PROV'.$this->id.')';
309 
310  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".((int) $this->id);
311  $resql = $this->db->query($sql);
312  if (!$resql) {
313  $this->error = $this->db->lasterror();
314  $error++;
315  }
316 
317  if (!$error) {
318  if (is_array($this->lines) && count($this->lines) > 0) {
319  foreach ($this->lines as $line) {
320  // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
321  //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
322  if (!is_object($line)) {
323  $line = (object) $line;
324  $newndfline = new ExpenseReportLine($this->db);
325  $newndfline->fk_expensereport = $line->fk_expensereport;
326  $newndfline->fk_c_type_fees = $line->fk_c_type_fees;
327  $newndfline->fk_project = $line->fk_project;
328  $newndfline->vatrate = $line->vatrate;
329  $newndfline->vat_src_code = $line->vat_src_code;
330  $newndfline->localtax1_tx = $line->localtax1_tx;
331  $newndfline->localtax2_tx = $line->localtax2_tx;
332  $newndfline->localtax1_type = $line->localtax1_type;
333  $newndfline->localtax2_type = $line->localtax2_type;
334  $newndfline->comments = $line->comments;
335  $newndfline->qty = $line->qty;
336  $newndfline->value_unit = $line->value_unit;
337  $newndfline->total_ht = $line->total_ht;
338  $newndfline->total_ttc = $line->total_ttc;
339  $newndfline->total_tva = $line->total_tva;
340  $newndfline->total_localtax1 = $line->total_localtax1;
341  $newndfline->total_localtax2 = $line->total_localtax2;
342  $newndfline->date = $line->date;
343  $newndfline->rule_warning_message = $line->rule_warning_message;
344  $newndfline->fk_c_exp_tax_cat = $line->fk_c_exp_tax_cat;
345  $newndfline->fk_ecm_files = $line->fk_ecm_files;
346  } else {
347  $newndfline = $line;
348  }
349  //$newndfline=new ExpenseReportLine($this->db);
350  $newndfline->fk_expensereport = $this->id;
351  $result = $newndfline->insert();
352  if ($result < 0) {
353  $this->error = $newndfline->error;
354  $this->errors = $newndfline->errors;
355  $error++;
356  break;
357  }
358  }
359  }
360  }
361 
362  if (!$error) {
363  $result = $this->insertExtraFields();
364  if ($result < 0) {
365  $error++;
366  }
367  }
368 
369  if (!$error) {
370  $result = $this->update_price();
371  if ($result > 0) {
372  if (!$notrigger) {
373  // Call trigger
374  $result = $this->call_trigger('EXPENSE_REPORT_CREATE', $user);
375 
376  if ($result < 0) {
377  $error++;
378  }
379  // End call triggers
380  }
381 
382  if (empty($error)) {
383  $this->db->commit();
384  return $this->id;
385  } else {
386  $this->db->rollback();
387  return -4;
388  }
389  } else {
390  $this->db->rollback();
391  return -3;
392  }
393  } else {
394  dol_syslog(get_class($this)."::create error ".$this->error, LOG_ERR);
395  $this->db->rollback();
396  return -2;
397  }
398  } else {
399  $this->error = $this->db->lasterror()." sql=".$sql;
400  $this->db->rollback();
401  return -1;
402  }
403  }
404 
412  public function createFromClone(User $user, $fk_user_author)
413  {
414  global $hookmanager;
415 
416  $error = 0;
417 
418  if (empty($fk_user_author)) {
419  $fk_user_author = $user->id;
420  }
421 
422  $this->db->begin();
423 
424  // get extrafields so they will be clone
425  //foreach($this->lines as $line)
426  //$line->fetch_optionals();
427 
428  // Load source object
429  $objFrom = clone $this;
430 
431  $this->id = 0;
432  $this->ref = '';
433  $this->status = 0;
434  $this->fk_statut = 0; // deprecated
435 
436  // Clear fields
437  $this->fk_user_creat = $user->id;
438  $this->fk_user_author = $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
439  $this->fk_user_valid = '';
440  $this->date_create = '';
441  $this->date_creation = '';
442  $this->date_validation = '';
443 
444  // Remove link on lines to a joined file
445  if (is_array($this->lines) && count($this->lines) > 0) {
446  foreach ($this->lines as $key => $line) {
447  $this->lines[$key]->fk_ecm_files = 0;
448  }
449  }
450 
451  // Create clone
452  $this->context['createfromclone'] = 'createfromclone';
453  $result = $this->create($user);
454  if ($result < 0) {
455  $error++;
456  }
457 
458  if (!$error) {
459  // Hook of thirdparty module
460  if (is_object($hookmanager)) {
461  $parameters = array('objFrom'=>$objFrom);
462  $action = '';
463  $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
464  if ($reshook < 0) {
465  $error++;
466  }
467  }
468  }
469 
470  unset($this->context['createfromclone']);
471 
472  // End
473  if (!$error) {
474  $this->db->commit();
475  return $this->id;
476  } else {
477  $this->db->rollback();
478  return -1;
479  }
480  }
481 
482 
491  public function update($user, $notrigger = 0, $userofexpensereport = null)
492  {
493  global $langs;
494 
495  $error = 0;
496  $this->db->begin();
497 
498  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
499  $sql .= " total_ht = ".$this->total_ht;
500  $sql .= " , total_ttc = ".$this->total_ttc;
501  $sql .= " , total_tva = ".$this->total_tva;
502  $sql .= " , date_debut = '".$this->db->idate($this->date_debut)."'";
503  $sql .= " , date_fin = '".$this->db->idate($this->date_fin)."'";
504  if ($userofexpensereport && is_object($userofexpensereport)) {
505  $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.
506  }
507  $sql .= " , fk_user_validator = ".($this->fk_user_validator > 0 ? $this->fk_user_validator : "null");
508  $sql .= " , fk_user_valid = ".($this->fk_user_valid > 0 ? $this->fk_user_valid : "null");
509  $sql .= " , fk_user_approve = ".($this->fk_user_approve > 0 ? $this->fk_user_approve : "null");
510  $sql .= " , fk_user_modif = ".$user->id;
511  $sql .= " , fk_statut = ".($this->fk_statut >= 0 ? $this->fk_statut : '0');
512  $sql .= " , fk_c_paiement = ".($this->fk_c_paiement > 0 ? $this->fk_c_paiement : "null");
513  $sql .= " , note_public = ".(!empty($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "''");
514  $sql .= " , note_private = ".(!empty($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "''");
515  $sql .= " , detail_refuse = ".(!empty($this->detail_refuse) ? "'".$this->db->escape($this->detail_refuse)."'" : "''");
516  $sql .= " WHERE rowid = ".((int) $this->id);
517 
518  dol_syslog(get_class($this)."::update", LOG_DEBUG);
519  $result = $this->db->query($sql);
520  if ($result) {
521  if (!$notrigger) {
522  // Call trigger
523  $result = $this->call_trigger('EXPENSE_REPORT_MODIFY', $user);
524 
525  if ($result < 0) {
526  $error++;
527  }
528  // End call triggers
529  }
530 
531  if (empty($error)) {
532  $this->db->commit();
533  return 1;
534  } else {
535  $this->db->rollback();
536  $this->error = $this->db->error();
537  return -2;
538  }
539  } else {
540  $this->db->rollback();
541  $this->error = $this->db->error();
542  return -1;
543  }
544  }
545 
553  public function fetch($id, $ref = '')
554  {
555  global $conf;
556 
557  $sql = "SELECT d.rowid, d.entity, d.ref, d.note_public, d.note_private,"; // DEFAULT
558  $sql .= " d.detail_refuse, d.detail_cancel, d.fk_user_refuse, d.fk_user_cancel,"; // ACTIONS
559  $sql .= " d.date_refuse, d.date_cancel,"; // ACTIONS
560  $sql .= " d.total_ht, d.total_ttc, d.total_tva,";
561  $sql .= " d.localtax1 as total_localtax1, d.localtax2 as total_localtax2,";
562  $sql .= " d.date_debut, d.date_fin, d.date_create, d.tms as date_modif, d.date_valid, d.date_approve,"; // DATES (datetime)
563  $sql .= " d.fk_user_creat, d.fk_user_author, d.fk_user_modif, d.fk_user_validator,";
564  $sql .= " d.fk_user_valid, d.fk_user_approve,";
565  $sql .= " d.fk_statut as status, d.fk_c_paiement, d.paid";
566  $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as d";
567  if ($ref) {
568  $sql .= " WHERE d.ref = '".$this->db->escape($ref)."'";
569  } else {
570  $sql .= " WHERE d.rowid = ".((int) $id);
571  }
572  //$sql.= $restrict;
573 
574  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
575  $resql = $this->db->query($sql);
576  if ($resql) {
577  $obj = $this->db->fetch_object($resql);
578  if ($obj) {
579  $this->id = $obj->rowid;
580  $this->ref = $obj->ref;
581 
582  $this->entity = $obj->entity;
583 
584  $this->total_ht = $obj->total_ht;
585  $this->total_tva = $obj->total_tva;
586  $this->total_ttc = $obj->total_ttc;
587  $this->localtax1 = $obj->total_localtax1; // For backward compatibility
588  $this->localtax2 = $obj->total_localtax2; // For backward compatibility
589  $this->total_localtax1 = $obj->total_localtax1;
590  $this->total_localtax2 = $obj->total_localtax2;
591 
592  $this->note_public = $obj->note_public;
593  $this->note_private = $obj->note_private;
594  $this->detail_refuse = $obj->detail_refuse;
595  $this->detail_cancel = $obj->detail_cancel;
596 
597  $this->date_debut = $this->db->jdate($obj->date_debut);
598  $this->date_fin = $this->db->jdate($obj->date_fin);
599  $this->date_valid = $this->db->jdate($obj->date_valid);
600  $this->date_approve = $this->db->jdate($obj->date_approve);
601  $this->date_create = $this->db->jdate($obj->date_create);
602  $this->date_modif = $this->db->jdate($obj->date_modif);
603  $this->date_refuse = $this->db->jdate($obj->date_refuse);
604  $this->date_cancel = $this->db->jdate($obj->date_cancel);
605 
606  $this->fk_user_creat = $obj->fk_user_creat;
607  $this->fk_user_author = $obj->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
608  $this->fk_user_modif = $obj->fk_user_modif;
609  $this->fk_user_validator = $obj->fk_user_validator;
610  $this->fk_user_valid = $obj->fk_user_valid;
611  $this->fk_user_refuse = $obj->fk_user_refuse;
612  $this->fk_user_cancel = $obj->fk_user_cancel;
613  $this->fk_user_approve = $obj->fk_user_approve;
614 
615  $user_author = new User($this->db);
616  if ($this->fk_user_author > 0) {
617  $user_author->fetch($this->fk_user_author);
618  }
619 
620  $this->user_author_infos = dolGetFirstLastname($user_author->firstname, $user_author->lastname);
621 
622  $user_approver = new User($this->db);
623  if ($this->fk_user_approve > 0) {
624  $user_approver->fetch($this->fk_user_approve);
625  } elseif ($this->fk_user_validator > 0) {
626  $user_approver->fetch($this->fk_user_validator); // For backward compatibility
627  }
628  $this->user_validator_infos = dolGetFirstLastname($user_approver->firstname, $user_approver->lastname);
629 
630  $this->fk_statut = $obj->status; // deprecated
631  $this->status = $obj->status;
632  $this->fk_c_paiement = $obj->fk_c_paiement;
633  $this->paid = $obj->paid;
634 
635  if ($this->status == self::STATUS_APPROVED || $this->status == self::STATUS_CLOSED) {
636  $user_valid = new User($this->db);
637  if ($this->fk_user_valid > 0) {
638  $user_valid->fetch($this->fk_user_valid);
639  }
640  $this->user_valid_infos = dolGetFirstLastname($user_valid->firstname, $user_valid->lastname);
641  }
642 
643  $this->fetch_optionals();
644 
645  $result = $this->fetch_lines();
646 
647  return $result;
648  } else {
649  return 0;
650  }
651  } else {
652  $this->error = $this->db->lasterror();
653  return -1;
654  }
655  }
656 
657  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
668  public function set_paid($id, $fuser, $notrigger = 0)
669  {
670  // phpcs:enable
671  dol_syslog(get_class($this)."::set_paid is deprecated, use setPaid instead", LOG_NOTICE);
672  return $this->setPaid($id, $fuser, $notrigger);
673  }
674 
683  public function setPaid($id, $fuser, $notrigger = 0)
684  {
685  $error = 0;
686  $this->db->begin();
687 
688  $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport";
689  $sql .= " SET fk_statut = ".self::STATUS_CLOSED.", paid=1";
690  $sql .= " WHERE rowid = ".((int) $id)." AND fk_statut = ".self::STATUS_APPROVED;
691 
692  dol_syslog(get_class($this)."::set_paid", LOG_DEBUG);
693  $resql = $this->db->query($sql);
694  if ($resql) {
695  if ($this->db->affected_rows($resql)) {
696  if (!$notrigger) {
697  // Call trigger
698  $result = $this->call_trigger('EXPENSE_REPORT_PAID', $fuser);
699 
700  if ($result < 0) {
701  $error++;
702  }
703  // End call triggers
704  }
705 
706  if (empty($error)) {
707  $this->db->commit();
708  return 1;
709  } else {
710  $this->db->rollback();
711  $this->error = $this->db->error();
712  return -2;
713  }
714  } else {
715  $this->db->commit();
716  return 0;
717  }
718  } else {
719  $this->db->rollback();
720  dol_print_error($this->db);
721  return -1;
722  }
723  }
724 
731  public function getLibStatut($mode = 0)
732  {
733  return $this->LibStatut($this->status, $mode);
734  }
735 
736  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
744  public function LibStatut($status, $mode = 0)
745  {
746  // phpcs:enable
747  global $langs;
748 
749  $labelStatus = $langs->transnoentitiesnoconv($this->statuts[$status]);
750  $labelStatusShort = $langs->transnoentitiesnoconv($this->statuts_short[$status]);
751 
752  $statusType = $this->statuts_logo[$status];
753 
754  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
755  }
756 
757 
764  public function info($id)
765  {
766  global $conf;
767 
768  $sql = "SELECT f.rowid,";
769  $sql .= " f.date_create as datec,";
770  $sql .= " f.tms as date_modification,";
771  $sql .= " f.date_valid as datev,";
772  $sql .= " f.date_approve as datea,";
773  $sql .= " f.fk_user_creat as fk_user_creation,";
774  $sql .= " f.fk_user_modif as fk_user_modification,";
775  $sql .= " f.fk_user_valid,";
776  $sql .= " f.fk_user_approve";
777  $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as f";
778  $sql .= " WHERE f.rowid = ".((int) $id);
779  $sql .= " AND f.entity = ".$conf->entity;
780 
781  $resql = $this->db->query($sql);
782  if ($resql) {
783  if ($this->db->num_rows($resql)) {
784  $obj = $this->db->fetch_object($resql);
785 
786  $this->id = $obj->rowid;
787 
788  $this->date_creation = $this->db->jdate($obj->datec);
789  $this->date_modification = $this->db->jdate($obj->date_modification);
790  $this->date_validation = $this->db->jdate($obj->datev);
791  $this->date_approbation = $this->db->jdate($obj->datea);
792 
793  $cuser = new User($this->db);
794  $cuser->fetch($obj->fk_user_author);
795  $this->user_creation = $cuser;
796 
797  if ($obj->fk_user_creation) {
798  $cuser = new User($this->db);
799  $cuser->fetch($obj->fk_user_creation);
800  $this->user_creation = $cuser;
801  }
802  if ($obj->fk_user_valid) {
803  $vuser = new User($this->db);
804  $vuser->fetch($obj->fk_user_valid);
805  $this->user_validation = $vuser;
806  }
807  if ($obj->fk_user_modification) {
808  $muser = new User($this->db);
809  $muser->fetch($obj->fk_user_modification);
810  $this->user_modification = $muser;
811  }
812  if ($obj->fk_user_approve) {
813  $auser = new User($this->db);
814  $auser->fetch($obj->fk_user_approve);
815  $this->user_approve = $auser;
816  }
817  }
818  $this->db->free($resql);
819  } else {
820  dol_print_error($this->db);
821  }
822  }
823 
824 
825 
833  public function initAsSpecimen()
834  {
835  global $user, $langs, $conf;
836 
837  $now = dol_now();
838 
839  // Initialise parametres
840  $this->id = 0;
841  $this->ref = 'SPECIMEN';
842  $this->specimen = 1;
843  $this->entity = 1;
844  $this->date_create = $now;
845  $this->date_debut = $now;
846  $this->date_fin = $now;
847  $this->date_valid = $now;
848  $this->date_approve = $now;
849 
850  $type_fees_id = 2; // TF_TRIP
851 
852  $this->status = 5;
853  $this->fk_statut = 5;
854 
855  $this->fk_user_author = $user->id;
856  $this->fk_user_validator = $user->id;
857  $this->fk_user_valid = $user->id;
858  $this->fk_user_approve = $user->id;
859 
860  $this->note_private = 'Private note';
861  $this->note_public = 'SPECIMEN';
862  $nbp = 5;
863  $xnbp = 0;
864  while ($xnbp < $nbp) {
865  $line = new ExpenseReportLine($this->db);
866  $line->comments = $langs->trans("Comment")." ".$xnbp;
867  $line->date = ($now - 3600 * (1 + $xnbp));
868  $line->total_ht = 100;
869  $line->total_tva = 20;
870  $line->total_ttc = 120;
871  $line->qty = 1;
872  $line->vatrate = 20;
873  $line->value_unit = 120;
874  $line->fk_expensereport = 0;
875  $line->type_fees_code = 'TRA';
876  $line->fk_c_type_fees = $type_fees_id;
877 
878  $line->projet_ref = 'ABC';
879 
880  $this->lines[$xnbp] = $line;
881  $xnbp++;
882 
883  $this->total_ht += $line->total_ht;
884  $this->total_tva += $line->total_tva;
885  $this->total_ttc += $line->total_ttc;
886  }
887  }
888 
889  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
897  public function fetch_line_by_project($projectid, $user = '')
898  {
899  // phpcs:enable
900  global $conf, $db, $langs;
901 
902  $langs->load('trips');
903 
904  if ($user->rights->expensereport->lire) {
905  $sql = "SELECT de.fk_expensereport, de.date, de.comments, de.total_ht, de.total_ttc";
906  $sql .= " FROM ".MAIN_DB_PREFIX."expensereport_det as de";
907  $sql .= " WHERE de.fk_projet = ".((int) $projectid);
908 
909  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
910  $result = $this->db->query($sql);
911  if ($result) {
912  $num = $this->db->num_rows($result);
913  $i = 0;
914  $total_HT = 0;
915  $total_TTC = 0;
916 
917  while ($i < $num) {
918  $objp = $this->db->fetch_object($result);
919 
920  $sql2 = "SELECT d.rowid, d.fk_user_author, d.ref, d.fk_statut as status";
921  $sql2 .= " FROM ".MAIN_DB_PREFIX."expensereport as d";
922  $sql2 .= " WHERE d.rowid = ".((int) $objp->fk_expensereport);
923 
924  $result2 = $this->db->query($sql2);
925  $obj = $this->db->fetch_object($result2);
926 
927  $objp->fk_user_author = $obj->fk_user_author;
928  $objp->ref = $obj->ref;
929  $objp->fk_c_expensereport_status = $obj->status;
930  $objp->rowid = $obj->rowid;
931 
932  $total_HT = $total_HT + $objp->total_ht;
933  $total_TTC = $total_TTC + $objp->total_ttc;
934  $author = new User($this->db);
935  $author->fetch($objp->fk_user_author);
936 
937  print '<tr>';
938  print '<td><a href="'.DOL_URL_ROOT.'/expensereport/card.php?id='.$objp->rowid.'">'.$objp->ref_num.'</a></td>';
939  print '<td class="center">'.dol_print_date($objp->date, 'day').'</td>';
940  print '<td>'.$author->getNomUrl(1).'</td>';
941  print '<td>'.$objp->comments.'</td>';
942  print '<td class="right">'.price($objp->total_ht).'</td>';
943  print '<td class="right">'.price($objp->total_ttc).'</td>';
944  print '<td class="right">';
945 
946  switch ($objp->fk_c_expensereport_status) {
947  case 4:
948  print img_picto($langs->trans('StatusOrderCanceled'), 'statut5');
949  break;
950  case 1:
951  print $langs->trans('Draft').' '.img_picto($langs->trans('Draft'), 'statut0');
952  break;
953  case 2:
954  print $langs->trans('TripForValid').' '.img_picto($langs->trans('TripForValid'), 'statut3');
955  break;
956  case 5:
957  print $langs->trans('TripForPaid').' '.img_picto($langs->trans('TripForPaid'), 'statut3');
958  break;
959  case 6:
960  print $langs->trans('TripPaid').' '.img_picto($langs->trans('TripPaid'), 'statut4');
961  break;
962  }
963  /*
964  if ($status==4) return img_picto($langs->trans('StatusOrderCanceled'),'statut5');
965  if ($status==1) return img_picto($langs->trans('StatusOrderDraft'),'statut0');
966  if ($status==2) return img_picto($langs->trans('StatusOrderValidated'),'statut1');
967  if ($status==2) return img_picto($langs->trans('StatusOrderOnProcess'),'statut3');
968  if ($status==5) return img_picto($langs->trans('StatusOrderToBill'),'statut4');
969  if ($status==6) return img_picto($langs->trans('StatusOrderOnProcess'),'statut6');
970  */
971  print '</td>';
972  print '</tr>';
973 
974  $i++;
975  }
976 
977  print '<tr class="liste_total"><td colspan="4">'.$langs->trans("Number").': '.$i.'</td>';
978  print '<td class="right" width="100">'.$langs->trans("TotalHT").' : '.price($total_HT).'</td>';
979  print '<td class="right" width="100">'.$langs->trans("TotalTTC").' : '.price($total_TTC).'</td>';
980  print '<td>&nbsp;</td>';
981  print '</tr>';
982  } else {
983  $this->error = $this->db->lasterror();
984  return -1;
985  }
986  }
987  }
988 
989  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
995  public function fetch_lines()
996  {
997  // phpcs:enable
998  global $conf;
999 
1000  $this->lines = array();
1001 
1002  $sql = ' SELECT de.rowid, de.comments, de.qty, de.value_unit, de.date, de.rang,';
1003  $sql .= " de.".$this->fk_element.", de.fk_c_type_fees, de.fk_c_exp_tax_cat, de.fk_projet as fk_project,";
1004  $sql .= ' de.tva_tx, de.vat_src_code,';
1005  $sql .= ' de.localtax1_tx, de.localtax2_tx, de.localtax1_type, de.localtax2_type,';
1006  $sql .= ' de.fk_ecm_files,';
1007  $sql .= ' de.total_ht, de.total_tva, de.total_ttc,';
1008  $sql .= ' de.total_localtax1, de.total_localtax2, de.rule_warning_message,';
1009  $sql .= ' ctf.code as code_type_fees, ctf.label as libelle_type_fees, ctf.accountancy_code as accountancy_code_type_fees,';
1010  $sql .= ' p.ref as ref_projet, p.title as title_projet';
1011  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as de';
1012  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_type_fees as ctf ON de.fk_c_type_fees = ctf.id';
1013  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as p ON de.fk_projet = p.rowid';
1014  $sql .= " WHERE de.".$this->fk_element." = ".((int) $this->id);
1015  if (!empty($conf->global->EXPENSEREPORT_LINES_SORTED_BY_ROWID)) {
1016  $sql .= ' ORDER BY de.rang ASC, de.rowid ASC';
1017  } else {
1018  $sql .= ' ORDER BY de.rang ASC, de.date ASC';
1019  }
1020 
1021  $resql = $this->db->query($sql);
1022  if ($resql) {
1023  $num = $this->db->num_rows($resql);
1024  $i = 0;
1025  while ($i < $num) {
1026  $objp = $this->db->fetch_object($resql);
1027 
1028  $deplig = new ExpenseReportLine($this->db);
1029 
1030  $deplig->rowid = $objp->rowid;
1031  $deplig->id = $objp->rowid;
1032  $deplig->comments = $objp->comments;
1033  $deplig->qty = $objp->qty;
1034  $deplig->value_unit = $objp->value_unit;
1035  $deplig->date = $objp->date;
1036  $deplig->dates = $this->db->jdate($objp->date);
1037 
1038  $deplig->fk_expensereport = $objp->fk_expensereport;
1039  $deplig->fk_c_type_fees = $objp->fk_c_type_fees;
1040  $deplig->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
1041  $deplig->fk_projet = $objp->fk_project; // deprecated
1042  $deplig->fk_project = $objp->fk_project;
1043  $deplig->fk_ecm_files = $objp->fk_ecm_files;
1044 
1045  $deplig->total_ht = $objp->total_ht;
1046  $deplig->total_tva = $objp->total_tva;
1047  $deplig->total_ttc = $objp->total_ttc;
1048  $deplig->total_localtax1 = $objp->total_localtax1;
1049  $deplig->total_localtax2 = $objp->total_localtax2;
1050 
1051  $deplig->type_fees_code = empty($objp->code_type_fees) ? 'TF_OTHER' : $objp->code_type_fees;
1052  $deplig->type_fees_libelle = $objp->libelle_type_fees;
1053  $deplig->type_fees_accountancy_code = $objp->accountancy_code_type_fees;
1054 
1055  $deplig->tva_tx = $objp->tva_tx;
1056  $deplig->vatrate = $objp->tva_tx;
1057  $deplig->vat_src_code = $objp->vat_src_code;
1058  $deplig->localtax1_tx = $objp->localtax1_tx;
1059  $deplig->localtax2_tx = $objp->localtax2_tx;
1060  $deplig->localtax1_type = $objp->localtax1_type;
1061  $deplig->localtax2_type = $objp->localtax2_type;
1062 
1063  $deplig->projet_ref = $objp->ref_projet;
1064  $deplig->projet_title = $objp->title_projet;
1065 
1066  $deplig->rule_warning_message = $objp->rule_warning_message;
1067 
1068  $deplig->rang = $objp->rang;
1069 
1070  $this->lines[$i] = $deplig;
1071 
1072  $i++;
1073  }
1074  $this->db->free($resql);
1075  return 1;
1076  } else {
1077  $this->error = $this->db->lasterror();
1078  dol_syslog(get_class($this)."::fetch_lines: Error ".$this->error, LOG_ERR);
1079  return -3;
1080  }
1081  }
1082 
1083 
1091  public function delete(User $user = null, $notrigger = false)
1092  {
1093  global $conf;
1094  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1095 
1096  $error = 0;
1097 
1098  $this->db->begin();
1099 
1100  if (!$notrigger) {
1101  // Call trigger
1102  $result = $this->call_trigger('EXPENSE_REPORT_DELETE', $user);
1103  if ($result < 0) {
1104  $error++;
1105  }
1106  // End call triggers
1107  }
1108 
1109  // Delete extrafields of lines and lines
1110  if (!$error && !empty($this->table_element_line)) {
1111  $tabletodelete = $this->table_element_line;
1112  //$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).")";
1113  $sql = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id);
1114  if (!$this->db->query($sql)) {
1115  $error++;
1116  $this->error = $this->db->lasterror();
1117  $this->errors[] = $this->error;
1118  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1119  }
1120  }
1121 
1122  if (!$error) {
1123  // Delete linked object
1124  $res = $this->deleteObjectLinked();
1125  if ($res < 0) {
1126  $error++;
1127  }
1128  }
1129 
1130  if (!$error) {
1131  // Delete linked contacts
1132  $res = $this->delete_linked_contact();
1133  if ($res < 0) {
1134  $error++;
1135  }
1136  }
1137 
1138  // Removed extrafields of object
1139  if (!$error) {
1140  $result = $this->deleteExtraFields();
1141  if ($result < 0) {
1142  $error++;
1143  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1144  }
1145  }
1146 
1147  // Delete main record
1148  if (!$error) {
1149  $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".((int) $this->id);
1150  $res = $this->db->query($sql);
1151  if (!$res) {
1152  $error++;
1153  $this->error = $this->db->lasterror();
1154  $this->errors[] = $this->error;
1155  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1156  }
1157  }
1158 
1159  // Delete record into ECM index and physically
1160  if (!$error) {
1161  $res = $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
1162  if (!$res) {
1163  $error++;
1164  }
1165  }
1166 
1167  if (!$error) {
1168  // We remove directory
1169  $ref = dol_sanitizeFileName($this->ref);
1170  if ($conf->expensereport->multidir_output[$this->entity] && !empty($this->ref)) {
1171  $dir = $conf->expensereport->multidir_output[$this->entity]."/".$ref;
1172  $file = $dir."/".$ref.".pdf";
1173  if (file_exists($file)) {
1174  dol_delete_preview($this);
1175 
1176  if (!dol_delete_file($file, 0, 0, 0, $this)) {
1177  $this->error = 'ErrorFailToDeleteFile';
1178  $this->errors[] = $this->error;
1179  $this->db->rollback();
1180  return 0;
1181  }
1182  }
1183  if (file_exists($dir)) {
1184  $res = @dol_delete_dir_recursive($dir);
1185  if (!$res) {
1186  $this->error = 'ErrorFailToDeleteDir';
1187  $this->errors[] = $this->error;
1188  $this->db->rollback();
1189  return 0;
1190  }
1191  }
1192  }
1193  }
1194 
1195  if (!$error) {
1196  dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
1197  $this->db->commit();
1198  return 1;
1199  } else {
1200  $this->db->rollback();
1201  return -1;
1202  }
1203  }
1204 
1212  public function setValidate($fuser, $notrigger = 0)
1213  {
1214  global $conf, $langs, $user;
1215 
1216  $error = 0;
1217  $now = dol_now();
1218 
1219  // Protection
1220  if ($this->status == self::STATUS_VALIDATED) {
1221  dol_syslog(get_class($this)."::valid action abandonned: already validated", LOG_WARNING);
1222  return 0;
1223  }
1224 
1225  $this->date_valid = $now; // Required for the getNextNum later.
1226 
1227  // Define new ref
1228  if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
1229  $num = $this->getNextNumRef();
1230  } else {
1231  $num = $this->ref;
1232  }
1233  if (empty($num) || $num < 0) {
1234  return -1;
1235  }
1236 
1237  $this->newref = dol_sanitizeFileName($num);
1238 
1239  $this->db->begin();
1240 
1241  // Validate
1242  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1243  $sql .= " SET ref = '".$this->db->escape($num)."',";
1244  $sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
1245  $sql .= " date_valid='".$this->db->idate($this->date_valid)."',";
1246  $sql .= " fk_user_valid = ".$user->id;
1247  $sql .= " WHERE rowid = ".((int) $this->id);
1248 
1249  $resql = $this->db->query($sql);
1250  if ($resql) {
1251  if (!$error && !$notrigger) {
1252  // Call trigger
1253  $result = $this->call_trigger('EXPENSE_REPORT_VALIDATE', $fuser);
1254  if ($result < 0) {
1255  $error++;
1256  }
1257  // End call triggers
1258  }
1259 
1260  if (!$error) {
1261  $this->oldref = $this->ref;
1262 
1263  // Rename directory if dir was a temporary ref
1264  if (preg_match('/^[\(]?PROV/i', $this->ref)) {
1265  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1266 
1267  // Now we rename also files into index
1268  $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)."'";
1269  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'expensereport/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1270  $resql = $this->db->query($sql);
1271  if (!$resql) {
1272  $error++; $this->error = $this->db->lasterror();
1273  }
1274 
1275  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1276  $oldref = dol_sanitizeFileName($this->ref);
1277  $newref = dol_sanitizeFileName($num);
1278  $dirsource = $conf->expensereport->dir_output.'/'.$oldref;
1279  $dirdest = $conf->expensereport->dir_output.'/'.$newref;
1280  if (!$error && file_exists($dirsource)) {
1281  dol_syslog(get_class($this)."::setValidate() rename dir ".$dirsource." into ".$dirdest);
1282 
1283  if (@rename($dirsource, $dirdest)) {
1284  dol_syslog("Rename ok");
1285  // Rename docs starting with $oldref with $newref
1286  $listoffiles = dol_dir_list($conf->expensereport->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
1287  foreach ($listoffiles as $fileentry) {
1288  $dirsource = $fileentry['name'];
1289  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1290  $dirsource = $fileentry['path'].'/'.$dirsource;
1291  $dirdest = $fileentry['path'].'/'.$dirdest;
1292  @rename($dirsource, $dirdest);
1293  }
1294  }
1295  }
1296  }
1297  }
1298 
1299  // Set new ref and current status
1300  if (!$error) {
1301  $this->ref = $num;
1302  $this->status = self::STATUS_VALIDATED;
1303  }
1304 
1305  if (empty($error)) {
1306  $this->db->commit();
1307  return 1;
1308  } else {
1309  $this->db->rollback();
1310  $this->error = $this->db->error();
1311  return -2;
1312  }
1313  } else {
1314  $this->db->rollback();
1315  $this->error = $this->db->lasterror();
1316  return -1;
1317  }
1318  }
1319 
1320  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1327  public function set_save_from_refuse($fuser)
1328  {
1329  // phpcs:enable
1330  global $conf, $langs;
1331 
1332  // Sélection de la date de début de la NDF
1333  $sql = 'SELECT date_debut';
1334  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
1335  $sql .= " WHERE rowid = ".((int) $this->id);
1336 
1337  $result = $this->db->query($sql);
1338 
1339  $objp = $this->db->fetch_object($result);
1340 
1341  $this->date_debut = $this->db->jdate($objp->date_debut);
1342 
1343  if ($this->status != self::STATUS_VALIDATED) {
1344  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1345  $sql .= " SET fk_statut = ".self::STATUS_VALIDATED;
1346  $sql .= " WHERE rowid = ".((int) $this->id);
1347 
1348  dol_syslog(get_class($this)."::set_save_from_refuse", LOG_DEBUG);
1349 
1350  if ($this->db->query($sql)) {
1351  return 1;
1352  } else {
1353  $this->error = $this->db->lasterror();
1354  return -1;
1355  }
1356  } else {
1357  dol_syslog(get_class($this)."::set_save_from_refuse expensereport already with save status", LOG_WARNING);
1358  }
1359  }
1360 
1368  public function setApproved($fuser, $notrigger = 0)
1369  {
1370  $now = dol_now();
1371  $error = 0;
1372 
1373  // date approval
1374  $this->date_approve = $now;
1375  if ($this->status != self::STATUS_APPROVED) {
1376  $this->db->begin();
1377 
1378  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1379  $sql .= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = ".self::STATUS_APPROVED.", fk_user_approve = ".((int) $fuser->id).",";
1380  $sql .= " date_approve='".$this->db->idate($this->date_approve)."'";
1381  $sql .= " WHERE rowid = ".((int) $this->id);
1382  if ($this->db->query($sql)) {
1383  if (!$notrigger) {
1384  // Call trigger
1385  $result = $this->call_trigger('EXPENSE_REPORT_APPROVE', $fuser);
1386 
1387  if ($result < 0) {
1388  $error++;
1389  }
1390  // End call triggers
1391  }
1392 
1393  if (empty($error)) {
1394  $this->db->commit();
1395  return 1;
1396  } else {
1397  $this->db->rollback();
1398  $this->error = $this->db->error();
1399  return -2;
1400  }
1401  } else {
1402  $this->db->rollback();
1403  $this->error = $this->db->lasterror();
1404  return -1;
1405  }
1406  } else {
1407  dol_syslog(get_class($this)."::setApproved expensereport already with approve status", LOG_WARNING);
1408  }
1409 
1410  return 0;
1411  }
1412 
1421  public function setDeny($fuser, $details, $notrigger = 0)
1422  {
1423  $now = dol_now();
1424  $error = 0;
1425 
1426  // date de refus
1427  if ($this->status != self::STATUS_REFUSED) {
1428  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1429  $sql .= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = ".self::STATUS_REFUSED.", fk_user_refuse = ".((int) $fuser->id).",";
1430  $sql .= " date_refuse='".$this->db->idate($now)."',";
1431  $sql .= " detail_refuse='".$this->db->escape($details)."',";
1432  $sql .= " fk_user_approve = NULL";
1433  $sql .= " WHERE rowid = ".((int) $this->id);
1434  if ($this->db->query($sql)) {
1435  $this->fk_statut = 99; // deprecated
1436  $this->status = 99;
1437  $this->fk_user_refuse = $fuser->id;
1438  $this->detail_refuse = $details;
1439  $this->date_refuse = $now;
1440 
1441  if (!$notrigger) {
1442  // Call trigger
1443  $result = $this->call_trigger('EXPENSE_REPORT_DENY', $fuser);
1444 
1445  if ($result < 0) {
1446  $error++;
1447  }
1448  // End call triggers
1449  }
1450 
1451  if (empty($error)) {
1452  $this->db->commit();
1453  return 1;
1454  } else {
1455  $this->db->rollback();
1456  $this->error = $this->db->error();
1457  return -2;
1458  }
1459  } else {
1460  $this->db->rollback();
1461  $this->error = $this->db->lasterror();
1462  return -1;
1463  }
1464  } else {
1465  dol_syslog(get_class($this)."::setDeny expensereport already with refuse status", LOG_WARNING);
1466  }
1467  }
1468 
1469  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1479  public function set_unpaid($fuser, $notrigger = 0)
1480  {
1481  // phpcs:enable
1482  dol_syslog(get_class($this)."::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE);
1483  return $this->setUnpaid($fuser, $notrigger);
1484  }
1485 
1493  public function setUnpaid($fuser, $notrigger = 0)
1494  {
1495  $error = 0;
1496 
1497  if ($this->paid) {
1498  $this->db->begin();
1499 
1500  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1501  $sql .= " SET paid = 0, fk_statut = ".self::STATUS_APPROVED;
1502  $sql .= " WHERE rowid = ".((int) $this->id);
1503 
1504  dol_syslog(get_class($this)."::set_unpaid", LOG_DEBUG);
1505 
1506  if ($this->db->query($sql)) {
1507  if (!$notrigger) {
1508  // Call trigger
1509  $result = $this->call_trigger('EXPENSE_REPORT_UNPAID', $fuser);
1510 
1511  if ($result < 0) {
1512  $error++;
1513  }
1514  // End call triggers
1515  }
1516 
1517  if (empty($error)) {
1518  $this->db->commit();
1519  return 1;
1520  } else {
1521  $this->db->rollback();
1522  $this->error = $this->db->error();
1523  return -2;
1524  }
1525  } else {
1526  $this->db->rollback();
1527  $this->error = $this->db->error();
1528  return -1;
1529  }
1530  } else {
1531  dol_syslog(get_class($this)."::set_unpaid expensereport already with unpaid status", LOG_WARNING);
1532  }
1533  }
1534 
1535  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1544  public function set_cancel($fuser, $detail, $notrigger = 0)
1545  {
1546  // phpcs:enable
1547  $error = 0;
1548  $this->date_cancel = $this->db->idate(dol_now());
1549  if ($this->status != self::STATUS_CANCELED) {
1550  $this->db->begin();
1551 
1552  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1553  $sql .= " SET fk_statut = ".self::STATUS_CANCELED.", fk_user_cancel = ".((int) $fuser->id);
1554  $sql .= ", date_cancel='".$this->db->idate($this->date_cancel)."'";
1555  $sql .= " ,detail_cancel='".$this->db->escape($detail)."'";
1556  $sql .= " WHERE rowid = ".((int) $this->id);
1557 
1558  dol_syslog(get_class($this)."::set_cancel", LOG_DEBUG);
1559 
1560  if ($this->db->query($sql)) {
1561  if (!$notrigger) {
1562  // Call trigger
1563  $result = $this->call_trigger('EXPENSE_REPORT_CANCEL', $fuser);
1564 
1565  if ($result < 0) {
1566  $error++;
1567  }
1568  // End call triggers
1569  }
1570 
1571  if (empty($error)) {
1572  $this->db->commit();
1573  return 1;
1574  } else {
1575  $this->db->rollback();
1576  $this->error = $this->db->error();
1577  return -2;
1578  }
1579  } else {
1580  $this->db->rollback();
1581  $this->error = $this->db->error();
1582  return -1;
1583  }
1584  } else {
1585  dol_syslog(get_class($this)."::set_cancel expensereport already with cancel status", LOG_WARNING);
1586  }
1587  }
1588 
1594  public function getNextNumRef()
1595  {
1596  global $langs, $conf;
1597  $langs->load("trips");
1598 
1599  if (!empty($conf->global->EXPENSEREPORT_ADDON)) {
1600  $mybool = false;
1601 
1602  $file = $conf->global->EXPENSEREPORT_ADDON.".php";
1603  $classname = $conf->global->EXPENSEREPORT_ADDON;
1604 
1605  // Include file with class
1606  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1607  foreach ($dirmodels as $reldir) {
1608  $dir = dol_buildpath($reldir."core/modules/expensereport/");
1609 
1610  // Load file with numbering class (if found)
1611  $mybool |= @include_once $dir.$file;
1612  }
1613 
1614  if ($mybool === false) {
1615  dol_print_error('', "Failed to include file ".$file);
1616  return '';
1617  }
1618 
1619  $obj = new $classname();
1620  $numref = $obj->getNextValue($this);
1621 
1622  if ($numref != "") {
1623  return $numref;
1624  } else {
1625  $this->error = $obj->error;
1626  $this->errors = $obj->errors;
1627  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1628  return -1;
1629  }
1630  } else {
1631  $this->error = "Error_EXPENSEREPORT_ADDON_NotDefined";
1632  return -2;
1633  }
1634  }
1635 
1648  public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1)
1649  {
1650  global $langs, $conf, $hookmanager;
1651 
1652  $result = '';
1653 
1654  $url = DOL_URL_ROOT.'/expensereport/card.php?id='.$this->id;
1655 
1656  if ($short) {
1657  return $url;
1658  }
1659 
1660  $label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("ExpenseReport").'</u>';
1661  if (isset($this->status)) {
1662  $label .= ' '.$this->getLibStatut(5);
1663  }
1664  if (!empty($this->ref)) {
1665  $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1666  }
1667  if (!empty($this->total_ht)) {
1668  $label .= '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
1669  }
1670  if (!empty($this->total_tva)) {
1671  $label .= '<br><b>'.$langs->trans('VAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
1672  }
1673  if (!empty($this->total_ttc)) {
1674  $label .= '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
1675  }
1676  if ($moretitle) {
1677  $label .= ' - '.$moretitle;
1678  }
1679 
1680  if ($option != 'nolink') {
1681  // Add param to save lastsearch_values or not
1682  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1683  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1684  $add_save_lastsearch_values = 1;
1685  }
1686  if ($add_save_lastsearch_values) {
1687  $url .= '&save_lastsearch_values=1';
1688  }
1689  }
1690 
1691  $ref = $this->ref;
1692  if (empty($ref)) {
1693  $ref = $this->id;
1694  }
1695 
1696  $linkclose = '';
1697  if (empty($notooltip)) {
1698  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1699  $label = $langs->trans("ShowExpenseReport");
1700  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1701  }
1702  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1703  $linkclose .= ' class="classfortooltip"';
1704  }
1705 
1706  $linkstart = '<a href="'.$url.'"';
1707  $linkstart .= $linkclose.'>';
1708  $linkend = '</a>';
1709 
1710  $result .= $linkstart;
1711  if ($withpicto) {
1712  $result .= img_object(($notooltip ? '' : $label), $this->picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
1713  }
1714  if ($withpicto != 2) {
1715  $result .= ($max ? dol_trunc($ref, $max) : $ref);
1716  }
1717  $result .= $linkend;
1718 
1719  global $action;
1720  $hookmanager->initHooks(array($this->element . 'dao'));
1721  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1722  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1723  if ($reshook > 0) {
1724  $result = $hookmanager->resPrint;
1725  } else {
1726  $result .= $hookmanager->resPrint;
1727  }
1728  return $result;
1729  }
1730 
1731  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1739  public function update_totaux_add($ligne_total_ht, $ligne_total_tva)
1740  {
1741  // phpcs:enable
1742  $this->total_ht = $this->total_ht + $ligne_total_ht;
1743  $this->total_tva = $this->total_tva + $ligne_total_tva;
1744  $this->total_ttc = $this->total_ht + $this->total_tva;
1745 
1746  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
1747  $sql .= " total_ht = ".$this->total_ht;
1748  $sql .= " , total_ttc = ".$this->total_ttc;
1749  $sql .= " , total_tva = ".$this->total_tva;
1750  $sql .= " WHERE rowid = ".((int) $this->id);
1751 
1752  $result = $this->db->query($sql);
1753  if ($result) {
1754  return 1;
1755  } else {
1756  $this->error = $this->db->error();
1757  return -1;
1758  }
1759  }
1760 
1776  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)
1777  {
1778  global $conf, $langs, $mysoc;
1779 
1780  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);
1781 
1782  if ($this->status == self::STATUS_DRAFT) {
1783  if (empty($qty)) {
1784  $qty = 0;
1785  }
1786  if (empty($fk_c_type_fees) || $fk_c_type_fees < 0) {
1787  $fk_c_type_fees = 0;
1788  }
1789  if (empty($fk_c_exp_tax_cat) || $fk_c_exp_tax_cat < 0) {
1790  $fk_c_exp_tax_cat = 0;
1791  }
1792  if (empty($vatrate) || $vatrate < 0) {
1793  $vatrate = 0;
1794  }
1795  if (empty($date)) {
1796  $date = '';
1797  }
1798  if (empty($fk_project)) {
1799  $fk_project = 0;
1800  }
1801 
1802  $qty = price2num($qty);
1803  if (!preg_match('/\s*\((.*)\)/', $vatrate)) {
1804  $vatrate = price2num($vatrate); // $txtva can have format '5.0 (XXX)' or '5'
1805  }
1806  $up = price2num($up);
1807 
1808  $this->db->begin();
1809 
1810  $this->line = new ExpenseReportLine($this->db);
1811 
1812  // We don't know seller and buyer for expense reports
1813  $seller = $mysoc; // We use same than current company (expense report are often done in same country)
1814  $seller->tva_assuj = 1; // Most seller uses vat
1815  $buyer = new Societe($this->db);
1816 
1817  $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller);
1818 
1819  $vat_src_code = '';
1820  $reg = array();
1821  if (preg_match('/\s*\((.*)\)/', $vatrate, $reg)) {
1822  $vat_src_code = $reg[1];
1823  $vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate.
1824  }
1825  $vatrate = preg_replace('/\*/', '', $vatrate);
1826 
1827  $tmp = calcul_price_total($qty, $up, 0, $vatrate, -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
1828 
1829  $this->line->value_unit = $up;
1830 
1831  $this->line->vat_src_code = $vat_src_code;
1832  $this->line->vatrate = price2num($vatrate);
1833  $this->line->localtax1_tx = $localtaxes_type[1];
1834  $this->line->localtax2_tx = $localtaxes_type[3];
1835  $this->line->localtax1_type = $localtaxes_type[0];
1836  $this->line->localtax2_type = $localtaxes_type[2];
1837 
1838  $this->line->total_ttc = $tmp[2];
1839  $this->line->total_ht = $tmp[0];
1840  $this->line->total_tva = $tmp[1];
1841  $this->line->total_localtax1 = $tmp[9];
1842  $this->line->total_localtax2 = $tmp[10];
1843 
1844  $this->line->fk_expensereport = $this->id;
1845  $this->line->qty = $qty;
1846  $this->line->date = $date;
1847  $this->line->fk_c_type_fees = $fk_c_type_fees;
1848  $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
1849  $this->line->comments = $comments;
1850  $this->line->fk_projet = $fk_project; // deprecated
1851  $this->line->fk_project = $fk_project;
1852 
1853  $this->line->fk_ecm_files = $fk_ecm_files;
1854 
1855  $this->applyOffset();
1856  $this->checkRules($type, $seller);
1857 
1858  $result = $this->line->insert(0, true);
1859  if ($result > 0) {
1860  $result = $this->update_price(); // This method is designed to add line from user input so total calculation must be done using 'auto' mode.
1861  if ($result > 0) {
1862  $this->db->commit();
1863  return $this->line->id;
1864  } else {
1865  $this->db->rollback();
1866  return -1;
1867  }
1868  } else {
1869  $this->error = $this->line->error;
1870  dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1871  $this->db->rollback();
1872  return -2;
1873  }
1874  } else {
1875  dol_syslog(get_class($this)."::addline status of expense report must be Draft to allow use of ->addline()", LOG_ERR);
1876  $this->error = 'ErrorExpenseNotDraft';
1877  return -3;
1878  }
1879  }
1880 
1888  public function checkRules($type = 0, $seller = '')
1889  {
1890  global $user, $conf, $db, $langs, $mysoc;
1891 
1892  $langs->load('trips');
1893 
1894  // We don't know seller and buyer for expense reports
1895  if (!is_object($seller)) {
1896  $seller = $mysoc; // We use same than current company (expense report are often done in same country)
1897  $seller->tva_assuj = 1; // Most seller uses vat
1898  }
1899 
1900  $expensereportrule = new ExpenseReportRule($db);
1901  $rulestocheck = $expensereportrule->getAllRule($this->line->fk_c_type_fees, $this->line->date, $this->fk_user_author);
1902 
1903  $violation = 0;
1904  $rule_warning_message_tab = array();
1905 
1906  $current_total_ttc = $this->line->total_ttc;
1907  $new_current_total_ttc = $this->line->total_ttc;
1908 
1909  // check if one is violated
1910  foreach ($rulestocheck as $rule) {
1911  if (in_array($rule->code_expense_rules_type, array('EX_DAY', 'EX_MON', 'EX_YEA'))) {
1912  $amount_to_test = $this->line->getExpAmount($rule, $this->fk_user_author, $rule->code_expense_rules_type);
1913  } else {
1914  $amount_to_test = $current_total_ttc; // EX_EXP
1915  }
1916 
1917  $amount_to_test = $amount_to_test - $current_total_ttc + $new_current_total_ttc; // if amount as been modified by a previous rule
1918 
1919  if ($amount_to_test > $rule->amount) {
1920  $violation++;
1921 
1922  if ($rule->restrictive) {
1923  $this->error = 'ExpenseReportConstraintViolationError';
1924  $this->errors[] = $this->error;
1925 
1926  $new_current_total_ttc -= $amount_to_test - $rule->amount; // ex, entered 16€, limit 12€, subtracts 4€;
1927  $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));
1928  } else {
1929  $this->error = 'ExpenseReportConstraintViolationWarning';
1930  $this->errors[] = $this->error;
1931 
1932  $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));
1933  }
1934 
1935  // No break, we sould test if another rule is violated
1936  }
1937  }
1938 
1939  $this->line->rule_warning_message = implode('\n', $rule_warning_message_tab);
1940 
1941  if ($violation > 0) {
1942  $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);
1943 
1944  $this->line->value_unit = $tmp[5];
1945  $this->line->total_ttc = $tmp[2];
1946  $this->line->total_ht = $tmp[0];
1947  $this->line->total_tva = $tmp[1];
1948  $this->line->total_localtax1 = $tmp[9];
1949  $this->line->total_localtax2 = $tmp[10];
1950 
1951  return false;
1952  } else {
1953  return true;
1954  }
1955  }
1956 
1964  public function applyOffset($type = 0, $seller = '')
1965  {
1966  global $conf, $mysoc;
1967 
1968  if (empty($conf->global->MAIN_USE_EXPENSE_IK)) {
1969  return false;
1970  }
1971 
1972  $userauthor = new User($this->db);
1973  if ($userauthor->fetch($this->fk_user_author) <= 0) {
1974  $this->error = 'ErrorCantFetchUser';
1975  $this->errors[] = 'ErrorCantFetchUser';
1976  return false;
1977  }
1978 
1979  // We don't know seller and buyer for expense reports
1980  if (!is_object($seller)) {
1981  $seller = $mysoc; // We use same than current company (expense report are often done in same country)
1982  $seller->tva_assuj = 1; // Most seller uses vat
1983  }
1984 
1985  $expenseik = new ExpenseReportIk($this->db);
1986  $range = $expenseik->getRangeByUser($userauthor, $this->line->fk_c_exp_tax_cat);
1987 
1988  if (empty($range)) {
1989  $this->error = 'ErrorNoRangeAvailable';
1990  $this->errors[] = 'ErrorNoRangeAvailable';
1991  return false;
1992  }
1993 
1994  if (!empty($conf->global->MAIN_EXPENSE_APPLY_ENTIRE_OFFSET)) {
1995  $ikoffset = $range->ikoffset;
1996  } else {
1997  $ikoffset = $range->ikoffset / 12; // The amount of offset is a global value for the year
1998  }
1999 
2000  // Test if ikoffset has been applied for the current month
2001  if (!$this->offsetAlreadyGiven()) {
2002  $new_up = $range->coef + ($ikoffset / $this->line->qty);
2003  $tmp = calcul_price_total($this->line->qty, $new_up, 0, $this->line->vatrate, 0, 0, 0, 'TTC', 0, $type, $seller);
2004 
2005  $this->line->value_unit = $tmp[5];
2006  $this->line->total_ttc = $tmp[2];
2007  $this->line->total_ht = $tmp[0];
2008  $this->line->total_tva = $tmp[1];
2009  $this->line->total_localtax1 = $tmp[9];
2010  $this->line->total_localtax2 = $tmp[10];
2011 
2012  return true;
2013  }
2014 
2015  return false;
2016  }
2017 
2023  public function offsetAlreadyGiven()
2024  {
2025  $sql = 'SELECT e.rowid FROM '.MAIN_DB_PREFIX.'expensereport e';
2026  $sql .= " INNER JOIN ".MAIN_DB_PREFIX."expensereport_det d ON (e.rowid = d.fk_expensereport)";
2027  $sql .= " INNER JOIN ".MAIN_DB_PREFIX."c_type_fees f ON (d.fk_c_type_fees = f.id AND f.code = 'EX_KME')";
2028  $sql .= " WHERE e.fk_user_author = ".(int) $this->fk_user_author;
2029  $sql .= " AND YEAR(d.date) = '".dol_print_date($this->line->date, '%Y')."' AND MONTH(d.date) = '".dol_print_date($this->line->date, '%m')."'";
2030  if (!empty($this->line->id)) {
2031  $sql .= ' AND d.rowid <> '.((int) $this->line->id);
2032  }
2033 
2034  dol_syslog(get_class($this)."::offsetAlreadyGiven");
2035  $resql = $this->db->query($sql);
2036  if ($resql) {
2037  $num = $this->db->num_rows($resql);
2038  if ($num > 0) {
2039  return true;
2040  }
2041  } else {
2042  dol_print_error($this->db);
2043  }
2044 
2045  return false;
2046  }
2047 
2065  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)
2066  {
2067  global $user, $mysoc;
2068 
2069  if ($this->status == self::STATUS_DRAFT || $this->status == self::STATUS_REFUSED) {
2070  $this->db->begin();
2071 
2072  $error = 0;
2073  $type = 0; // TODO What if type is service ?
2074 
2075  // We don't know seller and buyer for expense reports
2076  $seller = $mysoc; // We use same than current company (expense report are often done in same country)
2077  $seller->tva_assuj = 1; // Most seller uses vat
2078  $seller->localtax1_assuj = $mysoc->localtax1_assuj; // We don't know, we reuse the state of company
2079  $seller->localtax2_assuj = $mysoc->localtax1_assuj; // We don't know, we reuse the state of company
2080  $buyer = new Societe($this->db);
2081 
2082  $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller);
2083 
2084  // Clean vat code
2085  $reg = array();
2086  $vat_src_code = '';
2087  if (preg_match('/\((.*)\)/', $vatrate, $reg)) {
2088  $vat_src_code = $reg[1];
2089  $vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate.
2090  }
2091  $vatrate = preg_replace('/\*/', '', $vatrate);
2092 
2093  $tmp = calcul_price_total($qty, $value_unit, 0, $vatrate, -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
2094  //var_dump($vatrate);var_dump($localtaxes_type);var_dump($tmp);exit;
2095  // calcul total of line
2096  //$total_ttc = price2num($qty*$value_unit, 'MT');
2097 
2098  $tx_tva = $vatrate / 100;
2099  $tx_tva = $tx_tva + 1;
2100 
2101  $this->line = new ExpenseReportLine($this->db);
2102  $this->line->comments = $comments;
2103  $this->line->qty = $qty;
2104  $this->line->value_unit = $value_unit;
2105  $this->line->date = $date;
2106 
2107  $this->line->fk_expensereport = $expensereport_id;
2108  $this->line->fk_c_type_fees = $type_fees_id;
2109  $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
2110  $this->line->fk_projet = $projet_id; // deprecated
2111  $this->line->fk_project = $projet_id;
2112 
2113  $this->line->vat_src_code = $vat_src_code;
2114  $this->line->vatrate = price2num($vatrate);
2115  $this->line->localtax1_tx = $localtaxes_type[1];
2116  $this->line->localtax2_tx = $localtaxes_type[3];
2117  $this->line->localtax1_type = $localtaxes_type[0];
2118  $this->line->localtax2_type = $localtaxes_type[2];
2119 
2120  $this->line->total_ttc = $tmp[2];
2121  $this->line->total_ht = $tmp[0];
2122  $this->line->total_tva = $tmp[1];
2123  $this->line->total_localtax1 = $tmp[9];
2124  $this->line->total_localtax2 = $tmp[10];
2125 
2126  $this->line->fk_ecm_files = $fk_ecm_files;
2127 
2128  $this->line->id = ((int) $rowid);
2129 
2130  // Select des infos sur le type fees
2131  $sql = "SELECT c.code as code_type_fees, c.label as libelle_type_fees";
2132  $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
2133  $sql .= " WHERE c.id = ".((int) $type_fees_id);
2134  $resql = $this->db->query($sql);
2135  if ($resql) {
2136  $objp_fees = $this->db->fetch_object($resql);
2137  $this->line->type_fees_code = $objp_fees->code_type_fees;
2138  $this->line->type_fees_libelle = $objp_fees->libelle_type_fees;
2139  $this->db->free($resql);
2140  }
2141 
2142  // Select des informations du projet
2143  $sql = "SELECT p.ref as ref_projet, p.title as title_projet";
2144  $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
2145  $sql .= " WHERE p.rowid = ".((int) $projet_id);
2146  $resql = $this->db->query($sql);
2147  if ($resql) {
2148  $objp_projet = $this->db->fetch_object($resql);
2149  $this->line->projet_ref = $objp_projet->ref_projet;
2150  $this->line->projet_title = $objp_projet->title_projet;
2151  $this->db->free($resql);
2152  }
2153 
2154  $this->applyOffset();
2155  $this->checkRules();
2156 
2157  $result = $this->line->update($user);
2158  if ($result < 0) {
2159  $error++;
2160  }
2161 
2162  if (!$error && !$notrigger) {
2163  // Call triggers
2164  $result = $this->call_trigger('EXPENSE_REPORT_DET_MODIFY', $user);
2165  if ($result < 0) {
2166  $error++;
2167  }
2168  // End call triggers
2169  }
2170 
2171  if (!$error) {
2172  $this->db->commit();
2173  return 1;
2174  } else {
2175  $this->error = $this->line->error;
2176  $this->errors = $this->line->errors;
2177  $this->db->rollback();
2178  return -2;
2179  }
2180  }
2181  }
2182 
2191  public function deleteline($rowid, $fuser = '', $notrigger = 0)
2192  {
2193  $error=0;
2194 
2195  $this->db->begin();
2196 
2197  if (!$notrigger) {
2198  // Call triggers
2199  $result = $this->call_trigger('EXPENSE_REPORT_DET_DELETE', $fuser);
2200  if ($result < 0) {
2201  $error++;
2202  }
2203  // End call triggers
2204  }
2205 
2206  $sql = ' DELETE FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2207  $sql .= ' WHERE rowid = '.((int) $rowid);
2208 
2209  dol_syslog(get_class($this)."::deleteline sql=".$sql);
2210  $result = $this->db->query($sql);
2211 
2212  if (!$result || $error > 0 ) {
2213  $this->error = $this->db->error();
2214  dol_syslog(get_class($this)."::deleteline Error ".$this->error, LOG_ERR);
2215  $this->db->rollback();
2216  return -1;
2217  }
2218 
2219  $this->update_price();
2220 
2221  $this->db->commit();
2222 
2223  return 1;
2224  }
2225 
2226  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2235  public function periode_existe($fuser, $date_debut, $date_fin)
2236  {
2237  // phpcs:enable
2238  $sql = "SELECT rowid, date_debut, date_fin";
2239  $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
2240  $sql .= " WHERE fk_user_author = '{$fuser->id}'";
2241 
2242  dol_syslog(get_class($this)."::periode_existe sql=".$sql);
2243  $result = $this->db->query($sql);
2244  if ($result) {
2245  $num_rows = $this->db->num_rows($result); $i = 0;
2246 
2247  if ($num_rows > 0) {
2248  $date_d_form = $date_debut;
2249  $date_f_form = $date_fin;
2250 
2251  while ($i < $num_rows) {
2252  $objp = $this->db->fetch_object($result);
2253 
2254  $date_d_req = $this->db->jdate($objp->date_debut); // 3
2255  $date_f_req = $this->db->jdate($objp->date_fin); // 4
2256 
2257  if (!($date_f_form < $date_d_req || $date_d_form > $date_f_req)) {
2258  return $objp->rowid;
2259  }
2260 
2261  $i++;
2262  }
2263 
2264  return 0;
2265  } else {
2266  return 0;
2267  }
2268  } else {
2269  $this->error = $this->db->lasterror();
2270  dol_syslog(get_class($this)."::periode_existe Error ".$this->error, LOG_ERR);
2271  return -1;
2272  }
2273  }
2274 
2275 
2276  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2284  {
2285  // phpcs:enable
2286  $users_validator = array();
2287 
2288  $sql = "SELECT DISTINCT ur.fk_user";
2289  $sql .= " FROM ".MAIN_DB_PREFIX."user_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2290  $sql .= " WHERE ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2291  $sql .= " UNION";
2292  $sql .= " SELECT DISTINCT ugu.fk_user";
2293  $sql .= " FROM ".MAIN_DB_PREFIX."usergroup_user as ugu, ".MAIN_DB_PREFIX."usergroup_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2294  $sql .= " WHERE ugu.fk_usergroup = ur.fk_usergroup AND ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2295  //print $sql;
2296 
2297  dol_syslog(get_class($this)."::fetch_users_approver_expensereport sql=".$sql);
2298  $result = $this->db->query($sql);
2299  if ($result) {
2300  $num_rows = $this->db->num_rows($result); $i = 0;
2301  while ($i < $num_rows) {
2302  $objp = $this->db->fetch_object($result);
2303  array_push($users_validator, $objp->fk_user);
2304  $i++;
2305  }
2306  return $users_validator;
2307  } else {
2308  $this->error = $this->db->lasterror();
2309  dol_syslog(get_class($this)."::fetch_users_approver_expensereport Error ".$this->error, LOG_ERR);
2310  return -1;
2311  }
2312  }
2313 
2325  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
2326  {
2327  global $conf;
2328 
2329  $outputlangs->load("trips");
2330 
2331  if (!dol_strlen($modele)) {
2332  if (!empty($this->model_pdf)) {
2333  $modele = $this->model_pdf;
2334  } elseif (!empty($this->modelpdf)) { // deprecated
2335  $modele = $this->modelpdf;
2336  } elseif (!empty($conf->global->EXPENSEREPORT_ADDON_PDF)) {
2337  $modele = $conf->global->EXPENSEREPORT_ADDON_PDF;
2338  }
2339  }
2340 
2341  if (!empty($modele)) {
2342  $modelpath = "core/modules/expensereport/doc/";
2343 
2344  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2345  } else {
2346  return 0;
2347  }
2348  }
2349 
2356  public function listOfTypes($active = 1)
2357  {
2358  global $langs;
2359  $ret = array();
2360  $sql = "SELECT id, code, label";
2361  $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees";
2362  $sql .= " WHERE active = ".((int) $active);
2363  dol_syslog(get_class($this)."::listOfTypes", LOG_DEBUG);
2364  $result = $this->db->query($sql);
2365  if ($result) {
2366  $num = $this->db->num_rows($result);
2367  $i = 0;
2368  while ($i < $num) {
2369  $obj = $this->db->fetch_object($result);
2370  $ret[$obj->code] = (($langs->transnoentitiesnoconv($obj->code) != $obj->code) ? $langs->transnoentitiesnoconv($obj->code) : $obj->label);
2371  $i++;
2372  }
2373  } else {
2374  dol_print_error($this->db);
2375  }
2376  return $ret;
2377  }
2378 
2379  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2385  public function load_state_board()
2386  {
2387  // phpcs:enable
2388  global $conf, $user;
2389 
2390  $this->nb = array();
2391 
2392  $sql = "SELECT count(ex.rowid) as nb";
2393  $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2394  $sql .= " WHERE ex.fk_statut > 0";
2395  $sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2396  if (empty($user->rights->expensereport->readall)) {
2397  $userchildids = $user->getAllChildIds(1);
2398  $sql .= " AND (ex.fk_user_author IN (".$this->db->sanitize(join(',', $userchildids)).")";
2399  $sql .= " OR ex.fk_user_validator IN (".$this->db->sanitize(join(',', $userchildids))."))";
2400  }
2401 
2402  $resql = $this->db->query($sql);
2403  if ($resql) {
2404  while ($obj = $this->db->fetch_object($resql)) {
2405  $this->nb["expensereports"] = $obj->nb;
2406  }
2407  $this->db->free($resql);
2408  return 1;
2409  } else {
2410  dol_print_error($this->db);
2411  $this->error = $this->db->error();
2412  return -1;
2413  }
2414  }
2415 
2416  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2424  public function load_board($user, $option = 'topay')
2425  {
2426  // phpcs:enable
2427  global $conf, $langs;
2428 
2429  if ($user->socid) {
2430  return -1; // protection pour eviter appel par utilisateur externe
2431  }
2432 
2433  $now = dol_now();
2434 
2435  $sql = "SELECT ex.rowid, ex.date_valid";
2436  $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2437  if ($option == 'toapprove') {
2438  $sql .= " WHERE ex.fk_statut = ".self::STATUS_VALIDATED;
2439  } else {
2440  $sql .= " WHERE ex.fk_statut = ".self::STATUS_APPROVED;
2441  }
2442  $sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2443  if (empty($user->rights->expensereport->readall)) {
2444  $userchildids = $user->getAllChildIds(1);
2445  $sql .= " AND (ex.fk_user_author IN (".$this->db->sanitize(join(',', $userchildids)).")";
2446  $sql .= " OR ex.fk_user_validator IN (".$this->db->sanitize(join(',', $userchildids))."))";
2447  }
2448 
2449  $resql = $this->db->query($sql);
2450  if ($resql) {
2451  $langs->load("trips");
2452 
2453  $response = new WorkboardResponse();
2454  if ($option == 'toapprove') {
2455  $response->warning_delay = $conf->expensereport->approve->warning_delay / 60 / 60 / 24;
2456  $response->label = $langs->trans("ExpenseReportsToApprove");
2457  $response->labelShort = $langs->trans("ToApprove");
2458  $response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_VALIDATED;
2459  } else {
2460  $response->warning_delay = $conf->expensereport->payment->warning_delay / 60 / 60 / 24;
2461  $response->label = $langs->trans("ExpenseReportsToPay");
2462  $response->labelShort = $langs->trans("StatusToPay");
2463  $response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_APPROVED;
2464  }
2465  $response->img = img_object('', "trip");
2466 
2467  while ($obj = $this->db->fetch_object($resql)) {
2468  $response->nbtodo++;
2469 
2470  if ($option == 'toapprove') {
2471  if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->approve->warning_delay)) {
2472  $response->nbtodolate++;
2473  }
2474  } else {
2475  if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->payment->warning_delay)) {
2476  $response->nbtodolate++;
2477  }
2478  }
2479  }
2480 
2481  return $response;
2482  } else {
2483  dol_print_error($this->db);
2484  $this->error = $this->db->error();
2485  return -1;
2486  }
2487  }
2488 
2495  public function hasDelay($option)
2496  {
2497  global $conf;
2498 
2499  // Only valid expenses reports
2500  if ($option == 'toapprove' && $this->status != 2) {
2501  return false;
2502  }
2503  if ($option == 'topay' && $this->status != 5) {
2504  return false;
2505  }
2506 
2507  $now = dol_now();
2508  if ($option == 'toapprove') {
2509  return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->approve->warning_delay);
2510  } else {
2511  return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->payment->warning_delay);
2512  }
2513  }
2514 
2520  public function getVentilExportCompta()
2521  {
2522  $alreadydispatched = 0;
2523 
2524  $type = 'expense_report';
2525 
2526  $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);
2527  $resql = $this->db->query($sql);
2528  if ($resql) {
2529  $obj = $this->db->fetch_object($resql);
2530  if ($obj) {
2531  $alreadydispatched = $obj->nb;
2532  }
2533  } else {
2534  $this->error = $this->db->lasterror();
2535  return -1;
2536  }
2537 
2538  if ($alreadydispatched) {
2539  return 1;
2540  }
2541  return 0;
2542  }
2543 
2549  public function getSumPayments()
2550  {
2551  $table = 'payment_expensereport';
2552  $field = 'fk_expensereport';
2553 
2554  $sql = 'SELECT sum(amount) as amount';
2555  $sql .= ' FROM '.MAIN_DB_PREFIX.$table;
2556  $sql .= " WHERE ".$field." = ".((int) $this->id);
2557 
2558  dol_syslog(get_class($this)."::getSumPayments", LOG_DEBUG);
2559  $resql = $this->db->query($sql);
2560  if ($resql) {
2561  $obj = $this->db->fetch_object($resql);
2562  $this->db->free($resql);
2563  return (empty($obj->amount) ? 0 : $obj->amount);
2564  } else {
2565  $this->error = $this->db->lasterror();
2566  return -1;
2567  }
2568  }
2569 
2578  public function computeTotalKm($fk_cat, $qty, $tva)
2579  {
2580  global $langs,$user,$db,$conf;
2581 
2582 
2583  $cumulYearQty = 0;
2584  $ranges = array();
2585  $coef = 0;
2586 
2587 
2588  if ($fk_cat < 0) {
2589  $this->error = $langs->trans('ErrorBadParameterCat');
2590  return -1;
2591  }
2592 
2593  if ($qty <= 0) {
2594  $this->error = $langs->trans('ErrorBadParameterQty');
2595  return -1;
2596  }
2597 
2598  $currentUser = new User($db);
2599  $currentUser->fetch($this->fk_user);
2600  $currentUser->getrights('expensereport');
2601  //Clean
2602  $qty = price2num($qty);
2603 
2604  $sql = " SELECT r.range_ik, t.ikoffset as offset, t.coef";
2605  $sql .= " FROM ".MAIN_DB_PREFIX."expensereport_ik t";
2606  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_exp_tax_range r ON r.rowid = t.fk_range";
2607  $sql .= " WHERE t.fk_c_exp_tax_cat = ".(int) $fk_cat;
2608  $sql .= " ORDER BY r.range_ik ASC";
2609 
2610  dol_syslog("expenseReport::computeTotalkm sql=".$sql, LOG_DEBUG);
2611 
2612  $result = $this->db->query($sql);
2613 
2614  if ($result) {
2615  if ($conf->global->EXPENSEREPORT_CALCULATE_MILEAGE_EXPENSE_COEFFICIENT_ON_CURRENT_YEAR) {
2616  $arrayDate = dol_getdate(dol_now());
2617  $sql = " SELECT count(n.qty) as cumul FROM ".MAIN_DB_PREFIX."expensereport_det n";
2618  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expensereport e ON e.rowid = n.fk_expensereport";
2619  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_type_fees tf ON tf.id = n.fk_c_type_fees";
2620  $sql.= " WHERE e.fk_user_author = ".(int) $this->fk_user_author;
2621  $sql.= " AND YEAR(n.date) = ".(int) $arrayDate['year'];
2622  $sql.= " AND tf.code = 'EX_KME' ";
2623  $sql.= " AND e.fk_statut = ".(int) ExpenseReport::STATUS_VALIDATED;
2624 
2625  $resql = $this->db->query($sql);
2626 
2627  if ($resql) {
2628  $obj = $this->db->fetch_object($resql);
2629  $cumulYearQty = $obj->cumul;
2630  }
2631  $qty = $cumulYearQty + $qty;
2632  }
2633 
2634  $num = $this->db->num_rows($result);
2635 
2636  if ($num) {
2637  for ($i = 0; $i < $num; $i++) {
2638  $obj = $this->db->fetch_object($result);
2639 
2640  $ranges[$i] = $obj;
2641  }
2642 
2643 
2644  for ($i = 0; $i < $num; $i++) {
2645  if ($i < ($num - 1)) {
2646  if ($qty > $ranges[$i]->range_ik && $qty < $ranges[$i+1]->range_ik) {
2647  $coef = $ranges[$i]->coef;
2648  $offset = $ranges[$i]->offset;
2649  }
2650  } else {
2651  if ($qty > $ranges[$i]->range_ik) {
2652  $coef = $ranges[$i]->coef;
2653  $offset = $ranges[$i]->offset;
2654  }
2655  }
2656  }
2657  $total_ht = $coef;
2658  return $total_ht;
2659  } else {
2660  $this->error = $langs->trans('TaxUndefinedForThisCategory');
2661  return 0;
2662  }
2663  } else {
2664  $this->error = $this->db->error()." sql=".$sql;
2665 
2666  return -1;
2667  }
2668  }
2669 }
2670 
2671 
2676 {
2680  public $db;
2681 
2685  public $error = '';
2686 
2690  public $rowid;
2691 
2692  public $comments;
2693  public $qty;
2694  public $value_unit;
2695  public $date;
2696 
2700  public $fk_c_type_fees;
2701 
2705  public $fk_c_exp_tax_cat;
2706 
2710  public $fk_projet;
2711 
2715  public $fk_expensereport;
2716 
2717  public $type_fees_code;
2718  public $type_fees_libelle;
2719  public $type_fees_accountancy_code;
2720 
2721  public $projet_ref;
2722  public $projet_title;
2723  public $rang;
2724 
2725  public $vatrate;
2726  public $vat_src_code;
2727  public $tva_tx;
2728  public $localtax1_tx;
2729  public $localtax2_tx;
2730  public $localtax1_type;
2731  public $localtax2_type;
2732 
2733  public $total_ht;
2734  public $total_tva;
2735  public $total_ttc;
2736  public $total_localtax1;
2737  public $total_localtax2;
2738 
2742  public $fk_ecm_files;
2743 
2744  public $rule_warning_message;
2745 
2746 
2752  public function __construct($db)
2753  {
2754  $this->db = $db;
2755  }
2756 
2763  public function fetch($rowid)
2764  {
2765  $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,';
2766  $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,';
2767  $sql .= ' fde.localtax1_tx, fde.localtax2_tx, fde.localtax1_type, fde.localtax2_type, fde.total_localtax1, fde.total_localtax2, fde.rule_warning_message,';
2768  $sql .= ' ctf.code as type_fees_code, ctf.label as type_fees_libelle,';
2769  $sql .= ' pjt.rowid as projet_id, pjt.title as projet_title, pjt.ref as projet_ref';
2770  $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det as fde';
2771  $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.
2772  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as pjt ON fde.fk_projet=pjt.rowid';
2773  $sql .= ' WHERE fde.rowid = '.((int) $rowid);
2774 
2775  $result = $this->db->query($sql);
2776 
2777  if ($result) {
2778  $objp = $this->db->fetch_object($result);
2779 
2780  $this->rowid = $objp->rowid;
2781  $this->id = $objp->rowid;
2782  $this->ref = $objp->ref;
2783  $this->fk_expensereport = $objp->fk_expensereport;
2784  $this->comments = $objp->comments;
2785  $this->qty = $objp->qty;
2786  $this->date = $objp->date;
2787  $this->dates = $this->db->jdate($objp->date);
2788  $this->value_unit = $objp->value_unit;
2789  $this->fk_c_type_fees = $objp->fk_c_type_fees;
2790  $this->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
2791  $this->fk_projet = $objp->fk_project; // deprecated
2792  $this->fk_project = $objp->fk_project;
2793  $this->type_fees_code = $objp->type_fees_code;
2794  $this->type_fees_libelle = $objp->type_fees_libelle;
2795  $this->projet_ref = $objp->projet_ref;
2796  $this->projet_title = $objp->projet_title;
2797 
2798  $this->vatrate = $objp->vatrate;
2799  $this->vat_src_code = $objp->vat_src_code;
2800  $this->localtax1_tx = $objp->localtax1_tx;
2801  $this->localtax2_tx = $objp->localtax2_tx;
2802  $this->localtax1_type = $objp->localtax1_type;
2803  $this->localtax2_type = $objp->localtax2_type;
2804 
2805  $this->total_ht = $objp->total_ht;
2806  $this->total_tva = $objp->total_tva;
2807  $this->total_ttc = $objp->total_ttc;
2808  $this->total_localtax1 = $objp->total_localtax1;
2809  $this->total_localtax2 = $objp->total_localtax2;
2810 
2811  $this->fk_ecm_files = $objp->fk_ecm_files;
2812 
2813  $this->rule_warning_message = $objp->rule_warning_message;
2814 
2815  $this->db->free($result);
2816  } else {
2817  dol_print_error($this->db);
2818  }
2819  }
2820 
2828  public function insert($notrigger = 0, $fromaddline = false)
2829  {
2830  global $langs, $user, $conf;
2831 
2832  $error = 0;
2833 
2834  dol_syslog("ExpenseReportLine::Insert", LOG_DEBUG);
2835 
2836  // Clean parameters
2837  $this->comments = trim($this->comments);
2838  if (empty($this->value_unit)) {
2839  $this->value_unit = 0;
2840  }
2841  $this->qty = price2num($this->qty);
2842  $this->vatrate = price2num($this->vatrate);
2843  if (empty($this->fk_c_exp_tax_cat)) {
2844  $this->fk_c_exp_tax_cat = 0;
2845  }
2846 
2847  $this->db->begin();
2848 
2849  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'expensereport_det';
2850  $sql .= ' (fk_expensereport, fk_c_type_fees, fk_projet,';
2851  $sql .= ' tva_tx, vat_src_code,';
2852  $sql .= ' localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
2853  $sql .= ' comments, qty, value_unit,';
2854  $sql .= ' total_ht, total_tva, total_ttc,';
2855  $sql .= ' total_localtax1, total_localtax2,';
2856  $sql .= ' date, rule_warning_message, fk_c_exp_tax_cat, fk_ecm_files)';
2857  $sql .= " VALUES (".$this->db->escape($this->fk_expensereport).",";
2858  $sql .= " ".((int) $this->fk_c_type_fees).",";
2859  $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')).",";
2860  $sql .= " ".((float) $this->vatrate).",";
2861  $sql .= " '".$this->db->escape(empty($this->vat_src_code) ? '' : $this->vat_src_code)."',";
2862  $sql .= " ".((float) price2num($this->localtax1_tx)).",";
2863  $sql .= " ".((float) price2num($this->localtax2_tx)).",";
2864  $sql .= " '".$this->db->escape($this->localtax1_type)."',";
2865  $sql .= " '".$this->db->escape($this->localtax2_type)."',";
2866  $sql .= " '".$this->db->escape($this->comments)."',";
2867  $sql .= " ".((float) $this->qty).",";
2868  $sql .= " ".((float) $this->value_unit).",";
2869  $sql .= " ".((float) price2num($this->total_ht)).",";
2870  $sql .= " ".((float) price2num($this->total_tva)).",";
2871  $sql .= " ".((float) price2num($this->total_ttc)).",";
2872  $sql .= " ".((float) price2num($this->total_localtax1)).",";
2873  $sql .= " ".((float) price2num($this->total_localtax2)).",";
2874  $sql .= " '".$this->db->idate($this->date)."',";
2875  $sql .= " ".(empty($this->rule_warning_message) ? 'null' : "'".$this->db->escape($this->rule_warning_message)."'").",";
2876  $sql .= " ".((int) $this->fk_c_exp_tax_cat).",";
2877  $sql .= " ".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
2878  $sql .= ")";
2879 
2880  $resql = $this->db->query($sql);
2881  if ($resql) {
2882  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'expensereport_det');
2883 
2884 
2885  if (!$error && !$notrigger) {
2886  // Call triggers
2887  $result = $this->call_trigger('EXPENSE_REPORT_DET_CREATE', $user);
2888  if ($result < 0) {
2889  $error++;
2890  }
2891  // End call triggers
2892  }
2893 
2894 
2895  if (!$fromaddline) {
2896  $tmpparent = new ExpenseReport($this->db);
2897  $tmpparent->fetch($this->fk_expensereport);
2898  $result = $tmpparent->update_price();
2899  if ($result < 0) {
2900  $error++;
2901  $this->error = $tmpparent->error;
2902  $this->errors = $tmpparent->errors;
2903  }
2904  }
2905  } else {
2906  $error++;
2907  }
2908 
2909  if (!$error) {
2910  $this->db->commit();
2911  return $this->id;
2912  } else {
2913  $this->error = $this->db->lasterror();
2914  dol_syslog("ExpenseReportLine::insert Error ".$this->error, LOG_ERR);
2915  $this->db->rollback();
2916  return -2;
2917  }
2918  }
2919 
2928  public function getExpAmount(ExpenseReportRule $rule, $fk_user, $mode = 'day')
2929  {
2930  $amount = 0;
2931 
2932  $sql = 'SELECT SUM(d.total_ttc) as total_amount';
2933  $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det d';
2934  $sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'expensereport e ON (d.fk_expensereport = e.rowid)';
2935  $sql .= ' WHERE e.fk_user_author = '.((int) $fk_user);
2936  if (!empty($this->id)) {
2937  $sql .= ' AND d.rowid <> '.((int) $this->id);
2938  }
2939  $sql .= ' AND d.fk_c_type_fees = '.((int) $rule->fk_c_type_fees);
2940  if ($mode == 'day' || $mode == 'EX_DAY') {
2941  $sql .= " AND d.date = '".dol_print_date($this->date, '%Y-%m-%d')."'";
2942  } elseif ($mode == 'mon' || $mode == 'EX_MON') {
2943  $sql .= " AND DATE_FORMAT(d.date, '%Y-%m') = '".dol_print_date($this->date, '%Y-%m')."'"; // @todo DATE_FORMAT is forbidden
2944  } elseif ($mode == 'year' || $mode == 'EX_YEA') {
2945  $sql .= " AND DATE_FORMAT(d.date, '%Y') = '".dol_print_date($this->date, '%Y')."'"; // @todo DATE_FORMAT is forbidden
2946  }
2947 
2948  dol_syslog('ExpenseReportLine::getExpAmount');
2949 
2950  $resql = $this->db->query($sql);
2951  if ($resql) {
2952  $num = $this->db->num_rows($resql);
2953  if ($num > 0) {
2954  $obj = $this->db->fetch_object($resql);
2955  $amount = (double) $obj->total_amount;
2956  }
2957  } else {
2958  dol_print_error($this->db);
2959  }
2960 
2961  return $amount + $this->total_ttc;
2962  }
2963 
2970  public function update(User $user)
2971  {
2972  global $langs, $conf;
2973 
2974  $error = 0;
2975 
2976  // Clean parameters
2977  $this->comments = trim($this->comments);
2978  $this->vatrate = price2num($this->vatrate);
2979  $this->value_unit = price2num($this->value_unit);
2980  if (empty($this->fk_c_exp_tax_cat)) {
2981  $this->fk_c_exp_tax_cat = 0;
2982  }
2983 
2984  $this->db->begin();
2985 
2986  // Update line in database
2987  $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport_det SET";
2988  $sql .= " comments='".$this->db->escape($this->comments)."'";
2989  $sql .= ", value_unit = ".((float) $this->value_unit);
2990  $sql .= ", qty=".((float) $this->qty);
2991  $sql .= ", date='".$this->db->idate($this->date)."'";
2992  $sql .= ", total_ht=".((float) price2num($this->total_ht, 'MT'));
2993  $sql .= ", total_tva=".((float) price2num($this->total_tva, 'MT'));
2994  $sql .= ", total_ttc=".((float) price2num($this->total_ttc, 'MT'));
2995  $sql .= ", total_localtax1=".((float) price2num($this->total_localtax1, 'MT'));
2996  $sql .= ", total_localtax2=".((float) price2num($this->total_localtax2, 'MT'));
2997  $sql .= ", tva_tx=".((float) $this->vatrate);
2998  $sql .= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
2999  $sql .= ", localtax1_tx=".((float) $this->localtax1_tx);
3000  $sql .= ", localtax2_tx=".((float) $this->localtax2_tx);
3001  $sql .= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
3002  $sql .= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
3003  $sql .= ", rule_warning_message='".$this->db->escape($this->rule_warning_message)."'";
3004  $sql .= ", fk_c_exp_tax_cat=".$this->db->escape($this->fk_c_exp_tax_cat);
3005  $sql .= ", fk_ecm_files=".($this->fk_ecm_files > 0 ? ((int) $this->fk_ecm_files) : 'null');
3006  if ($this->fk_c_type_fees) {
3007  $sql .= ", fk_c_type_fees = ".((int) $this->fk_c_type_fees);
3008  } else {
3009  $sql .= ", fk_c_type_fees=null";
3010  }
3011  if ($this->fk_project > 0) {
3012  $sql .= ", fk_projet=".((int) $this->fk_project);
3013  } else {
3014  $sql .= ", fk_projet=null";
3015  }
3016  $sql .= " WHERE rowid = ".((int) ($this->rowid ? $this->rowid : $this->id));
3017 
3018  dol_syslog("ExpenseReportLine::update");
3019 
3020  $resql = $this->db->query($sql);
3021  if ($resql) {
3022  $tmpparent = new ExpenseReport($this->db);
3023  $result = $tmpparent->fetch($this->fk_expensereport);
3024  if ($result > 0) {
3025  $result = $tmpparent->update_price();
3026  if ($result < 0) {
3027  $error++;
3028  $this->error = $tmpparent->error;
3029  $this->errors = $tmpparent->errors;
3030  }
3031  } else {
3032  $error++;
3033  $this->error = $tmpparent->error;
3034  $this->errors = $tmpparent->errors;
3035  }
3036  } else {
3037  $error++;
3038  dol_print_error($this->db);
3039  }
3040 
3041  if (!$error) {
3042  $this->db->commit();
3043  return 1;
3044  } else {
3045  $this->error = $this->db->lasterror();
3046  dol_syslog("ExpenseReportLine::update Error ".$this->error, LOG_ERR);
3047  $this->db->rollback();
3048  return -2;
3049  }
3050  }
3051 
3052  // ajouter ici comput_ ...
3053 }
createFromClone(User $user, $fk_user_author)
Load an object from its id and create a new one in database.
getNextNumRef()
Return next reference of expense report not already used.
const STATUS_APPROVED
Classified approved.
const STATUS_VALIDATED
Validated (need to be paid)
LibStatut($status, $mode=0)
Returns the label of a status.
info($id)
Load information on object.
Class of expense report details lines.
__construct($db)
Constructor.
$conf db
API class for accounts.
Definition: inc.php:41
getNomUrl($withpicto=0, $option= '', $max=0, $short=0, $moretitle= '', $notooltip=0, $save_lastsearch_value=-1)
Return clicable name (with picto eventually)
Class to manage inventories.
setUnpaid($fuser, $notrigger=0)
set_unpaid
dol_now($mode= 'auto')
Return date for now.
getVentilExportCompta()
Return if object was dispatched into bookkeeping.
deleteObjectLinked($sourceid=null, $sourcetype= '', $targetid=null, $targettype= '', $rowid= '', $f_user=null, $notrigger=0)
Delete all links between an object $this.
dol_delete_preview($object)
Delete all preview files linked to object instance.
Definition: files.lib.php:1434
Class to manage inventories.
delete_linked_contact($source= '', $code= '')
Delete all links between an object $this and all its contacts.
setPaid($id, $fuser, $notrigger=0)
Classify the expense report as paid.
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
Class to manage Dolibarr users.
Definition: user.class.php:44
const STATUS_CLOSED
Classified paid.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
setDeny($fuser, $details, $notrigger=0)
setDeny
const STATUS_CANCELED
Classified canceled.
fetch($rowid)
Fetch record for expense report detailed line.
fetch_lines()
fetch_lines
periode_existe($fuser, $date_debut, $date_fin)
periode_existe
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
deleteline($rowid, $fuser= '', $notrigger=0)
deleteline
const STATUS_REFUSED
Classified refused.
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...
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
set_unpaid($fuser, $notrigger=0)
set_unpaid
insertExtraFields($trigger= '', $userused=null)
Add/Update all extra fields values for the current object.
fetch_line_by_project($projectid, $user= '')
fetch_line_by_project
setValidate($fuser, $notrigger=0)
Set to status validate.
Class to manage third parties objects (customers, suppliers, prospects...)
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.
computeTotalKm($fk_cat, $qty, $tva)
Compute the cost of the kilometers expense based on the number of kilometers and the vehicule categor...
checkRules($type=0, $seller= '')
Check constraint of rules and update price if needed.
update(User $user)
Update line.
dol_strlen($string, $stringencoding= 'UTF-8')
Make a strlen call.
price2num($amount, $rounding= '', $option=0)
Function that return a number with universal decimal format (decimal separator is &#39;...
update_totaux_add($ligne_total_ht, $ligne_total_tva)
Update total of an expense report when you add a line.
load_board($user, $option= 'topay')
Load indicators for dashboard (this-&gt;nbtodo and this-&gt;nbtodolate)
fetch_users_approver_expensereport()
Return list of people with permission to validate expense reports.
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) ...
Definition: files.lib.php:1382
getSumPayments()
Return amount of payments already done.
deleteEcmFiles($mode=0)
Delete related files of object in database.
img_picto($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt= '', $morecss= '', $marginleftonlyshort=2)
Show picto whatever it&#39;s its name (generic function)
initAsSpecimen()
Initialise an instance with random values.
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.
set_paid($id, $fuser, $notrigger=0)
Classify the expense report as paid.
getExpAmount(ExpenseReportRule $rule, $fk_user, $mode= 'day')
Function to get total amount in expense reports for a same rule.
img_object($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
deleteExtraFields()
Delete all extra fields values for the current object.
dol_sanitizeFileName($str, $newstr= '_', $unaccent=1)
Clean a string to use it as a file name.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:60
Class to manage Trips and Expenses.
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this-&gt;array_options This method is in most cases call...
listOfTypes($active=1)
List of types.
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.
if(isModEnabled('facture')&&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur')&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)&&$user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice')&&$user->rights->supplier_invoice->lire)) if(isModEnabled('don')&&!empty($user->rights->don->lire)) if(isModEnabled('tax')&&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture')&&isModEnabled('commande')&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
setApproved($fuser, $notrigger=0)
Set status to approved.
hasDelay($option)
Return if an expense report is late or not.
load_state_board()
Charge indicateurs this-&gt;nb pour le tableau de bord.
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
call_trigger($triggerName, $user)
Call trigger based on this instance.
set_cancel($fuser, $detail, $notrigger=0)
set_cancel
create($user, $notrigger=0)
Create object in database.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk accordign to template module.
$object ref
Definition: info.php:77
insert($notrigger=0, $fromaddline=false)
Insert a line of expense report.
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
update($user, $notrigger=0, $userofexpensereport=null)
update
dol_trunc($string, $size=40, $trunc= 'right', $stringencoding= 'UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding &#39;…&#39; if string larger than length. ...
dolGetStatus($statusLabel= '', $statusLabelShort= '', $html= '', $statusType= 'status0', $displayMode=0, $url= '', $params=array())
Output the badge of a status.
offsetAlreadyGiven()
If the sql find any rows then the ikoffset is already given (ikoffset is applied at the first expense...
__construct($db)
Constructor.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
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)...
getLibStatut($mode=0)
Returns the label status.
const STATUS_DRAFT
Draft status.
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.
Definition: files.lib.php:1230
Parent class of all other business classes (invoices, contracts, proposals, orders, ...)
set_save_from_refuse($fuser)
set_save_from_refuse
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
applyOffset($type=0, $seller= '')
Method to apply the offset if needed.
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...
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid