dolibarr  9.0.0
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@zendsi.com>
5  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
6  * Copyright (c) 2018 Frédéric France <frederic.france@netlogic.fr>
7  * Copyright (C) 2016-2018 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 <http://www.gnu.org/licenses/>.
21  */
22 
28 require_once DOL_DOCUMENT_ROOT .'/core/class/commonobject.class.php';
29 require_once DOL_DOCUMENT_ROOT .'/expensereport/class/expensereport_ik.class.php';
30 require_once DOL_DOCUMENT_ROOT .'/expensereport/class/expensereport_rule.class.php';
31 
36 {
40  public $element='expensereport';
41 
45  public $table_element='expensereport';
46 
47  var $table_element_line = 'expensereport_det';
48  var $fk_element = 'fk_expensereport';
49  var $picto = 'trip';
50 
51  var $lines=array();
52 
53  public $date_debut;
54 
55  public $date_fin;
56 
57  var $status;
58  var $fk_statut; // -- 0=draft, 2=validated (attente approb), 4=canceled, 5=approved, 6=payed, 99=denied
59  var $fk_c_paiement;
60  var $paid;
61 
62  var $user_author_infos;
63  var $user_validator_infos;
64 
65  var $fk_typepayment;
66  var $num_payment;
67  var $code_paiement;
68  var $code_statut;
69 
70  // ACTIONS
71 
72  // Create
73  var $date_create;
74  var $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
75 
76  // Update
77  var $date_modif;
78  var $fk_user_modif;
79 
80  // Refus
81  var $date_refuse;
82  var $detail_refuse;
83  var $fk_user_refuse;
84 
85  // Annulation
86  var $date_cancel;
87  var $detail_cancel;
88  var $fk_user_cancel;
89 
90  var $fk_user_validator; // User that is defined to approve
91 
92  // Validation
93  var $date_valid; // User making validation
94  var $fk_user_valid;
95  var $user_valid_infos;
96 
97  // Approve
98  var $date_approve;
99  var $fk_user_approve; // User that has approved
100 
101  // Paiement
102  var $user_paid_infos;
103 
104  /*
105  END ACTIONS
106  */
107 
111  const STATUS_DRAFT = 0;
112 
116  const STATUS_VALIDATED = 2;
117 
121  const STATUS_APPROVED = 5;
122 
126  const STATUS_REFUSED = 99;
127 
131  const STATUS_CLOSED = 6;
132 
133 
134 
140  function __construct($db)
141  {
142  $this->db = $db;
143  $this->total_ht = 0;
144  $this->total_ttc = 0;
145  $this->total_tva = 0;
146  $this->modepaymentid = 0;
147 
148  // List of language codes for status
149  $this->statuts_short = array(0 => 'Draft', 2 => 'Validated', 4 => 'Canceled', 5 => 'Approved', 6 => 'Paid', 99 => 'Refused');
150  $this->statuts = array(0 => 'Draft', 2 => 'ValidatedWaitingApproval', 4 => 'Canceled', 5 => 'Approved', 6 => 'Paid', 99 => 'Refused');
151  $this->statuts_logo = array(0 => 'statut0', 2 => 'statut1', 4 => 'statut5', 5 => 'statut3', 6 => 'statut6', 99 => 'statut5');
152  }
153 
161  function create($user, $notrigger=0)
162  {
163  global $conf;
164 
165  $now = dol_now();
166 
167  $error = 0;
168 
169  // Check parameters
170  if (empty($this->date_debut) || empty($this->date_fin))
171  {
172  $this->error='ErrorFieldRequired';
173  return -1;
174  }
175 
176  $fuserid = $this->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
177  if (empty($fuserid)) $fuserid = $user->id;
178 
179  $this->db->begin();
180 
181  $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
182  $sql.= "ref";
183  $sql.= ",total_ht";
184  $sql.= ",total_ttc";
185  $sql.= ",total_tva";
186  $sql.= ",date_debut";
187  $sql.= ",date_fin";
188  $sql.= ",date_create";
189  $sql.= ",fk_user_author";
190  $sql.= ",fk_user_validator";
191  $sql.= ",fk_user_approve";
192  $sql.= ",fk_user_modif";
193  $sql.= ",fk_statut";
194  $sql.= ",fk_c_paiement";
195  $sql.= ",paid";
196  $sql.= ",note_public";
197  $sql.= ",note_private";
198  $sql.= ",entity";
199  $sql.= ") VALUES(";
200  $sql.= "'(PROV)'";
201  $sql.= ", ".$this->total_ht;
202  $sql.= ", ".$this->total_ttc;
203  $sql.= ", ".$this->total_tva;
204  $sql.= ", '".$this->db->idate($this->date_debut)."'";
205  $sql.= ", '".$this->db->idate($this->date_fin)."'";
206  $sql.= ", '".$this->db->idate($now)."'";
207  $sql.= ", ".$fuserid;
208  $sql.= ", ".($this->fk_user_validator > 0 ? $this->fk_user_validator:"null");
209  $sql.= ", ".($this->fk_user_approve > 0 ? $this->fk_user_approve:"null");
210  $sql.= ", ".($this->fk_user_modif > 0 ? $this->fk_user_modif:"null");
211  $sql.= ", ".($this->fk_statut > 1 ? $this->fk_statut:0);
212  $sql.= ", ".($this->modepaymentid?$this->modepaymentid:"null");
213  $sql.= ", 0";
214  $sql.= ", ".($this->note_public?"'".$this->db->escape($this->note_public)."'":"null");
215  $sql.= ", ".($this->note_private?"'".$this->db->escape($this->note_private)."'":"null");
216  $sql.= ", ".$conf->entity;
217  $sql.= ")";
218 
219  $result = $this->db->query($sql);
220  if ($result)
221  {
222  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
223  $this->ref='(PROV'.$this->id.')';
224 
225  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".$this->id;
226  $resql=$this->db->query($sql);
227  if (!$resql) $error++;
228 
229  if (is_array($this->lines) && count($this->lines)>0)
230  {
231  foreach ($this->lines as $i => $val)
232  {
233  $newndfline=new ExpenseReportLine($this->db);
234  $newndfline=$this->lines[$i];
235  $newndfline->fk_expensereport=$this->id;
236  if ($result >= 0)
237  {
238  $result=$newndfline->insert();
239  }
240  if ($result < 0)
241  {
242  $error++;
243  break;
244  }
245  }
246  }
247 
248  if (! $error)
249  {
250  $result=$this->insertExtraFields();
251  if ($result < 0) $error++;
252  }
253 
254  if (! $error)
255  {
256  $result=$this->update_price();
257  if ($result > 0)
258  {
259 
260  if (!$notrigger)
261  {
262  // Call trigger
263  $result=$this->call_trigger('EXPENSE_REPORT_CREATE',$user);
264 
265  if ($result < 0) {
266  $error++;
267  }
268  // End call triggers
269  }
270 
271  if (empty($error))
272  {
273  $this->db->commit();
274  return $this->id;
275  }
276  else
277  {
278  $this->db->rollback();
279  return -4;
280  }
281  }
282  else
283  {
284  $this->db->rollback();
285  return -3;
286  }
287  }
288  else
289  {
290  dol_syslog(get_class($this)."::create error ".$this->error, LOG_ERR);
291  $this->db->rollback();
292  return -2;
293  }
294  }
295  else
296  {
297  $this->error=$this->db->lasterror()." sql=".$sql;
298  $this->db->rollback();
299  return -1;
300  }
301  }
302 
303 
310  function createFromClone($fk_user_author)
311  {
312  global $user,$hookmanager;
313 
314  $error=0;
315 
316  if (empty($fk_user_author)) $fk_user_author = $user->id;
317 
318  $this->db->begin();
319 
320  // get extrafields so they will be clone
321  //foreach($this->lines as $line)
322  //$line->fetch_optionals($line->rowid);
323 
324  // Load source object
325  $objFrom = clone $this;
326 
327  $this->id=0;
328  $this->ref = '';
329  $this->status=0;
330  $this->fk_statut=0;
331 
332  // Clear fields
333  $this->fk_user_author = $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
334  $this->fk_user_valid = '';
335  $this->date_create = '';
336  $this->date_creation = '';
337  $this->date_validation = '';
338 
339  // Create clone
340  $this->context['createfromclone'] = 'createfromclone';
341  $result=$this->create($user);
342  if ($result < 0) $error++;
343 
344  if (! $error)
345  {
346  // Hook of thirdparty module
347  if (is_object($hookmanager))
348  {
349  $parameters=array('objFrom'=>$objFrom);
350  $action='';
351  $reshook=$hookmanager->executeHooks('createFrom',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks
352  if ($reshook < 0) $error++;
353  }
354  }
355 
356  unset($this->context['createfromclone']);
357 
358  // End
359  if (! $error)
360  {
361  $this->db->commit();
362  return $this->id;
363  }
364  else
365  {
366  $this->db->rollback();
367  return -1;
368  }
369  }
370 
371 
380  function update($user, $notrigger = 0, $userofexpensereport=null)
381  {
382  global $langs;
383 
384  $error = 0;
385  $this->db->begin();
386 
387  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
388  $sql.= " total_ht = ".$this->total_ht;
389  $sql.= " , total_ttc = ".$this->total_ttc;
390  $sql.= " , total_tva = ".$this->total_tva;
391  $sql.= " , date_debut = '".$this->db->idate($this->date_debut)."'";
392  $sql.= " , date_fin = '".$this->db->idate($this->date_fin)."'";
393  if ($userofexpensereport && is_object($userofexpensereport))
394  {
395  $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.
396  }
397  $sql.= " , fk_user_validator = ".($this->fk_user_validator > 0 ? $this->fk_user_validator:"null");
398  $sql.= " , fk_user_valid = ".($this->fk_user_valid > 0 ? $this->fk_user_valid:"null");
399  $sql.= " , fk_user_approve = ".($this->fk_user_approve > 0 ? $this->fk_user_approve:"null");
400  $sql.= " , fk_user_modif = ".$user->id;
401  $sql.= " , fk_statut = ".($this->fk_statut >= 0 ? $this->fk_statut:'0');
402  $sql.= " , fk_c_paiement = ".($this->fk_c_paiement > 0 ? $this->fk_c_paiement:"null");
403  $sql.= " , note_public = ".(!empty($this->note_public)?"'".$this->db->escape($this->note_public)."'":"''");
404  $sql.= " , note_private = ".(!empty($this->note_private)?"'".$this->db->escape($this->note_private)."'":"''");
405  $sql.= " , detail_refuse = ".(!empty($this->detail_refuse)?"'".$this->db->escape($this->detail_refuse)."'":"''");
406  $sql.= " WHERE rowid = ".$this->id;
407 
408  dol_syslog(get_class($this)."::update sql=".$sql, LOG_DEBUG);
409  $result = $this->db->query($sql);
410  if ($result)
411  {
412  if (!$notrigger)
413  {
414  // Call trigger
415  $result=$this->call_trigger('EXPENSE_REPORT_UPDATE',$user);
416 
417  if ($result < 0) {
418  $error++;
419  }
420  // End call triggers
421  }
422 
423  if (empty($error))
424  {
425  $this->db->commit();
426  return 1;
427  }
428  else
429  {
430  $this->db->rollback();
431  $this->error=$this->db->error();
432  return -2;
433  }
434  }
435  else
436  {
437  $this->db->rollback();
438  $this->error=$this->db->error();
439  return -1;
440  }
441  }
442 
450  function fetch($id, $ref='')
451  {
452  global $conf;
453 
454  $sql = "SELECT d.rowid, d.ref, d.note_public, d.note_private,"; // DEFAULT
455  $sql.= " d.detail_refuse, d.detail_cancel, d.fk_user_refuse, d.fk_user_cancel,"; // ACTIONS
456  $sql.= " d.date_refuse, d.date_cancel,"; // ACTIONS
457  $sql.= " d.total_ht, d.total_ttc, d.total_tva,"; // TOTAUX (int)
458  $sql.= " d.date_debut, d.date_fin, d.date_create, d.tms as date_modif, d.date_valid, d.date_approve,"; // DATES (datetime)
459  $sql.= " d.fk_user_author, d.fk_user_modif, d.fk_user_validator,";
460  $sql.= " d.fk_user_valid, d.fk_user_approve,";
461  $sql.= " d.fk_statut as status, d.fk_c_paiement, d.paid,";
462  $sql.= " dp.libelle as libelle_paiement, dp.code as code_paiement"; // INNER JOIN paiement
463  $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as d";
464  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as dp ON d.fk_c_paiement = dp.id";
465  if ($ref) $sql.= " WHERE d.ref = '".$this->db->escape($ref)."'";
466  else $sql.= " WHERE d.rowid = ".$id;
467  //$sql.= $restrict;
468 
469  dol_syslog(get_class($this)."::fetch sql=".$sql, LOG_DEBUG);
470  $resql = $this->db->query($sql) ;
471  if ($resql)
472  {
473  $obj = $this->db->fetch_object($resql);
474  if ($obj)
475  {
476  $this->id = $obj->rowid;
477  $this->ref = $obj->ref;
478  $this->total_ht = $obj->total_ht;
479  $this->total_tva = $obj->total_tva;
480  $this->total_ttc = $obj->total_ttc;
481  $this->note_public = $obj->note_public;
482  $this->note_private = $obj->note_private;
483  $this->detail_refuse = $obj->detail_refuse;
484  $this->detail_cancel = $obj->detail_cancel;
485 
486  $this->date_debut = $this->db->jdate($obj->date_debut);
487  $this->date_fin = $this->db->jdate($obj->date_fin);
488  $this->date_valid = $this->db->jdate($obj->date_valid);
489  $this->date_approve = $this->db->jdate($obj->date_approve);
490  $this->date_create = $this->db->jdate($obj->date_create);
491  $this->date_modif = $this->db->jdate($obj->date_modif);
492  $this->date_refuse = $this->db->jdate($obj->date_refuse);
493  $this->date_cancel = $this->db->jdate($obj->date_cancel);
494 
495  $this->fk_user_author = $obj->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
496  $this->fk_user_modif = $obj->fk_user_modif;
497  $this->fk_user_validator = $obj->fk_user_validator;
498  $this->fk_user_valid = $obj->fk_user_valid;
499  $this->fk_user_refuse = $obj->fk_user_refuse;
500  $this->fk_user_cancel = $obj->fk_user_cancel;
501  $this->fk_user_approve = $obj->fk_user_approve;
502 
503  $user_author = new User($this->db);
504  if ($this->fk_user_author > 0) $user_author->fetch($this->fk_user_author);
505 
506  $this->user_author_infos = dolGetFirstLastname($user_author->firstname, $user_author->lastname);
507 
508  $user_approver = new User($this->db);
509  if ($this->fk_user_approve > 0) $user_approver->fetch($this->fk_user_approve);
510  elseif ($this->fk_user_validator > 0) $user_approver->fetch($this->fk_user_validator); // For backward compatibility
511  $this->user_validator_infos = dolGetFirstLastname($user_approver->firstname, $user_approver->lastname);
512 
513  $this->fk_statut = $obj->status;
514  $this->status = $obj->status;
515  $this->fk_c_paiement = $obj->fk_c_paiement;
516  $this->paid = $obj->paid;
517 
518  if ($this->fk_statut==5 || $this->fk_statut==6)
519  {
520  $user_valid = new User($this->db);
521  if ($this->fk_user_valid > 0) $user_valid->fetch($this->fk_user_valid);
522  $this->user_valid_infos = dolGetFirstLastname($user_valid->firstname, $user_valid->lastname);
523  }
524 
525  $this->libelle_statut = $obj->libelle_statut;
526  $this->libelle_paiement = $obj->libelle_paiement;
527  $this->code_statut = $obj->code_statut;
528  $this->code_paiement = $obj->code_paiement;
529 
530  $this->lines = array();
531 
532  $result=$this->fetch_lines();
533 
534  return $result;
535  }
536  else
537  {
538  return 0;
539  }
540  }
541  else
542  {
543  $this->error=$this->db->lasterror();
544  return -1;
545  }
546  }
547 
548  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
557  function set_paid($id, $fuser, $notrigger = 0)
558  {
559  // phpcs:enable
560  $error = 0;
561  $this->db->begin();
562 
563  $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport";
564  $sql.= " SET fk_statut = 6, paid=1";
565  $sql.= " WHERE rowid = ".$id." AND fk_statut = 5";
566 
567  dol_syslog(get_class($this)."::set_paid sql=".$sql, LOG_DEBUG);
568  $resql=$this->db->query($sql);
569  if ($resql)
570  {
571  if ($this->db->affected_rows($resql))
572  {
573  if (!$notrigger)
574  {
575  // Call trigger
576  $result=$this->call_trigger('EXPENSE_REPORT_PAID',$fuser);
577 
578  if ($result < 0) {
579  $error++;
580  }
581  // End call triggers
582  }
583 
584  if (empty($error))
585  {
586  $this->db->commit();
587  return 1;
588  }
589  else
590  {
591  $this->db->rollback();
592  $this->error=$this->db->error();
593  return -2;
594  }
595  }
596  else
597  {
598  $this->db->commit();
599  return 0;
600  }
601  }
602  else
603  {
604  $this->db->rollback();
605  dol_print_error($this->db);
606  return -1;
607  }
608  }
609 
616  function getLibStatut($mode=0)
617  {
618  return $this->LibStatut($this->status,$mode);
619  }
620 
621  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
629  function LibStatut($status,$mode=0)
630  {
631  // phpcs:enable
632  global $langs;
633 
634  if ($mode == 0)
635  return $langs->transnoentities($this->statuts[$status]);
636 
637  elseif ($mode == 1)
638  return $langs->transnoentities($this->statuts_short[$status]);
639 
640  elseif ($mode == 2)
641  return img_picto($langs->transnoentities($this->statuts_short[$status]), $this->statuts_logo[$status]).' '.$langs->transnoentities($this->statuts_short[$status]);
642 
643  elseif ($mode == 3)
644  return img_picto($langs->transnoentities($this->statuts_short[$status]), $this->statuts_logo[$status]);
645 
646  elseif ($mode == 4)
647  return img_picto($langs->transnoentities($this->statuts_short[$status]),$this->statuts_logo[$status]).' '.$langs->transnoentities($this->statuts[$status]);
648 
649  elseif ($mode == 5)
650  return '<span class="hideonsmartphone">'.$langs->transnoentities($this->statuts_short[$status]).' </span>'.img_picto($langs->transnoentities($this->statuts_short[$status]),$this->statuts_logo[$status]);
651 
652  elseif ($mode == 6)
653  return $langs->transnoentities($this->statuts[$status]).' '.img_picto($langs->transnoentities($this->statuts_short[$status]),$this->statuts_logo[$status]);
654  }
655 
656 
663  function info($id)
664  {
665  global $conf;
666 
667  $sql = "SELECT f.rowid,";
668  $sql.= " f.date_create as datec,";
669  $sql.= " f.tms as date_modification,";
670  $sql.= " f.date_valid as datev,";
671  $sql.= " f.date_approve as datea,";
672  //$sql.= " f.fk_user_author as fk_user_creation,"; // This is not user of creation but user the expense is for.
673  $sql.= " f.fk_user_modif as fk_user_modification,";
674  $sql.= " f.fk_user_valid,";
675  $sql.= " f.fk_user_approve";
676  $sql.= " FROM ".MAIN_DB_PREFIX."expensereport as f";
677  $sql.= " WHERE f.rowid = ".$id;
678  $sql.= " AND f.entity = ".$conf->entity;
679 
680  $resql = $this->db->query($sql);
681  if ($resql)
682  {
683  if ($this->db->num_rows($resql))
684  {
685  $obj = $this->db->fetch_object($resql);
686 
687  $this->id = $obj->rowid;
688 
689  $this->date_creation = $this->db->jdate($obj->datec);
690  $this->date_modification = $this->db->jdate($obj->date_modification);
691  $this->date_validation = $this->db->jdate($obj->datev);
692  $this->date_approbation = $this->db->jdate($obj->datea);
693 
694  $cuser = new User($this->db);
695  $cuser->fetch($obj->fk_user_author);
696  $this->user_creation = $cuser;
697 
698  if ($obj->fk_user_creation)
699  {
700  $cuser = new User($this->db);
701  $cuser->fetch($obj->fk_user_creation);
702  $this->user_creation = $cuser;
703  }
704  if ($obj->fk_user_valid)
705  {
706  $vuser = new User($this->db);
707  $vuser->fetch($obj->fk_user_valid);
708  $this->user_validation = $vuser;
709  }
710  if ($obj->fk_user_modification)
711  {
712  $muser = new User($this->db);
713  $muser->fetch($obj->fk_user_modification);
714  $this->user_modification = $muser;
715  }
716  if ($obj->fk_user_approve)
717  {
718  $auser = new User($this->db);
719  $auser->fetch($obj->fk_user_approve);
720  $this->user_approve = $auser;
721  }
722  }
723  $this->db->free($resql);
724  }
725  else
726  {
727  dol_print_error($this->db);
728  }
729  }
730 
731 
732 
740  function initAsSpecimen()
741  {
742  global $user,$langs,$conf;
743 
744  $now=dol_now();
745 
746  // Initialise parametres
747  $this->id=0;
748  $this->ref = 'SPECIMEN';
749  $this->specimen=1;
750  $this->date_create = $now;
751  $this->date_debut = $now;
752  $this->date_fin = $now;
753  $this->date_valid = $now;
754  $this->date_approve = $now;
755 
756  $type_fees_id = 2; // TF_TRIP
757 
758  $this->status = 5;
759  $this->fk_statut = 5;
760 
761  $this->fk_user_author = $user->id;
762  $this->fk_user_validator = $user->id;
763  $this->fk_user_valid = $user->id;
764  $this->fk_user_approve = $user->id;
765 
766  $this->note_private='Private note';
767  $this->note_public='SPECIMEN';
768  $nbp = 5;
769  $xnbp = 0;
770  while ($xnbp < $nbp)
771  {
772  $line=new ExpenseReportLine($this->db);
773  $line->comments=$langs->trans("Comment")." ".$xnbp;
774  $line->date=($now-3600*(1+$xnbp));
775  $line->total_ht=100;
776  $line->total_tva=20;
777  $line->total_ttc=120;
778  $line->qty=1;
779  $line->vatrate=20;
780  $line->value_unit=120;
781  $line->fk_expensereport=0;
782  $line->type_fees_code='TRA';
783  $line->fk_c_type_fees=$type_fees_id;
784 
785  $line->projet_ref = 'ABC';
786 
787  $this->lines[$xnbp]=$line;
788  $xnbp++;
789 
790  $this->total_ht+=$line->total_ht;
791  $this->total_tva+=$line->total_tva;
792  $this->total_ttc+=$line->total_ttc;
793  }
794  }
795 
796  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
804  function fetch_line_by_project($projectid,$user='')
805  {
806  // phpcs:enable
807  global $conf,$db,$langs;
808 
809  $langs->load('trips');
810 
811  if ($user->rights->expensereport->lire) {
812 
813  $sql = "SELECT de.fk_expensereport, de.date, de.comments, de.total_ht, de.total_ttc";
814  $sql.= " FROM ".MAIN_DB_PREFIX."expensereport_det as de";
815  $sql.= " WHERE de.fk_projet = ".$projectid;
816 
817  dol_syslog(get_class($this)."::fetch sql=".$sql, LOG_DEBUG);
818  $result = $db->query($sql) ;
819  if ($result)
820  {
821  $num = $db->num_rows($result);
822  $i = 0;
823  $total_HT = 0;
824  $total_TTC = 0;
825 
826  while ($i < $num)
827  {
828 
829  $objp = $db->fetch_object($result);
830 
831  $sql2 = "SELECT d.rowid, d.fk_user_author, d.ref, d.fk_statut";
832  $sql2.= " FROM ".MAIN_DB_PREFIX."expensereport as d";
833  $sql2.= " WHERE d.rowid = '".$objp->fk_expensereport."'";
834 
835  $result2 = $db->query($sql2);
836  $obj = $db->fetch_object($result2);
837 
838  $objp->fk_user_author = $obj->fk_user_author;
839  $objp->ref = $obj->ref;
840  $objp->fk_c_expensereport_status = $obj->fk_statut;
841  $objp->rowid = $obj->rowid;
842 
843  $total_HT = $total_HT + $objp->total_ht;
844  $total_TTC = $total_TTC + $objp->total_ttc;
845  $author = new User($db);
846  $author->fetch($objp->fk_user_author);
847 
848  print '<tr>';
849  print '<td><a href="'.DOL_URL_ROOT.'/expensereport/card.php?id='.$objp->rowid.'">'.$objp->ref_num.'</a></td>';
850  print '<td align="center">'.dol_print_date($objp->date,'day').'</td>';
851  print '<td>'.$author->getNomUrl(1).'</td>';
852  print '<td>'.$objp->comments.'</td>';
853  print '<td align="right">'.price($objp->total_ht).'</td>';
854  print '<td align="right">'.price($objp->total_ttc).'</td>';
855  print '<td align="right">';
856 
857  switch($objp->fk_c_expensereport_status) {
858  case 4:
859  print img_picto($langs->trans('StatusOrderCanceled'),'statut5');
860  break;
861  case 1:
862  print $langs->trans('Draft').' '.img_picto($langs->trans('Draft'),'statut0');
863  break;
864  case 2:
865  print $langs->trans('TripForValid').' '.img_picto($langs->trans('TripForValid'),'statut3');
866  break;
867  case 5:
868  print $langs->trans('TripForPaid').' '.img_picto($langs->trans('TripForPaid'),'statut3');
869  break;
870  case 6:
871  print $langs->trans('TripPaid').' '.img_picto($langs->trans('TripPaid'),'statut4');
872  break;
873  }
874  /*
875  if ($status==4) return img_picto($langs->trans('StatusOrderCanceled'),'statut5');
876  if ($status==1) return img_picto($langs->trans('StatusOrderDraft'),'statut0');
877  if ($status==2) return img_picto($langs->trans('StatusOrderValidated'),'statut1');
878  if ($status==2) return img_picto($langs->trans('StatusOrderOnProcess'),'statut3');
879  if ($status==5) return img_picto($langs->trans('StatusOrderToBill'),'statut4');
880  if ($status==6) return img_picto($langs->trans('StatusOrderOnProcess'),'statut6');
881  */
882  print '</td>';
883  print '</tr>';
884 
885  $i++;
886  }
887 
888  print '<tr class="liste_total"><td colspan="4">'.$langs->trans("Number").': '.$i.'</td>';
889  print '<td align="right" width="100">'.$langs->trans("TotalHT").' : '.price($total_HT).'</td>';
890  print '<td align="right" width="100">'.$langs->trans("TotalTTC").' : '.price($total_TTC).'</td>';
891  print '<td>&nbsp;</td>';
892  print '</tr>';
893  }
894  else
895  {
896  $this->error=$db->lasterror();
897  return -1;
898  }
899  }
900  }
901 
909  function recalculer($id)
910  {
911  $sql = 'SELECT tt.total_ht, tt.total_ttc, tt.total_tva';
912  $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as tt';
913  $sql.= ' WHERE tt.'.$this->fk_element.' = '.$id;
914 
915  $total_ht = 0; $total_tva = 0; $total_ttc = 0;
916 
917  $result = $this->db->query($sql);
918  if($result)
919  {
920  $num = $this->db->num_rows($result);
921  $i = 0;
922  while ($i < $num):
923  $objp = $this->db->fetch_object($result);
924  $total_ht+=$objp->total_ht;
925  $total_tva+=$objp->total_tva;
926  $i++;
927  endwhile;
928 
929  $total_ttc = $total_ht + $total_tva;
930  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
931  $sql.= " total_ht = ".$total_ht;
932  $sql.= " , total_ttc = ".$total_ttc;
933  $sql.= " , total_tva = ".$total_tva;
934  $sql.= " WHERE rowid = ".$id;
935  $result = $this->db->query($sql);
936  if($result):
937  $this->db->free($result);
938  return 1;
939  else:
940  $this->error=$this->db->lasterror();
941  dol_syslog(get_class($this)."::recalculer: Error ".$this->error,LOG_ERR);
942  return -3;
943  endif;
944  }
945  else
946  {
947  $this->error=$this->db->lasterror();
948  dol_syslog(get_class($this)."::recalculer: Error ".$this->error,LOG_ERR);
949  return -3;
950  }
951  }
952 
953  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
959  function fetch_lines()
960  {
961  // phpcs:enable
962  $this->lines=array();
963 
964  $sql = ' SELECT de.rowid, de.comments, de.qty, de.value_unit, de.date, de.rang,';
965  $sql.= ' de.'.$this->fk_element.', de.fk_c_type_fees, de.fk_c_exp_tax_cat, de.fk_projet, de.tva_tx,';
966  $sql.= ' de.total_ht, de.total_tva, de.total_ttc,';
967  $sql.= ' ctf.code as code_type_fees, ctf.label as libelle_type_fees,';
968  $sql.= ' p.ref as ref_projet, p.title as title_projet';
969  $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as de';
970  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_type_fees as ctf ON de.fk_c_type_fees = ctf.id';
971  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as p ON de.fk_projet = p.rowid';
972  $sql.= ' WHERE de.'.$this->fk_element.' = '.$this->id;
973  if (! empty($conf->global->EXPENSEREPORT_LINES_SORTED_BY_ROWID))
974  {
975  $sql.= ' ORDER BY de.rang ASC, de.rowid ASC';
976  }
977  else
978  {
979  $sql.= ' ORDER BY de.rang ASC, de.date ASC';
980  }
981 
982  $resql = $this->db->query($sql);
983  if ($resql)
984  {
985  $num = $this->db->num_rows($resql);
986  $i = 0;
987  while ($i < $num)
988  {
989  $objp = $this->db->fetch_object($resql);
990 
991  $deplig = new ExpenseReportLine($this->db);
992 
993  $deplig->rowid = $objp->rowid;
994  $deplig->id = $objp->id;
995  $deplig->comments = $objp->comments;
996  $deplig->qty = $objp->qty;
997  $deplig->value_unit = $objp->value_unit;
998  $deplig->date = $objp->date;
999  $deplig->dates = $this->db->jdate($objp->date);
1000 
1001  $deplig->fk_expensereport = $objp->fk_expensereport;
1002  $deplig->fk_c_type_fees = $objp->fk_c_type_fees;
1003  $deplig->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
1004  $deplig->fk_projet = $objp->fk_projet;
1005 
1006  $deplig->total_ht = $objp->total_ht;
1007  $deplig->total_tva = $objp->total_tva;
1008  $deplig->total_ttc = $objp->total_ttc;
1009 
1010  $deplig->type_fees_code = empty($objp->code_type_fees)?'TF_OTHER':$objp->code_type_fees;
1011  $deplig->type_fees_libelle = $objp->libelle_type_fees;
1012  $deplig->tva_tx = $objp->tva_tx;
1013  $deplig->vatrate = $objp->tva_tx;
1014  $deplig->projet_ref = $objp->ref_projet;
1015  $deplig->projet_title = $objp->title_projet;
1016 
1017  $deplig->rang = $objp->rang;
1018 
1019  $this->lines[$i] = $deplig;
1020 
1021  $i++;
1022  }
1023  $this->db->free($resql);
1024  return 1;
1025  }
1026  else
1027  {
1028  $this->error=$this->db->lasterror();
1029  dol_syslog(get_class($this)."::fetch_lines: Error ".$this->error, LOG_ERR);
1030  return -3;
1031  }
1032  }
1033 
1034 
1041  function delete(User $fuser=null)
1042  {
1043  global $user,$langs,$conf;
1044 
1045  if (! $rowid) $rowid=$this->id;
1046 
1047  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element_line.' WHERE '.$this->fk_element.' = '.$rowid;
1048  if ($this->db->query($sql))
1049  {
1050  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid = '.$rowid;
1051  $resql=$this->db->query($sql);
1052  if ($resql)
1053  {
1054  $this->db->commit();
1055  return 1;
1056  }
1057  else
1058  {
1059  $this->error=$this->db->error()." sql=".$sql;
1060  dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR);
1061  $this->db->rollback();
1062  return -6;
1063  }
1064  }
1065  else
1066  {
1067  $this->error=$this->db->error()." sql=".$sql;
1068  dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR);
1069  $this->db->rollback();
1070  return -4;
1071  }
1072  }
1073 
1081  function setValidate($fuser, $notrigger=0)
1082  {
1083  global $conf,$langs,$user;
1084 
1085  $error = 0;
1086  $now = dol_now();
1087 
1088  // Protection
1089  if ($this->statut == self::STATUS_VALIDATED)
1090  {
1091  dol_syslog(get_class($this)."::valid action abandonned: already validated", LOG_WARNING);
1092  return 0;
1093  }
1094 
1095  $this->date_valid = $now; // Required for the getNextNum later.
1096 
1097  // Define new ref
1098  if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life
1099  {
1100  $num = $this->getNextNumRef();
1101  }
1102  else
1103  {
1104  $num = $this->ref;
1105  }
1106  if (empty($num) || $num < 0) return -1;
1107 
1108  $this->newref = $num;
1109 
1110  $this->db->begin();
1111 
1112  // Validate
1113  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1114  $sql.= " SET ref = '".$num."',";
1115  $sql.= " fk_statut = ".self::STATUS_VALIDATED.",";
1116  $sql.= " date_valid='".$this->db->idate($this->date_valid)."',";
1117  $sql.= " fk_user_valid = ".$user->id;
1118  $sql.= " WHERE rowid = ".$this->id;
1119 
1120  $resql=$this->db->query($sql);
1121  if ($resql)
1122  {
1123  if (!$notrigger)
1124  {
1125  // Call trigger
1126  $result=$this->call_trigger('EXPENSE_REPORT_VALIDATE',$fuser);
1127 
1128  if ($result < 0) {
1129  $error++;
1130  }
1131  // End call triggers
1132  }
1133 
1134  if (! $error)
1135  {
1136  $this->oldref = $this->ref;
1137 
1138  // Rename directory if dir was a temporary ref
1139  if (preg_match('/^[\(]?PROV/i', $this->ref))
1140  {
1141  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1142 
1143  // On renomme repertoire ($this->ref = ancienne ref, $num = nouvelle ref)
1144  // in order not to lose the attachments
1145  $oldref = dol_sanitizeFileName($this->ref);
1146  $newref = dol_sanitizeFileName($num);
1147  $dirsource = $conf->expensereport->dir_output.'/'.$oldref;
1148  $dirdest = $conf->expensereport->dir_output.'/'.$newref;
1149  if (file_exists($dirsource))
1150  {
1151  dol_syslog(get_class($this)."::valid() rename dir ".$dirsource." into ".$dirdest);
1152 
1153  if (@rename($dirsource, $dirdest))
1154  {
1155  dol_syslog("Rename ok");
1156  // Rename docs starting with $oldref with $newref
1157  $listoffiles=dol_dir_list($conf->expensereport->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref,'/'));
1158  foreach($listoffiles as $fileentry)
1159  {
1160  $dirsource=$fileentry['name'];
1161  $dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource);
1162  $dirsource=$fileentry['path'].'/'.$dirsource;
1163  $dirdest=$fileentry['path'].'/'.$dirdest;
1164  @rename($dirsource, $dirdest);
1165  }
1166  }
1167  }
1168  }
1169  }
1170 
1171  // Set new ref and current status
1172  if (! $error)
1173  {
1174  $this->ref = $num;
1175  $this->statut = self::STATUS_VALIDATED;
1176  }
1177 
1178  if (empty($error))
1179  {
1180  $this->db->commit();
1181  return 1;
1182  }
1183  else
1184  {
1185  $this->db->rollback();
1186  $this->error=$this->db->error();
1187  return -2;
1188  }
1189  }
1190  else
1191  {
1192  $this->db->rollback();
1193  $this->error=$this->db->lasterror();
1194  return -1;
1195  }
1196  }
1197 
1198  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1205  function set_save_from_refuse($fuser)
1206  {
1207  // phpcs:enable
1208  global $conf,$langs;
1209 
1210  // Sélection de la date de début de la NDF
1211  $sql = 'SELECT date_debut';
1212  $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
1213  $sql.= ' WHERE rowid = '.$this->id;
1214 
1215  $result = $this->db->query($sql);
1216 
1217  $objp = $this->db->fetch_object($result);
1218 
1219  $this->date_debut = $this->db->jdate($objp->date_debut);
1220 
1221  if ($this->fk_statut != 2)
1222  {
1223  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1224  $sql.= " SET fk_statut = 2";
1225  $sql.= ' WHERE rowid = '.$this->id;
1226 
1227  dol_syslog(get_class($this)."::set_save_from_refuse sql=".$sql, LOG_DEBUG);
1228 
1229  if ($this->db->query($sql))
1230  {
1231  return 1;
1232  }
1233  else
1234  {
1235  $this->error=$this->db->lasterror();
1236  return -1;
1237  }
1238  }
1239  else
1240  {
1241  dol_syslog(get_class($this)."::set_save_from_refuse expensereport already with save status", LOG_WARNING);
1242  }
1243  }
1244 
1252  function setApproved($fuser, $notrigger=0)
1253  {
1254  $now=dol_now();
1255  $error = 0;
1256 
1257  // date approval
1258  $this->date_approve = $now;
1259  if ($this->fk_statut != 5)
1260  {
1261  $this->db->begin();
1262 
1263  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1264  $sql.= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = 5, fk_user_approve = ".$fuser->id.",";
1265  $sql.= " date_approve='".$this->db->idate($this->date_approve)."'";
1266  $sql.= ' WHERE rowid = '.$this->id;
1267  if ($this->db->query($sql))
1268  {
1269  if (!$notrigger)
1270  {
1271  // Call trigger
1272  $result=$this->call_trigger('EXPENSE_REPORT_APPROVE',$fuser);
1273 
1274  if ($result < 0) {
1275  $error++;
1276  }
1277  // End call triggers
1278  }
1279 
1280  if (empty($error))
1281  {
1282  $this->db->commit();
1283  return 1;
1284  }
1285  else
1286  {
1287  $this->db->rollback();
1288  $this->error=$this->db->error();
1289  return -2;
1290  }
1291  }
1292  else
1293  {
1294  $this->db->rollback();
1295  $this->error=$this->db->lasterror();
1296  return -1;
1297  }
1298  }
1299  else
1300  {
1301  dol_syslog(get_class($this)."::setApproved expensereport already with approve status", LOG_WARNING);
1302  }
1303 
1304  return 0;
1305  }
1306 
1315  function setDeny($fuser,$details,$notrigger=0)
1316  {
1317  $now = dol_now();
1318  $error = 0;
1319 
1320  // date de refus
1321  if ($this->fk_statut != 99)
1322  {
1323  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1324  $sql.= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = 99, fk_user_refuse = ".$fuser->id.",";
1325  $sql.= " date_refuse='".$this->db->idate($now)."',";
1326  $sql.= " detail_refuse='".$this->db->escape($details)."',";
1327  $sql.= " fk_user_approve = NULL";
1328  $sql.= ' WHERE rowid = '.$this->id;
1329  if ($this->db->query($sql))
1330  {
1331  $this->fk_statut = 99;
1332  $this->fk_user_refuse = $fuser->id;
1333  $this->detail_refuse = $details;
1334  $this->date_refuse = $now;
1335 
1336  if (!$notrigger)
1337  {
1338  // Call trigger
1339  $result=$this->call_trigger('EXPENSE_REPORT_DENY',$fuser);
1340 
1341  if ($result < 0) {
1342  $error++;
1343  }
1344  // End call triggers
1345  }
1346 
1347  if (empty($error))
1348  {
1349  $this->db->commit();
1350  return 1;
1351  }
1352  else
1353  {
1354  $this->db->rollback();
1355  $this->error=$this->db->error();
1356  return -2;
1357  }
1358  }
1359  else
1360  {
1361  $this->db->rollback();
1362  $this->error=$this->db->lasterror();
1363  return -1;
1364  }
1365  }
1366  else
1367  {
1368  dol_syslog(get_class($this)."::setDeny expensereport already with refuse status", LOG_WARNING);
1369  }
1370  }
1371 
1372  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1380  function set_unpaid($fuser, $notrigger = 0)
1381  {
1382  // phpcs:enable
1383  $error = 0;
1384 
1385  if ($this->fk_c_deplacement_statuts != 5)
1386  {
1387  $this->db->begin();
1388 
1389  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1390  $sql.= " SET fk_statut = 5";
1391  $sql.= ' WHERE rowid = '.$this->id;
1392 
1393  dol_syslog(get_class($this)."::set_unpaid sql=".$sql, LOG_DEBUG);
1394 
1395  if ($this->db->query($sql))
1396  {
1397  if (!$notrigger)
1398  {
1399  // Call trigger
1400  $result=$this->call_trigger('EXPENSE_REPORT_UNPAID',$fuser);
1401 
1402  if ($result < 0) {
1403  $error++;
1404  }
1405  // End call triggers
1406  }
1407 
1408  if (empty($error))
1409  {
1410  $this->db->commit();
1411  return 1;
1412  }
1413  else
1414  {
1415  $this->db->rollback();
1416  $this->error=$this->db->error();
1417  return -2;
1418  }
1419  }
1420  else
1421  {
1422  $this->db->rollback();
1423  $this->error=$this->db->error();
1424  return -1;
1425  }
1426  }
1427  else
1428  {
1429  dol_syslog(get_class($this)."::set_unpaid expensereport already with unpaid status", LOG_WARNING);
1430  }
1431  }
1432 
1433  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1442  function set_cancel($fuser,$detail, $notrigger=0)
1443  {
1444  // phpcs:enable
1445  $error = 0;
1446  $this->date_cancel = $this->db->idate(gmmktime());
1447  if ($this->fk_statut != 4)
1448  {
1449  $this->db->begin();
1450 
1451  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1452  $sql.= " SET fk_statut = 4, fk_user_cancel = ".$fuser->id;
1453  $sql.= ", date_cancel='".$this->db->idate($this->date_cancel)."'";
1454  $sql.= " ,detail_cancel='".$this->db->escape($detail)."'";
1455  $sql.= ' WHERE rowid = '.$this->id;
1456 
1457  dol_syslog(get_class($this)."::set_cancel sql=".$sql, LOG_DEBUG);
1458 
1459  if ($this->db->query($sql))
1460  {
1461  if (!$notrigger)
1462  {
1463  // Call trigger
1464  $result=$this->call_trigger('EXPENSE_REPORT_CANCEL',$fuser);
1465 
1466  if ($result < 0) {
1467  $error++;
1468  }
1469  // End call triggers
1470  }
1471 
1472  if (empty($error))
1473  {
1474  $this->db->commit();
1475  return 1;
1476  }
1477  else
1478  {
1479  $this->db->rollback();
1480  $this->error=$this->db->error();
1481  return -2;
1482  }
1483  }
1484  else
1485  {
1486  $this->db->rollback();
1487  $this->error=$this->db->error();
1488  return -1;
1489  }
1490  }
1491  else
1492  {
1493  dol_syslog(get_class($this)."::set_cancel expensereport already with cancel status", LOG_WARNING);
1494  }
1495  }
1496 
1502  function getNextNumRef()
1503  {
1504  global $langs, $conf;
1505  $langs->load("trips");
1506 
1507  if (! empty($conf->global->EXPENSEREPORT_ADDON))
1508  {
1509  $mybool=false;
1510 
1511  $file = $conf->global->EXPENSEREPORT_ADDON.".php";
1512  $classname = $conf->global->EXPENSEREPORT_ADDON;
1513 
1514  // Include file with class
1515  $dirmodels=array_merge(array('/'), (array) $conf->modules_parts['models']);
1516  foreach ($dirmodels as $reldir)
1517  {
1518  $dir = dol_buildpath($reldir."core/modules/expensereport/");
1519 
1520  // Load file with numbering class (if found)
1521  $mybool|=@include_once $dir.$file;
1522  }
1523 
1524  if ($mybool === false) {
1525  dol_print_error('', "Failed to include file ".$file);
1526  return '';
1527  }
1528 
1529  $obj = new $classname();
1530  $numref = $obj->getNextValue($this);
1531 
1532  if ($numref != "")
1533  {
1534  return $numref;
1535  }
1536  else
1537  {
1538  $this->error=$obj->error;
1539  $this->errors=$obj->errors;
1540  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1541  return -1;
1542  }
1543  }
1544  else
1545  {
1546  $this->error = "Error_EXPENSEREPORT_ADDON_NotDefined";
1547  return -2;
1548  }
1549  }
1550 
1562  function getNomUrl($withpicto=0, $max=0, $short=0, $moretitle='', $notooltip=0, $save_lastsearch_value=-1)
1563  {
1564  global $langs, $conf;
1565 
1566  $result='';
1567 
1568  $url = DOL_URL_ROOT.'/expensereport/card.php?id='.$this->id;
1569 
1570  if ($short) return $url;
1571 
1572  $label = '<u>' . $langs->trans("ShowExpenseReport") . '</u>';
1573  if (! empty($this->ref))
1574  $label .= '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
1575  if (! empty($this->total_ht))
1576  $label.= '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
1577  if (! empty($this->total_tva))
1578  $label.= '<br><b>' . $langs->trans('VAT') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
1579  if (! empty($this->total_ttc))
1580  $label.= '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
1581  if ($moretitle) $label.=' - '.$moretitle;
1582 
1583  //if ($option != 'nolink')
1584  //{
1585  // Add param to save lastsearch_values or not
1586  $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
1587  if ($save_lastsearch_value == -1 && preg_match('/list\.php/',$_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
1588  if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
1589  //}
1590 
1591  $ref=$this->ref;
1592  if (empty($ref)) $ref=$this->id;
1593 
1594  $linkclose='';
1595  if (empty($notooltip))
1596  {
1597  if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
1598  {
1599  $label=$langs->trans("ShowExpenseReport");
1600  $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
1601  }
1602  $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
1603  $linkclose.=' class="classfortooltip"';
1604  }
1605 
1606  $linkstart = '<a href="'.$url.'"';
1607  $linkstart.=$linkclose.'>';
1608  $linkend='</a>';
1609 
1610  $result .= $linkstart;
1611  if ($withpicto) $result.=img_object(($notooltip?'':$label), $this->picto, ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
1612  if ($withpicto != 2) $result.=($max?dol_trunc($ref,$max):$ref);
1613  $result .= $linkend;
1614 
1615  return $result;
1616  }
1617 
1618  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1626  function update_totaux_add($ligne_total_ht,$ligne_total_tva)
1627  {
1628  // phpcs:enable
1629  $this->total_ht = $this->total_ht + $ligne_total_ht;
1630  $this->total_tva = $this->total_tva + $ligne_total_tva;
1631  $this->total_ttc = $this->total_ht + $this->total_tva;
1632 
1633  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
1634  $sql.= " total_ht = ".$this->total_ht;
1635  $sql.= " , total_ttc = ".$this->total_ttc;
1636  $sql.= " , total_tva = ".$this->total_tva;
1637  $sql.= " WHERE rowid = ".$this->id;
1638 
1639  $result = $this->db->query($sql);
1640  if ($result):
1641  return 1;
1642  else:
1643  $this->error=$this->db->error();
1644  return -1;
1645  endif;
1646  }
1647 
1648  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1656  function update_totaux_del($ligne_total_ht,$ligne_total_tva)
1657  {
1658  // phpcs:enable
1659  $this->total_ht = $this->total_ht - $ligne_total_ht;
1660  $this->total_tva = $this->total_tva - $ligne_total_tva;
1661  $this->total_ttc = $this->total_ht + $this->total_tva;
1662 
1663  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
1664  $sql.= " total_ht = ".$this->total_ht;
1665  $sql.= " , total_ttc = ".$this->total_ttc;
1666  $sql.= " , total_tva = ".$this->total_tva;
1667  $sql.= " WHERE rowid = ".$this->id;
1668 
1669  $result = $this->db->query($sql);
1670  if ($result):
1671  return 1;
1672  else:
1673  $this->error=$this->db->error();
1674  return -1;
1675  endif;
1676  }
1677 
1692  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)
1693  {
1694  global $conf,$langs,$mysoc;
1695 
1696  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);
1697 
1698  if ($this->fk_statut == self::STATUS_DRAFT)
1699  {
1700  if (empty($qty)) $qty = 0;
1701  if (empty($fk_c_type_fees) || $fk_c_type_fees < 0) $fk_c_type_fees = 0;
1702  if (empty($fk_c_exp_tax_cat) || $fk_c_exp_tax_cat < 0) $fk_c_exp_tax_cat = 0;
1703  if (empty($vatrate) || $vatrate < 0) $vatrate = 0;
1704  if (empty($date)) $date = '';
1705  if (empty($fk_project)) $fk_project = 0;
1706 
1707  $qty = price2num($qty);
1708  if (!preg_match('/\((.*)\)/', $vatrate)) {
1709  $vatrate = price2num($vatrate); // $txtva can have format '5.0(XXX)' or '5'
1710  }
1711  $up = price2num($up);
1712 
1713  $this->db->begin();
1714 
1715  $this->line = new ExpenseReportLine($this->db);
1716 
1717  $localtaxes_type=getLocalTaxesFromRate($vatrate,0,$mysoc,$this->thirdparty);
1718 
1719  $vat_src_code = '';
1720  if (preg_match('/\((.*)\)/', $vatrate, $reg))
1721  {
1722  $vat_src_code = $reg[1];
1723  $vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate.
1724  }
1725  $vatrate = preg_replace('/\*/','',$vatrate);
1726 
1727  $seller = ''; // seller is unknown
1728 
1729  $tmp = calcul_price_total($qty, $up, 0, $vatrate, 0, 0, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
1730 
1731  $this->line->value_unit = $up;
1732  $this->line->vatrate = price2num($vatrate);
1733  $this->line->total_ttc = $tmp[2];
1734  $this->line->total_ht = $tmp[0];
1735  $this->line->total_tva = $tmp[1];
1736 
1737  $this->line->fk_expensereport = $this->id;
1738  $this->line->qty = $qty;
1739  $this->line->date = $date;
1740  $this->line->fk_c_type_fees = $fk_c_type_fees;
1741  $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
1742  $this->line->comments = $comments;
1743  $this->line->fk_projet = $fk_project;
1744 
1745  $this->applyOffset();
1746  $this->checkRules($type, $seller);
1747 
1748  $result=$this->line->insert(0, true);
1749  if ($result > 0)
1750  {
1751  $result=$this->update_price(); // This method is designed to add line from user input so total calculation must be done using 'auto' mode.
1752  if ($result > 0)
1753  {
1754  $this->db->commit();
1755  return $this->line->rowid;
1756  }
1757  else
1758  {
1759  $this->db->rollback();
1760  return -1;
1761  }
1762  }
1763  else
1764  {
1765  $this->error=$this->line->error;
1766  dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1767  $this->db->rollback();
1768  return -2;
1769  }
1770  }
1771  else
1772  {
1773  dol_syslog(get_class($this)."::addline status of expense report must be Draft to allow use of ->addline()", LOG_ERR);
1774  $this->error = 'ErrorExpenseNotDraft';
1775  return -3;
1776  }
1777  }
1778 
1786  function checkRules($type=0, $seller='')
1787  {
1788  global $user,$conf,$db,$langs;
1789 
1790  $langs->load('trips');
1791 
1792  if (empty($conf->global->MAIN_USE_EXPENSE_RULE)) return true; // if don't use rules
1793 
1794  $rulestocheck = ExpenseReportRule::getAllRule($this->line->fk_c_type_fees, $this->line->date, $this->fk_user_author);
1795 
1796  $violation = 0;
1797  $rule_warning_message_tab = array();
1798 
1799  $current_total_ttc = $this->line->total_ttc;
1800  $new_current_total_ttc = $this->line->total_ttc;
1801 
1802  // check if one is violated
1803  foreach ($rulestocheck as $rule)
1804  {
1805  if (in_array($rule->code_expense_rules_type, array('EX_DAY', 'EX_MON', 'EX_YEA'))) $amount_to_test = $this->line->getExpAmount($rule, $this->fk_user_author, $rule->code_expense_rules_type);
1806  else $amount_to_test = $current_total_ttc; // EX_EXP
1807 
1808  $amount_to_test = $amount_to_test - $current_total_ttc + $new_current_total_ttc; // if amount as been modified by a previous rule
1809 
1810  if ($amount_to_test > $rule->amount)
1811  {
1812  $violation++;
1813 
1814  if ($rule->restrictive)
1815  {
1816  $this->error = 'ExpenseReportConstraintViolationError';
1817  $this->errors[] = $this->error;
1818 
1819  $new_current_total_ttc -= $amount_to_test - $rule->amount; // ex, entered 16€, limit 12€, subtracts 4€;
1820  $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), $langs->trans('by'.$rule->code_expense_rules_type, price($new_current_total_ttc,0,$langs,1,-1,-1,$conf->currency)));
1821  }
1822  else
1823  {
1824  $this->error = 'ExpenseReportConstraintViolationWarning';
1825  $this->errors[] = $this->error;
1826 
1827  $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), $langs->trans('nolimitby'.$rule->code_expense_rules_type));
1828  }
1829 
1830  // No break, we sould test if another rule is violated
1831  }
1832  }
1833 
1834  $this->line->rule_warning_message = implode('\n', $rule_warning_message_tab);
1835 
1836  if ($violation > 0)
1837  {
1838  $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);
1839 
1840  $this->line->value_unit = $tmp[5];
1841  $this->line->total_ttc = $tmp[2];
1842  $this->line->total_ht = $tmp[0];
1843  $this->line->total_tva = $tmp[1];
1844 
1845  return false;
1846  }
1847  else return true;
1848  }
1849 
1855  function applyOffset()
1856  {
1857  global $conf;
1858 
1859  if (empty($conf->global->MAIN_USE_EXPENSE_IK)) return false;
1860 
1861  $userauthor = new User($this->db);
1862  if ($userauthor->fetch($this->fk_user_author) <= 0)
1863  {
1864  $this->error = 'ErrorCantFetchUser';
1865  $this->errors[] = 'ErrorCantFetchUser';
1866  return false;
1867  }
1868 
1869  $range = ExpenseReportIk::getRangeByUser($userauthor, $this->line->fk_c_exp_tax_cat);
1870 
1871  if (empty($range))
1872  {
1873  $this->error = 'ErrorNoRangeAvailable';
1874  $this->errors[] = 'ErrorNoRangeAvailable';
1875  return false;
1876  }
1877 
1878  if (!empty($conf->global->MAIN_EXPENSE_APPLY_ENTIRE_OFFSET)) $ikoffset = $range->ikoffset;
1879  else $ikoffset = $range->ikoffset / 12; // The amount of offset is a global value for the year
1880 
1881  // Test if ikoffset has been applied for the current month
1882  if (!$this->offsetAlreadyGiven())
1883  {
1884  $new_up = $range->coef + ($ikoffset / $this->line->qty);
1885  $tmp = calcul_price_total($this->line->qty, $new_up, 0, $this->line->vatrate, 0, 0, 0, 'TTC', 0, $type, $seller);
1886 
1887  $this->line->value_unit = $tmp[5];
1888  $this->line->total_ttc = $tmp[2];
1889  $this->line->total_ht = $tmp[0];
1890  $this->line->total_tva = $tmp[1];
1891 
1892  return true;
1893  }
1894 
1895  return false;
1896  }
1897 
1904  {
1905  $sql = 'SELECT e.rowid FROM '.MAIN_DB_PREFIX.'expensereport e';
1906  $sql.= ' INNER JOIN '.MAIN_DB_PREFIX.'expensereport_det d ON (e.rowid = d.fk_expensereport)';
1907  $sql.= ' INNER JOIN '.MAIN_DB_PREFIX.'c_type_fees f ON (d.fk_c_type_fees = f.id AND f.code = "EX_KME")';
1908  $sql.= ' WHERE e.fk_user_author = '.(int) $this->fk_user_author;
1909  $sql.= ' AND YEAR(d.date) = "'.dol_print_date($this->line->date, '%Y').'" AND MONTH(d.date) = "'.dol_print_date($this->line->date, '%m').'"';
1910  if (!empty($this->line->id)) $sql.= ' AND d.rowid <> '.$this->line->id;
1911 
1912  dol_syslog(get_class($this)."::offsetAlreadyGiven sql=".$sql);
1913  $resql = $this->db->query($sql);
1914  if ($resql)
1915  {
1916  $num = $this->db->num_rows($resql);
1917  if ($num > 0) return true;
1918  }
1919  else
1920  {
1921  dol_print_error($this->db);
1922  }
1923 
1924  return false;
1925  }
1926 
1942  function updateline($rowid, $type_fees_id, $projet_id, $vatrate, $comments, $qty, $value_unit, $date, $expensereport_id, $fk_c_exp_tax_cat=0)
1943  {
1944  global $user, $mysoc;
1945 
1946  if ($this->fk_statut==0 || $this->fk_statut==99)
1947  {
1948  $this->db->begin();
1949 
1950  $type = 0; // TODO What if type is service ?
1951 
1952  // We don't know seller and buyer for expense reports
1953  $seller = $mysoc;
1954  $buyer = new Societe($this->db);
1955 
1956  $localtaxes_type=getLocalTaxesFromRate($vatrate,0,$buyer,$seller);
1957 
1958  // Clean vat code
1959  $vat_src_code='';
1960  if (preg_match('/\((.*)\)/', $vatrate, $reg))
1961  {
1962  $vat_src_code = $reg[1];
1963  $vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate.
1964  }
1965  $vatrate = preg_replace('/\*/','',$vatrate);
1966 
1967  $tmp = calcul_price_total($qty, $value_unit, 0, $vatrate, 0, 0, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
1968 
1969  // calcul total of line
1970  //$total_ttc = price2num($qty*$value_unit, 'MT');
1971 
1972  $tx_tva = $vatrate / 100;
1973  $tx_tva = $tx_tva + 1;
1974  $total_ht = price2num($total_ttc/$tx_tva, 'MT');
1975 
1976  $total_tva = price2num($total_ttc - $total_ht, 'MT');
1977  // fin calculs
1978 
1979  $this->line = new ExpenseReportLine($this->db);
1980  $this->line->comments = $comments;
1981  $this->line->qty = $qty;
1982  $this->line->value_unit = $value_unit;
1983  $this->line->date = $date;
1984 
1985  $this->line->fk_expensereport= $expensereport_id;
1986  $this->line->fk_c_type_fees = $type_fees_id;
1987  $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
1988  $this->line->fk_projet = $projet_id;
1989 
1990  $this->line->vat_src_code = $vat_src_code;
1991  $this->line->vatrate = price2num($vatrate);
1992  $this->line->total_ttc = $tmp[2];
1993  $this->line->total_ht = $tmp[0];
1994  $this->line->total_tva = $tmp[1];
1995  $this->line->localtax1_tx = $localtaxes_type[1];
1996  $this->line->localtax2_tx = $localtaxes_type[3];
1997  $this->line->localtax1_type = $localtaxes_type[0];
1998  $this->line->localtax2_type = $localtaxes_type[2];
1999 
2000  $this->line->rowid = $rowid;
2001  $this->line->id = $rowid;
2002 
2003  // Select des infos sur le type fees
2004  $sql = "SELECT c.code as code_type_fees, c.label as libelle_type_fees";
2005  $sql.= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
2006  $sql.= " WHERE c.id = ".$type_fees_id;
2007  $result = $this->db->query($sql);
2008  $objp_fees = $this->db->fetch_object($result);
2009  $this->line->type_fees_code = $objp_fees->code_type_fees;
2010  $this->line->type_fees_libelle = $objp_fees->libelle_type_fees;
2011 
2012  // Select des informations du projet
2013  $sql = "SELECT p.ref as ref_projet, p.title as title_projet";
2014  $sql.= " FROM ".MAIN_DB_PREFIX."projet as p";
2015  $sql.= " WHERE p.rowid = ".$projet_id;
2016  $result = $this->db->query($sql);
2017  if ($result) {
2018  $objp_projet = $this->db->fetch_object($result);
2019  }
2020  $this->line->projet_ref = $objp_projet->ref_projet;
2021  $this->line->projet_title = $objp_projet->title_projet;
2022 
2023  $this->applyOffset();
2024  $this->checkRules();
2025 
2026  $result = $this->line->update($user);
2027  if ($result > 0)
2028  {
2029  $this->db->commit();
2030  return 1;
2031  }
2032  else
2033  {
2034  $this->error=$this->line->error;
2035  $this->errors=$this->line->errors;
2036  $this->db->rollback();
2037  return -2;
2038  }
2039  }
2040  }
2041 
2049  function deleteline($rowid, $fuser='')
2050  {
2051  $this->db->begin();
2052 
2053  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2054  $sql.= ' WHERE rowid = '.$rowid;
2055 
2056  dol_syslog(get_class($this)."::deleteline sql=".$sql);
2057  $result = $this->db->query($sql);
2058  if (!$result)
2059  {
2060  $this->error=$this->db->error();
2061  dol_syslog(get_class($this)."::deleteline Error ".$this->error, LOG_ERR);
2062  $this->db->rollback();
2063  return -1;
2064  }
2065 
2066  $this->db->commit();
2067 
2068  return 1;
2069  }
2070 
2071  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2080  function periode_existe($fuser, $date_debut, $date_fin)
2081  {
2082  // phpcs:enable
2083  $sql = "SELECT rowid, date_debut, date_fin";
2084  $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element;
2085  $sql.= " WHERE fk_user_author = '{$fuser->id}'";
2086 
2087  dol_syslog(get_class($this)."::periode_existe sql=".$sql);
2088  $result = $this->db->query($sql);
2089  if($result)
2090  {
2091  $num_lignes = $this->db->num_rows($result); $i = 0;
2092 
2093  if ($num_lignes>0)
2094  {
2095  $date_d_form = $date_debut;
2096  $date_f_form = $date_fin;
2097 
2098  $existe = false;
2099 
2100  while ($i < $num_lignes)
2101  {
2102  $objp = $this->db->fetch_object($result);
2103 
2104  $date_d_req = $this->db->jdate($objp->date_debut); // 3
2105  $date_f_req = $this->db->jdate($objp->date_fin); // 4
2106 
2107  if (!($date_f_form < $date_d_req || $date_d_form > $date_f_req)) $existe = true;
2108 
2109  $i++;
2110  }
2111 
2112  if($existe) return 1;
2113  else return 0;
2114  }
2115  else
2116  {
2117  return 0;
2118  }
2119  }
2120  else
2121  {
2122  $this->error=$this->db->lasterror();
2123  dol_syslog(get_class($this)."::periode_existe Error ".$this->error, LOG_ERR);
2124  return -1;
2125  }
2126  }
2127 
2128 
2129  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2137  {
2138  // phpcs:enable
2139  $users_validator=array();
2140 
2141  $sql = "SELECT DISTINCT ur.fk_user";
2142  $sql.= " FROM ".MAIN_DB_PREFIX."user_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2143  $sql.= " WHERE ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2144  $sql.= "UNION";
2145  $sql.= " SELECT DISTINCT ugu.fk_user";
2146  $sql.= " FROM ".MAIN_DB_PREFIX."usergroup_user as ugu, ".MAIN_DB_PREFIX."usergroup_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2147  $sql.= " WHERE ugu.fk_usergroup = ur.fk_usergroup AND ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2148  //print $sql;
2149 
2150  dol_syslog(get_class($this)."::fetch_users_approver_expensereport sql=".$sql);
2151  $result = $this->db->query($sql);
2152  if($result)
2153  {
2154  $num_lignes = $this->db->num_rows($result); $i = 0;
2155  while ($i < $num_lignes)
2156  {
2157  $objp = $this->db->fetch_object($result);
2158  array_push($users_validator,$objp->fk_user);
2159  $i++;
2160  }
2161  return $users_validator;
2162  }
2163  else
2164  {
2165  $this->error=$this->db->lasterror();
2166  dol_syslog(get_class($this)."::fetch_users_approver_expensereport Error ".$this->error, LOG_ERR);
2167  return -1;
2168  }
2169  }
2170 
2182  public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
2183  {
2184  global $conf,$langs;
2185 
2186  $langs->load("trips");
2187 
2188  if (! dol_strlen($modele)) {
2189 
2190  $modele = 'standard';
2191 
2192  if ($this->modelpdf) {
2193  $modele = $this->modelpdf;
2194  } elseif (! empty($conf->global->EXPENSEREPORT_ADDON_PDF)) {
2195  $modele = $conf->global->EXPENSEREPORT_ADDON_PDF;
2196  }
2197  }
2198 
2199  $modelpath = "core/modules/expensereport/doc/";
2200 
2201  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref,$moreparams);
2202  }
2203 
2210  function listOfTypes($active=1)
2211  {
2212  global $langs;
2213  $ret=array();
2214  $sql = "SELECT id, code, label";
2215  $sql.= " FROM ".MAIN_DB_PREFIX."c_type_fees";
2216  $sql.= " WHERE active = ".$active;
2217  dol_syslog(get_class($this)."::listOfTypes", LOG_DEBUG);
2218  $result = $this->db->query($sql);
2219  if ( $result )
2220  {
2221  $num = $this->db->num_rows($result);
2222  $i=0;
2223  while ($i < $num)
2224  {
2225  $obj = $this->db->fetch_object($result);
2226  $ret[$obj->code]=(($langs->trans($obj->code)!=$obj->code)?$langs->trans($obj->code):$obj->label);
2227  $i++;
2228  }
2229  }
2230  else
2231  {
2232  dol_print_error($this->db);
2233  }
2234  return $ret;
2235  }
2236 
2237  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2243  function load_state_board()
2244  {
2245  // phpcs:enable
2246  global $conf;
2247 
2248  $this->nb=array();
2249 
2250  $sql = "SELECT count(ex.rowid) as nb";
2251  $sql.= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2252  $sql.= " WHERE ex.fk_statut > 0";
2253  $sql.= " AND ex.entity IN (".getEntity('expensereport').")";
2254 
2255  $resql=$this->db->query($sql);
2256  if ($resql)
2257  {
2258  while ($obj=$this->db->fetch_object($resql))
2259  {
2260  $this->nb["expensereports"]=$obj->nb;
2261  }
2262  $this->db->free($resql);
2263  return 1;
2264  }
2265  else
2266  {
2267  dol_print_error($this->db);
2268  $this->error=$this->db->error();
2269  return -1;
2270  }
2271  }
2272 
2273  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2281  function load_board($user, $option='topay')
2282  {
2283  // phpcs:enable
2284  global $conf, $langs;
2285 
2286  if ($user->societe_id) return -1; // protection pour eviter appel par utilisateur externe
2287 
2288  $now=dol_now();
2289 
2290  $userchildids = $user->getAllChildIds(1);
2291 
2292  $sql = "SELECT ex.rowid, ex.date_valid";
2293  $sql.= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2294  if ($option == 'toapprove') $sql.= " WHERE ex.fk_statut = 2";
2295  else $sql.= " WHERE ex.fk_statut = 5";
2296  $sql.= " AND ex.entity IN (".getEntity('expensereport').")";
2297  $sql.= " AND (ex.fk_user_author IN (".join(',',$userchildids).")";
2298  $sql.= " OR ex.fk_user_validator IN (".join(',',$userchildids)."))";
2299 
2300  $resql=$this->db->query($sql);
2301  if ($resql)
2302  {
2303  $langs->load("members");
2304 
2305  $response = new WorkboardResponse();
2306  if ($option == 'toapprove')
2307  {
2308  $response->warning_delay=$conf->expensereport->approve->warning_delay/60/60/24;
2309  $response->label=$langs->trans("ExpenseReportsToApprove");
2310  $response->url=DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut=2';
2311  }
2312  else
2313  {
2314  $response->warning_delay=$conf->expensereport->payment->warning_delay/60/60/24;
2315  $response->label=$langs->trans("ExpenseReportsToPay");
2316  $response->url=DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut=5';
2317  }
2318  $response->img=img_object('',"trip");
2319 
2320  while ($obj=$this->db->fetch_object($resql))
2321  {
2322  $response->nbtodo++;
2323 
2324  if ($option == 'toapprove')
2325  {
2326  if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->approve->warning_delay)) {
2327  $response->nbtodolate++;
2328  }
2329  }
2330  else
2331  {
2332  if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->payment->warning_delay)) {
2333  $response->nbtodolate++;
2334  }
2335  }
2336  }
2337 
2338  return $response;
2339  }
2340  else
2341  {
2342  dol_print_error($this->db);
2343  $this->error=$this->db->error();
2344  return -1;
2345  }
2346  }
2347 
2354  public function hasDelay($option)
2355  {
2356  global $conf;
2357 
2358  //Only valid members
2359  if ($option == 'toapprove' && $this->status != 2) return false;
2360  if ($option == 'topay' && $this->status != 5) return false;
2361 
2362  $now = dol_now();
2363  if ($option == 'toapprove')
2364  {
2365  return ($this->datevalid?$this->datevalid:$this->date_valid) < ($now - $conf->expensereport->approve->warning_delay);
2366  }
2367  else
2368  return ($this->datevalid?$this->datevalid:$this->date_valid) < ($now - $conf->expensereport->payment->warning_delay);
2369  }
2370 
2376  public function getVentilExportCompta()
2377  {
2378  $alreadydispatched = 0;
2379 
2380  $type = 'expense_report';
2381 
2382  $sql = " SELECT COUNT(ab.rowid) as nb FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab WHERE ab.doc_type='".$type."' AND ab.fk_doc = ".$this->id;
2383  $resql = $this->db->query($sql);
2384  if ($resql)
2385  {
2386  $obj = $this->db->fetch_object($resql);
2387  if ($obj)
2388  {
2389  $alreadydispatched = $obj->nb;
2390  }
2391  }
2392  else
2393  {
2394  $this->error = $this->db->lasterror();
2395  return -1;
2396  }
2397 
2398  if ($alreadydispatched)
2399  {
2400  return 1;
2401  }
2402  return 0;
2403  }
2404 }
2405 
2406 
2411 {
2415  public $db;
2416 
2420  public $error='';
2421 
2425  public $rowid;
2426 
2427  public $comments;
2428  public $qty;
2429  public $value_unit;
2430  public $date;
2431 
2435  public $fk_c_type_fees;
2436 
2440  public $fk_c_exp_tax_cat;
2441 
2445  public $fk_projet;
2446 
2450  public $fk_expensereport;
2451 
2452  public $type_fees_code;
2453  public $type_fees_libelle;
2454 
2455  public $projet_ref;
2456  public $projet_title;
2457 
2458  var $vatrate;
2459  var $total_ht;
2460  var $total_tva;
2461  var $total_ttc;
2462 
2468  function __construct($db)
2469  {
2470  $this->db= $db;
2471  }
2472 
2479  function fetch($rowid)
2480  {
2481  $sql = 'SELECT fde.rowid, fde.fk_expensereport, fde.fk_c_type_fees, fde.fk_c_exp_tax_cat, fde.fk_projet, fde.date,';
2482  $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,';
2483  $sql.= ' ctf.code as type_fees_code, ctf.label as type_fees_libelle,';
2484  $sql.= ' pjt.rowid as projet_id, pjt.title as projet_title, pjt.ref as projet_ref';
2485  $sql.= ' FROM '.MAIN_DB_PREFIX.'expensereport_det as fde';
2486  $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.
2487  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as pjt ON fde.fk_projet=pjt.rowid';
2488  $sql.= ' WHERE fde.rowid = '.$rowid;
2489 
2490  $result = $this->db->query($sql);
2491 
2492  if($result)
2493  {
2494  $objp = $this->db->fetch_object($result);
2495 
2496  $this->rowid = $objp->rowid;
2497  $this->id = $obj->rowid;
2498  $this->ref = $obj->ref;
2499  $this->fk_expensereport = $objp->fk_expensereport;
2500  $this->comments = $objp->comments;
2501  $this->qty = $objp->qty;
2502  $this->date = $objp->date;
2503  $this->dates = $this->db->jdate($objp->date);
2504  $this->value_unit = $objp->value_unit;
2505  $this->fk_c_type_fees = $objp->fk_c_type_fees;
2506  $this->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
2507  $this->fk_projet = $objp->fk_projet;
2508  $this->type_fees_code = $objp->type_fees_code;
2509  $this->type_fees_libelle = $objp->type_fees_libelle;
2510  $this->projet_ref = $objp->projet_ref;
2511  $this->projet_title = $objp->projet_title;
2512  $this->vatrate = $objp->vatrate;
2513  $this->vat_src_code = $objp->vat_src_code;
2514  $this->total_ht = $objp->total_ht;
2515  $this->total_tva = $objp->total_tva;
2516  $this->total_ttc = $objp->total_ttc;
2517 
2518  $this->db->free($result);
2519  } else {
2520  dol_print_error($this->db);
2521  }
2522  }
2523 
2531  function insert($notrigger=0,$fromaddline=false)
2532  {
2533  global $langs,$user,$conf;
2534 
2535  $error=0;
2536 
2537  dol_syslog("ExpenseReportLine::Insert rang=".$this->rang, LOG_DEBUG);
2538 
2539  // Clean parameters
2540  $this->comments=trim($this->comments);
2541  if (!$this->value_unit_HT) $this->value_unit_HT=0;
2542  $this->qty = price2num($this->qty);
2543  $this->vatrate = price2num($this->vatrate);
2544  if (empty($this->fk_c_exp_tax_cat)) $this->fk_c_exp_tax_cat = 0;
2545 
2546  $this->db->begin();
2547 
2548  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'expensereport_det';
2549  $sql.= ' (fk_expensereport, fk_c_type_fees, fk_projet,';
2550  $sql.= ' tva_tx, vat_src_code, comments, qty, value_unit, total_ht, total_tva, total_ttc, date, rule_warning_message, fk_c_exp_tax_cat)';
2551  $sql.= " VALUES (".$this->db->escape($this->fk_expensereport).",";
2552  $sql.= " ".$this->db->escape($this->fk_c_type_fees).",";
2553  $sql.= " ".$this->db->escape($this->fk_projet>0?$this->fk_projet:'null').",";
2554  $sql.= " ".$this->db->escape($this->vatrate).",";
2555  $sql.= " '".$this->db->escape($this->vat_src_code)."',";
2556  $sql.= " '".$this->db->escape($this->comments)."',";
2557  $sql.= " ".$this->db->escape($this->qty).",";
2558  $sql.= " ".$this->db->escape($this->value_unit).",";
2559  $sql.= " ".$this->db->escape($this->total_ht).",";
2560  $sql.= " ".$this->db->escape($this->total_tva).",";
2561  $sql.= " ".$this->db->escape($this->total_ttc).",";
2562  $sql.= "'".$this->db->idate($this->date)."',";
2563  $sql.= " '".$this->db->escape($this->rule_warning_message)."',";
2564  $sql.= " ".$this->db->escape($this->fk_c_exp_tax_cat);
2565  $sql.= ")";
2566 
2567  $resql=$this->db->query($sql);
2568  if ($resql)
2569  {
2570  $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'expensereport_det');
2571 
2572  if (! $fromaddline)
2573  {
2574  $tmpparent=new ExpenseReport($this->db);
2575  $tmpparent->fetch($this->fk_expensereport);
2576  $result = $tmpparent->update_price();
2577  if ($result < 0)
2578  {
2579  $error++;
2580  $this->error = $tmpparent->error;
2581  $this->errors = $tmpparent->errors;
2582  }
2583  }
2584  }
2585  else
2586  {
2587  $error++;
2588  }
2589 
2590  if (! $error)
2591  {
2592  $this->db->commit();
2593  return $this->rowid;
2594  }
2595  else
2596  {
2597  $this->error=$this->db->lasterror();
2598  dol_syslog("ExpenseReportLine::insert Error ".$this->error, LOG_ERR);
2599  $this->db->rollback();
2600  return -2;
2601  }
2602  }
2603 
2612  public function getExpAmount(ExpenseReportRule $rule, $fk_user, $mode='day')
2613  {
2614  $amount = 0;
2615 
2616  $sql = 'SELECT SUM(d.total_ttc) as total_amount';
2617  $sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det d';
2618  $sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'expensereport e ON (d.fk_expensereport = e.rowid)';
2619  $sql .= ' WHERE e.fk_user_author = '.$fk_user;
2620  if (!empty($this->id)) $sql.= ' AND d.rowid <> '.$this->id;
2621  $sql .= ' AND d.fk_c_type_fees = '.$rule->fk_c_type_fees;
2622  if ($mode == 'day' || $mode == 'EX_DAY') $sql .= ' AND d.date = \''.dol_print_date($this->date, '%Y-%m-%d').'\'';
2623  elseif ($mode == 'mon' || $mode == 'EX_MON') $sql .= ' AND DATE_FORMAT(d.date, \'%Y-%m\') = \''.dol_print_date($this->date, '%Y-%m').'\'';
2624  elseif ($mode == 'year' || $mode == 'EX_YEA') $sql .= ' AND DATE_FORMAT(d.date, \'%Y\') = \''.dol_print_date($this->date, '%Y').'\'';
2625 
2626  dol_syslog('ExpenseReportLine::getExpAmountByDay sql='.$sql);
2627 
2628  $resql = $this->db->query($sql);
2629  if ($resql)
2630  {
2631  $num = $this->db->num_rows($resql);
2632  if ($num > 0)
2633  {
2634  $obj = $this->db->fetch_object($resql);
2635  $amount = (double) $obj->total_amount;
2636  }
2637  }
2638  else
2639  {
2640  dol_print_error($this->db);
2641  }
2642 
2643 
2644  return $amount + $this->total_ttc;
2645  }
2646 
2653  function update($fuser)
2654  {
2655  global $fuser,$langs,$conf;
2656 
2657  $error=0;
2658 
2659  // Clean parameters
2660  $this->comments=trim($this->comments);
2661  $this->vatrate = price2num($this->vatrate);
2662  $this->value_unit = price2num($this->value_unit);
2663  if (empty($this->fk_c_exp_tax_cat)) $this->fk_c_exp_tax_cat = 0;
2664 
2665  $this->db->begin();
2666 
2667  // Update line in database
2668  $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport_det SET";
2669  $sql.= " comments='".$this->db->escape($this->comments)."'";
2670  $sql.= ",value_unit=".$this->db->escape($this->value_unit);
2671  $sql.= ",qty=".$this->db->escape($this->qty);
2672  $sql.= ",date='".$this->db->idate($this->date)."'";
2673  $sql.= ",total_ht=".$this->db->escape($this->total_ht)."";
2674  $sql.= ",total_tva=".$this->db->escape($this->total_tva)."";
2675  $sql.= ",total_ttc=".$this->db->escape($this->total_ttc)."";
2676  $sql.= ",tva_tx=".$this->db->escape($this->vatrate);
2677  $sql.= ",vat_src_code='".$this->db->escape($this->vat_src_code)."'";
2678  $sql.= ",rule_warning_message='".$this->db->escape($this->rule_warning_message)."'";
2679  $sql.= ",fk_c_exp_tax_cat=".$this->db->escape($this->fk_c_exp_tax_cat);
2680  if ($this->fk_c_type_fees) $sql.= ",fk_c_type_fees=".$this->db->escape($this->fk_c_type_fees);
2681  else $sql.= ",fk_c_type_fees=null";
2682  if ($this->fk_projet) $sql.= ",fk_projet=".$this->db->escape($this->fk_projet);
2683  else $sql.= ",fk_projet=null";
2684  $sql.= " WHERE rowid = ".$this->db->escape($this->rowid);
2685 
2686  dol_syslog("ExpenseReportLine::update sql=".$sql);
2687 
2688  $resql=$this->db->query($sql);
2689  if ($resql)
2690  {
2691  $tmpparent=new ExpenseReport($this->db);
2692  $result = $tmpparent->fetch($this->fk_expensereport);
2693  if ($result > 0)
2694  {
2695  $result = $tmpparent->update_price();
2696  if ($result < 0)
2697  {
2698  $error++;
2699  $this->error = $tmpparent->error;
2700  $this->errors = $tmpparent->errors;
2701  }
2702  }
2703  else
2704  {
2705  $error++;
2706  $this->error = $tmpparent->error;
2707  $this->errors = $tmpparent->errors;
2708  }
2709  }
2710  else
2711  {
2712  $error++;
2713  dol_print_error($this->db);
2714  }
2715 
2716  if (! $error)
2717  {
2718  $this->db->commit();
2719  return 1;
2720  }
2721  else
2722  {
2723  $this->error=$this->db->lasterror();
2724  dol_syslog("ExpenseReportLine::update Error ".$this->error, LOG_ERR);
2725  $this->db->rollback();
2726  return -2;
2727  }
2728  }
2729 }
2730 
2731 
2732 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2743 function select_expensereport_statut($selected='',$htmlname='fk_statut',$useempty=1, $useshortlabel=0)
2744 {
2745  // phpcs:enable
2746  global $db, $langs;
2747 
2748  $tmpep=new ExpenseReport($db);
2749 
2750  print '<select class="flat" name="'.$htmlname.'">';
2751  if ($useempty) print '<option value="-1">&nbsp;</option>';
2752  $arrayoflabels=$tmpep->statuts;
2753  if ($useshortlabel) $arrayoflabels=$tmpep->statuts_short;
2754  foreach ($arrayoflabels as $key => $val)
2755  {
2756  if ($selected != '' && $selected == $key)
2757  {
2758  print '<option value="'.$key.'" selected>';
2759  }
2760  else
2761  {
2762  print '<option value="'.$key.'">';
2763  }
2764  print $langs->trans($val);
2765  print '</option>';
2766  }
2767  print '</select>';
2768 }
2769 
2770 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2780 function select_type_fees_id($selected='',$htmlname='type',$showempty=0, $active=1)
2781 {
2782  // phpcs:enable
2783  global $db,$langs,$user;
2784  $langs->load("trips");
2785 
2786  print '<select class="flat" name="'.$htmlname.'">';
2787  if ($showempty)
2788  {
2789  print '<option value="-1"';
2790  if ($selected == -1) print ' selected';
2791  print '>&nbsp;</option>';
2792  }
2793 
2794  $sql = "SELECT c.id, c.code, c.label as type FROM ".MAIN_DB_PREFIX."c_type_fees as c";
2795  if ($active >= 0) $sql.= " WHERE c.active = ".$active;
2796  $sql.= " ORDER BY c.label ASC";
2797  $resql=$db->query($sql);
2798  if ($resql)
2799  {
2800  $num = $db->num_rows($resql);
2801  $i = 0;
2802 
2803  while ($i < $num)
2804  {
2805  $obj = $db->fetch_object($resql);
2806  print '<option value="'.$obj->id.'"';
2807  if ($obj->code == $selected || $obj->id == $selected) print ' selected';
2808  print '>';
2809  if ($obj->code != $langs->trans($obj->code)) print $langs->trans($obj->code);
2810  else print $langs->trans($obj->type);
2811  $i++;
2812  }
2813  }
2814  print '</select>';
2815 }
getNextNumRef()
Return next reference of expense report not already used.
select_expensereport_statut($selected='', $htmlname='fk_statut', $useempty=1, $useshortlabel=0)
Retourne la liste deroulante des differents etats d&#39;une note de frais.
createFromClone($fk_user_author)
Load an object from its id and create a new one in database.
const STATUS_APPROVED
Classified approved.
const STATUS_VALIDATED
Validated (need to be paid)
LibStatut($status, $mode=0)
Returns the label of a statut.
print
Draft customers invoices.
Definition: index.php:91
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.
if(! empty($conf->facture->enabled) && $user->rights->facture->lire) if(! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture->lire) if(! empty($conf->don->enabled) && $user->rights->societe->lire) if(! empty($conf->tax->enabled) && $user->rights->tax->charges->lire) if(! empty($conf->facture->enabled) &&! empty($conf->commande->enabled) && $user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(! empty($conf->facture->enabled) && $user->rights->facture->lire) if(! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1053
getExpAmount(ExpenseReportRule $rule, $fk_user, $mode='day')
Function to get total amount in expense reports for a same rule.
info($id)
Load information on object.
Class of expense report details lines.
static getRangeByUser(User $userauthor, $fk_c_exp_tax_cat)
Return an array of ranges for a user.
__construct($db)
Constructor.
applyOffset()
Method to apply the offset if needed.
load_board($user, $option='topay')
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
select_type_fees_id($selected='', $htmlname='type', $showempty=0, $active=1)
Return list of types of notes with select value = id.
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)
addline
getVentilExportCompta()
Return if an expensereport was dispatched into bookkeeping.
Class to manage inventories.
Class to manage Dolibarr users.
Definition: user.class.php:41
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
fetch($rowid)
Fetch record for expense report detailed line.
dol_print_error($db='', $error='', $errors=null)
Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remonte...
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.
const STATUS_REFUSED
Classified refused.
set_unpaid($fuser, $notrigger=0)
set_unpaid
setValidate($fuser, $notrigger=0)
Set to status validate.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='')
Write log message into outputs.
Class to manage third parties objects (customers, suppliers, prospects...)
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
update_totaux_del($ligne_total_ht, $ligne_total_tva)
Update total of an expense report when you delete a line.
checkRules($type=0, $seller='')
Check constraint of rules and update price if needed.
update_totaux_add($ligne_total_ht, $ligne_total_tva)
Update total of an expense report when you add a line.
fetch_users_approver_expensereport()
Return list of people with permission to validate expense reports.
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)...
initAsSpecimen()
Initialise an instance with random values.
fetch_line_by_project($projectid, $user='')
fetch_line_by_project
set_paid($id, $fuser, $notrigger=0)
Classify the expense report as paid.
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:59
dol_now($mode='gmt')
Return date for now.
updateline($rowid, $type_fees_id, $projet_id, $vatrate, $comments, $qty, $value_unit, $date, $expensereport_id, $fk_c_exp_tax_cat=0)
updateline
Class to manage Trips and Expenses.
listOfTypes($active=1)
List of types.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages...
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)
Calculate totals (net, vat, ...) of a line.
Definition: price.lib.php:85
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages...
dol_print_date($time, $format='', $tzoutput='tzserver', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
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->nb pour le tableau de bord.
set_cancel($fuser, $detail, $notrigger=0)
set_cancel
static getAllRule($fk_c_type_fees='', $date='', $fk_user='')
Return all rules or filtered by something.
create($user, $notrigger=0)
Create object in database.
getNomUrl($withpicto=0, $max=0, $short=0, $moretitle='', $notooltip=0, $save_lastsearch_value=-1)
Return clicable name (with picto eventually)
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk accordign to template module.
insert($notrigger=0, $fromaddline=false)
insert
update($user, $notrigger=0, $userofexpensereport=null)
update
offsetAlreadyGiven()
If the sql find any rows then the ikoffset is already given (ikoffset is applied at the first expense...
call_trigger($trigger_name, $user)
Call trigger based on this instance.
__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.
recalculer($id)
recalculer TODO Replace this with call to update_price if not already done
deleteline($rowid, $fuser='')
deleteline
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='')
Show picto whatever it&#39;s its name (generic function)
getLibStatut($mode=0)
Returns the label status.
const STATUS_DRAFT
Draft status.
price2num($amount, $rounding='', $alreadysqlnb=0)
Function that return a number with universal decimal format (decimal separator is &#39;...
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Parent class of all other business classes (invoices, contracts, proposals, orders, ...)
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
set_save_from_refuse($fuser)
set_save_from_refuse
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.