Completed
Branch develop (ba7d3e)
by
unknown
37:14
created

ExpenseReport::addline()   F

Complexity

Conditions 14
Paths 448

Size

Total Lines 82
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 53
nc 448
nop 9
dl 0
loc 82
rs 3.4905
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/* Copyright (C) 2011 Dimitri Mouillard   <[email protected]>
3
 * Copyright (C) 2015 Laurent Destailleur <[email protected]>
4
 * Copyright (C) 2015 Alexandre Spangaro  <[email protected]>
5
 * Copyright (C) 2016 Ferran Marcet       <[email protected]>
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
/**
22
 *       \file       htdocs/expensereport/class/expensereport.class.php
23
 *       \ingroup    expensereport
24
 *       \brief      File to manage Expense Reports
25
 */
26
require_once DOL_DOCUMENT_ROOT .'/core/class/commonobject.class.php';
27
require_once DOL_DOCUMENT_ROOT .'/expensereport/class/expensereport_ik.class.php';
28
require_once DOL_DOCUMENT_ROOT .'/expensereport/class/expensereport_rule.class.php';
29
30
/**
31
 * Class to manage Trips and Expenses
32
 */
33
class ExpenseReport extends CommonObject
34
{
35
    var $element='expensereport';
36
    var $table_element='expensereport';
37
    var $table_element_line = 'expensereport_det';
38
    var $fk_element = 'fk_expensereport';
39
    var $picto = 'trip';
40
41
    var $lines=array();
42
43
    public $date_debut;
44
45
    public $date_fin;
46
47
    var $status;
48
    var $fk_statut;     // -- 0=draft, 2=validated (attente approb), 4=canceled, 5=approved, 6=payed, 99=denied
49
    var $fk_c_paiement;
50
    var $paid;
51
52
    var $user_author_infos;
53
    var $user_validator_infos;
54
55
    var $fk_typepayment;
56
	var $num_payment;
57
    var $code_paiement;
58
    var $code_statut;
59
60
    // ACTIONS
61
62
    // Create
63
    var $date_create;
64
    var $fk_user_author;    // Note fk_user_author is not the 'author' but the guy the expense report is for.
65
66
    // Update
67
	var $date_modif;
68
    var $fk_user_modif;
69
70
    // Refus
71
    var $date_refuse;
72
    var $detail_refuse;
73
    var $fk_user_refuse;
74
75
    // Annulation
76
    var $date_cancel;
77
    var $detail_cancel;
78
    var $fk_user_cancel;
79
80
    var $fk_user_validator;	// User that is defined to approve
81
82
    // Validation
83
    var $date_valid;		// User making validation
84
    var $fk_user_valid;
85
    var $user_valid_infos;
86
87
    // Approve
88
    var $date_approve;
89
    var $fk_user_approve;	// User that has approved
90
91
    // Paiement
92
    var $user_paid_infos;
93
94
    /*
95
        END ACTIONS
96
    */
97
98
   /**
99
	 * Draft
100
	 */
101
	const STATUS_DRAFT = 0;
102
103
	/**
104
	 * Validated (need to be paid)
105
	 */
106
	const STATUS_VALIDATED = 2;
107
108
	/**
109
	 * Classified approved
110
	 */
111
	const STATUS_APPROVED = 5;
112
113
	/**
114
	 * Classified refused
115
	 */
116
	const STATUS_REFUSED = 99;
117
118
	/**
119
	 * Classified paid.
120
	 */
121
	const STATUS_CLOSED = 6;
122
123
124
125
	/**
126
     *  Constructor
127
     *
128
     *  @param  DoliDB  $db     Handler acces base de donnees
129
     */
130
    function __construct($db)
131
    {
132
        $this->db = $db;
133
        $this->total_ht = 0;
134
        $this->total_ttc = 0;
135
        $this->total_tva = 0;
136
        $this->modepaymentid = 0;
137
138
        // List of language codes for status
139
        $this->statuts_short = array(0 => 'Draft', 2 => 'Validated', 4 => 'Canceled', 5 => 'Approved', 6 => 'Paid', 99 => 'Refused');
140
        $this->statuts = array(0 => 'Draft', 2 => 'ValidatedWaitingApproval', 4 => 'Canceled', 5 => 'Approved', 6 => 'Paid', 99 => 'Refused');
141
        $this->statuts_logo = array(0 => 'statut0', 2 => 'statut1', 4 => 'statut5', 5 => 'statut3', 6 => 'statut6', 99 => 'statut8');
142
143
        return 1;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
144
    }
145
146
    /**
147
     * Create object in database
148
     *
149
     * @param   User    $user   User that create
150
	 * @param   int     $notrigger   Disable triggers
151
     * @return  int             <0 if KO, >0 if OK
152
     */
153
    function create($user, $notrigger=0)
154
    {
155
        global $conf;
156
157
        $now = dol_now();
158
159
        $error = 0;
160
161
        // Check parameters
162
        if (empty($this->date_debut) || empty($this->date_fin))
163
        {
164
            $this->error='ErrorFieldRequired';
165
            return -1;
166
        }
167
168
        $fuserid = $this->fk_user_author;       // Note fk_user_author is not the 'author' but the guy the expense report is for.
169
        if (empty($fuserid)) $fuserid = $user->id;
170
171
        $this->db->begin();
172
173
        $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
174
        $sql.= "ref";
175
        $sql.= ",total_ht";
176
        $sql.= ",total_ttc";
177
        $sql.= ",total_tva";
178
        $sql.= ",date_debut";
179
        $sql.= ",date_fin";
180
        $sql.= ",date_create";
181
        $sql.= ",fk_user_author";
182
        $sql.= ",fk_user_validator";
183
        $sql.= ",fk_user_approve";
184
        $sql.= ",fk_user_modif";
185
        $sql.= ",fk_statut";
186
        $sql.= ",fk_c_paiement";
187
        $sql.= ",paid";
188
        $sql.= ",note_public";
189
        $sql.= ",note_private";
190
        $sql.= ",entity";
191
        $sql.= ") VALUES(";
192
        $sql.= "'(PROV)'";
193
        $sql.= ", ".$this->total_ht;
194
        $sql.= ", ".$this->total_ttc;
195
        $sql.= ", ".$this->total_tva;
196
        $sql.= ", '".$this->db->idate($this->date_debut)."'";
197
        $sql.= ", '".$this->db->idate($this->date_fin)."'";
198
        $sql.= ", '".$this->db->idate($now)."'";
199
        $sql.= ", ".$fuserid;
200
        $sql.= ", ".($this->fk_user_validator > 0 ? $this->fk_user_validator:"null");
201
        $sql.= ", ".($this->fk_user_approve > 0 ? $this->fk_user_approve:"null");
202
        $sql.= ", ".($this->fk_user_modif > 0 ? $this->fk_user_modif:"null");
203
        $sql.= ", ".($this->fk_statut > 1 ? $this->fk_statut:0);
204
        $sql.= ", ".($this->modepaymentid?$this->modepaymentid:"null");
205
        $sql.= ", 0";
206
        $sql.= ", ".($this->note_public?"'".$this->db->escape($this->note_public)."'":"null");
207
        $sql.= ", ".($this->note_private?"'".$this->db->escape($this->note_private)."'":"null");
208
        $sql.= ", ".$conf->entity;
209
        $sql.= ")";
210
211
        $result = $this->db->query($sql);
212
        if ($result)
213
        {
214
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
215
            $this->ref='(PROV'.$this->id.')';
216
217
            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".$this->id;
218
            $resql=$this->db->query($sql);
219
            if (!$resql) $error++;
220
221
            if (is_array($this->lines) && count($this->lines)>0)
222
            {
223
	            foreach ($this->lines as $i => $val)
224
	            {
225
	                $newndfline=new ExpenseReportLine($this->db);
226
	                $newndfline=$this->lines[$i];
227
	                $newndfline->fk_expensereport=$this->id;
228
	                if ($result >= 0)
229
	                {
230
	                    $result=$newndfline->insert();
231
	                }
232
	                if ($result < 0)
233
	                {
234
	                    $error++;
235
	                    break;
236
	                }
237
	            }
238
            }
239
240
            if (! $error)
241
            {
242
            	$result=$this->insertExtraFields();
243
           		if ($result < 0) $error++;
244
            }
245
246
            if (! $error)
247
            {
248
                $result=$this->update_price();
249
                if ($result > 0)
250
                {
251
252
					if (!$notrigger)
253
					{
254
						// Call trigger
255
						$result=$this->call_trigger('EXPENSE_REPORT_CREATE',$user);
256
257
						if ($result < 0) {
258
							$error++;
259
						}
260
						// End call triggers
261
					}
262
263
					if (empty($error))
264
					{
265
						$this->db->commit();
266
						return $this->id;
267
					}
268
					else
269
					{
270
						$this->db->rollback();
271
						return -4;
272
					}
273
                }
274
                else
275
                {
276
                    $this->db->rollback();
277
                    return -3;
278
                }
279
            }
280
            else
281
            {
282
                dol_syslog(get_class($this)."::create error ".$this->error, LOG_ERR);
283
                $this->db->rollback();
284
                return -2;
285
            }
286
        }
287
        else
288
        {
289
            $this->error=$this->db->lasterror()." sql=".$sql;
290
            $this->db->rollback();
291
            return -1;
292
        }
293
    }
294
295
296
    /**
297
     *	Load an object from its id and create a new one in database
298
     *
299
     *	@param		int			$fk_user_author		  Id of new user
300
     *	@return		int							      New id of clone
301
     */
302
    function createFromClone($fk_user_author)
303
    {
304
        global $user,$hookmanager;
305
306
        $error=0;
307
308
        if (empty($fk_user_author)) $fk_user_author = $user->id;
309
310
        $this->context['createfromclone'] = 'createfromclone';
311
312
        $this->db->begin();
313
314
        // get extrafields so they will be clone
315
        //foreach($this->lines as $line)
316
            //$line->fetch_optionals($line->rowid);
317
318
        // Load source object
319
        $objFrom = clone $this;
320
321
        $this->id=0;
322
        $this->ref = '';
323
        $this->status=0;
324
        $this->fk_statut=0;
325
326
        // Clear fields
327
        $this->fk_user_author     = $fk_user_author;     // Note fk_user_author is not the 'author' but the guy the expense report is for.
328
        $this->fk_user_valid      = '';
329
        $this->date_create  	  = '';
330
        $this->date_creation      = '';
331
        $this->date_validation    = '';
332
333
        // Create clone
334
        $result=$this->create($user);
335
        if ($result < 0) $error++;
336
337
        if (! $error)
338
        {
339
            // Hook of thirdparty module
340
            if (is_object($hookmanager))
341
            {
342
                $parameters=array('objFrom'=>$objFrom);
343
                $action='';
344
                $reshook=$hookmanager->executeHooks('createFrom',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
345
                if ($reshook < 0) $error++;
346
            }
347
        }
348
349
        unset($this->context['createfromclone']);
350
351
        // End
352
        if (! $error)
353
        {
354
            $this->db->commit();
355
            return $this->id;
356
        }
357
        else
358
        {
359
            $this->db->rollback();
360
            return -1;
361
        }
362
    }
363
364
365
    /**
366
     * update
367
     *
368
     * @param   User    $user                   User making change
369
	 * @param   int     $notrigger              Disable triggers
370
     * @param   User    $userofexpensereport    New user we want to have the expense report on.
371
     * @return  int                             <0 if KO, >0 if OK
372
     */
373
    function update($user, $notrigger = 0, $userofexpensereport=null)
374
    {
375
        global $langs;
376
377
		$error = 0;
378
		$this->db->begin();
379
380
        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
381
        $sql.= " total_ht = ".$this->total_ht;
382
        $sql.= " , total_ttc = ".$this->total_ttc;
383
        $sql.= " , total_tva = ".$this->total_tva;
384
        $sql.= " , date_debut = '".$this->db->idate($this->date_debut)."'";
385
        $sql.= " , date_fin = '".$this->db->idate($this->date_fin)."'";
386
        if ($userofexpensereport && is_object($userofexpensereport))
387
        {
388
            $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.
389
        }
390
        $sql.= " , fk_user_validator = ".($this->fk_user_validator > 0 ? $this->fk_user_validator:"null");
391
        $sql.= " , fk_user_valid = ".($this->fk_user_valid > 0 ? $this->fk_user_valid:"null");
392
        $sql.= " , fk_user_approve = ".($this->fk_user_approve > 0 ? $this->fk_user_approve:"null");
393
        $sql.= " , fk_user_modif = ".$user->id;
394
        $sql.= " , fk_statut = ".($this->fk_statut >= 0 ? $this->fk_statut:'0');
395
        $sql.= " , fk_c_paiement = ".($this->fk_c_paiement > 0 ? $this->fk_c_paiement:"null");
396
        $sql.= " , note_public = ".(!empty($this->note_public)?"'".$this->db->escape($this->note_public)."'":"''");
397
        $sql.= " , note_private = ".(!empty($this->note_private)?"'".$this->db->escape($this->note_private)."'":"''");
398
        $sql.= " , detail_refuse = ".(!empty($this->detail_refuse)?"'".$this->db->escape($this->detail_refuse)."'":"''");
399
        $sql.= " WHERE rowid = ".$this->id;
400
401
        dol_syslog(get_class($this)."::update sql=".$sql, LOG_DEBUG);
402
        $result = $this->db->query($sql);
403
        if ($result)
404
        {
405
            if (!$notrigger)
406
			{
407
				// Call trigger
408
				$result=$this->call_trigger('EXPENSE_REPORT_UPDATE',$user);
409
410
				if ($result < 0) {
411
					$error++;
412
				}
413
				// End call triggers
414
			}
415
416
			if (empty($error))
417
			{
418
				$this->db->commit();
419
				return 1;
420
			}
421
			else
422
			{
423
				$this->db->rollback();
424
				$this->error=$this->db->error();
425
				return -2;
426
			}
427
        }
428
        else
429
        {
430
			$this->db->rollback();
431
            $this->error=$this->db->error();
432
            return -1;
433
        }
434
    }
435
436
    /**
437
     *  Load an object from database
438
     *
439
     *  @param  int     $id     Id                      {@min 1}
440
     *  @param  string  $ref    Ref                     {@name ref}
441
     *  @return int             <0 if KO, >0 if OK
442
     */
443
    function fetch($id, $ref='')
444
    {
445
        global $conf;
446
447
        $sql = "SELECT d.rowid, d.ref, d.note_public, d.note_private,";                                 // DEFAULT
448
        $sql.= " d.detail_refuse, d.detail_cancel, d.fk_user_refuse, d.fk_user_cancel,";                // ACTIONS
449
        $sql.= " d.date_refuse, d.date_cancel,";                                                        // ACTIONS
450
        $sql.= " d.total_ht, d.total_ttc, d.total_tva,";                                                // TOTAUX (int)
451
        $sql.= " d.date_debut, d.date_fin, d.date_create, d.tms as date_modif, d.date_valid, d.date_approve,";	// DATES (datetime)
452
        $sql.= " d.fk_user_author, d.fk_user_modif, d.fk_user_validator,";
453
        $sql.= " d.fk_user_valid, d.fk_user_approve,";
454
        $sql.= " d.fk_statut as status, d.fk_c_paiement,";
455
        $sql.= " dp.libelle as libelle_paiement, dp.code as code_paiement";                             // INNER JOIN paiement
456
        $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as d";
457
        $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as dp ON d.fk_c_paiement = dp.id";
458
        if ($ref) $sql.= " WHERE d.ref = '".$this->db->escape($ref)."'";
459
        else $sql.= " WHERE d.rowid = ".$id;
460
        //$sql.= $restrict;
461
462
        dol_syslog(get_class($this)."::fetch sql=".$sql, LOG_DEBUG);
463
        $resql = $this->db->query($sql) ;
464
        if ($resql)
465
        {
466
            $obj = $this->db->fetch_object($resql);
467
            if ($obj)
468
            {
469
                $this->id           = $obj->rowid;
470
                $this->ref          = $obj->ref;
471
                $this->total_ht     = $obj->total_ht;
472
                $this->total_tva    = $obj->total_tva;
473
                $this->total_ttc    = $obj->total_ttc;
474
                $this->note_public  = $obj->note_public;
475
                $this->note_private = $obj->note_private;
476
                $this->detail_refuse = $obj->detail_refuse;
477
                $this->detail_cancel = $obj->detail_cancel;
478
479
                $this->date_debut       = $this->db->jdate($obj->date_debut);
480
                $this->date_fin         = $this->db->jdate($obj->date_fin);
481
                $this->date_valid       = $this->db->jdate($obj->date_valid);
482
                $this->date_approve     = $this->db->jdate($obj->date_approve);
483
                $this->date_create      = $this->db->jdate($obj->date_create);
484
                $this->date_modif       = $this->db->jdate($obj->date_modif);
485
                $this->date_refuse      = $this->db->jdate($obj->date_refuse);
486
                $this->date_cancel      = $this->db->jdate($obj->date_cancel);
487
488
                $this->fk_user_author           = $obj->fk_user_author;    // Note fk_user_author is not the 'author' but the guy the expense report is for.
489
                $this->fk_user_modif            = $obj->fk_user_modif;
490
                $this->fk_user_validator        = $obj->fk_user_validator;
491
                $this->fk_user_valid            = $obj->fk_user_valid;
492
                $this->fk_user_refuse           = $obj->fk_user_refuse;
493
                $this->fk_user_cancel           = $obj->fk_user_cancel;
494
                $this->fk_user_approve          = $obj->fk_user_approve;
495
496
                $user_author = new User($this->db);
497
                if ($this->fk_user_author > 0) $user_author->fetch($this->fk_user_author);
498
499
                $this->user_author_infos = dolGetFirstLastname($user_author->firstname, $user_author->lastname);
500
501
                $user_approver = new User($this->db);
502
                if ($this->fk_user_approve > 0) $user_approver->fetch($this->fk_user_approve);
503
                elseif ($this->fk_user_validator > 0) $user_approver->fetch($this->fk_user_validator);		// For backward compatibility
504
                $this->user_validator_infos = dolGetFirstLastname($user_approver->firstname, $user_approver->lastname);
505
506
                $this->fk_statut                = $obj->status;
507
                $this->status                   = $obj->status;
508
                $this->fk_c_paiement            = $obj->fk_c_paiement;
509
                $this->paid                     = $obj->paid;
510
511
                if ($this->fk_statut==5 || $this->fk_statut==6)
512
                {
513
                    $user_valid = new User($this->db);
514
                    if ($this->fk_user_valid > 0) $user_valid->fetch($this->fk_user_valid);
515
                    $this->user_valid_infos = dolGetFirstLastname($user_valid->firstname, $user_valid->lastname);
516
                }
517
518
                $this->libelle_statut   = $obj->libelle_statut;
519
                $this->libelle_paiement = $obj->libelle_paiement;
520
                $this->code_statut      = $obj->code_statut;
521
                $this->code_paiement    = $obj->code_paiement;
522
523
                $this->lines = array();
524
525
                $result=$this->fetch_lines();
526
527
                return $result;
528
            }
529
            else
530
            {
531
                return 0;
532
            }
533
        }
534
        else
535
        {
536
            $this->error=$this->db->lasterror();
537
            return -1;
538
        }
539
    }
540
541
    /**
542
     *    Classify the expense report as paid
543
     *
544
     *    @param    int     $id                 Id of expense report
545
     *    @param    user    $fuser              User making change
546
	 *    @param    int     $notrigger          Disable triggers
547
     *    @return   int                         <0 if KO, >0 if OK
548
     */
549
    function set_paid($id, $fuser, $notrigger = 0)
550
    {
551
		$error = 0;
552
		$this->db->begin();
553
554
        $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport";
555
        $sql.= " SET fk_statut = 6, paid=1";
556
        $sql.= " WHERE rowid = ".$id." AND fk_statut = 5";
557
558
        dol_syslog(get_class($this)."::set_paid sql=".$sql, LOG_DEBUG);
559
        $resql=$this->db->query($sql);
560
        if ($resql)
561
        {
562
            if ($this->db->affected_rows($resql))
563
            {
564
				if (!$notrigger)
565
				{
566
					// Call trigger
567
					$result=$this->call_trigger('EXPENSE_REPORT_PAID',$fuser);
568
569
					if ($result < 0) {
570
						$error++;
571
					}
572
					// End call triggers
573
				}
574
575
				if (empty($error))
576
				{
577
					$this->db->commit();
578
					return 1;
579
				}
580
				else
581
				{
582
					$this->db->rollback();
583
					$this->error=$this->db->error();
584
					return -2;
585
				}
586
            }
587
            else
588
            {
589
				$this->db->commit();
590
                return 0;
591
            }
592
        }
593
        else
594
        {
595
			$this->db->rollback();
596
            dol_print_error($this->db);
597
            return -1;
598
        }
599
    }
600
601
    /**
602
     *  Returns the label status
603
     *
604
     *  @param      int     $mode       0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
605
     *  @return     string              Label
606
     */
607
    function getLibStatut($mode=0)
608
    {
609
        return $this->LibStatut($this->status,$mode);
610
    }
611
612
    /**
613
     *  Returns the label of a statut
614
     *
615
     *  @param      int     $status     id statut
616
     *  @param      int     $mode       0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
617
     *  @return     string              Label
618
     */
619
    function LibStatut($status,$mode=0)
620
    {
621
        global $langs;
622
623
        if ($mode == 0)
624
            return $langs->transnoentities($this->statuts[$status]);
625
626
        if ($mode == 1)
627
            return $langs->transnoentities($this->statuts_short[$status]);
628
629
        if ($mode == 2)
630
            return img_picto($langs->transnoentities($this->statuts_short[$status]), $this->statuts_logo[$status]).' '.$langs->transnoentities($this->statuts_short[$status]);
631
632
        if ($mode == 3)
633
            return img_picto($langs->transnoentities($this->statuts_short[$status]), $this->statuts_logo[$status]);
634
635
        if ($mode == 4)
636
            return img_picto($langs->transnoentities($this->statuts_short[$status]),$this->statuts_logo[$status]).' '.$langs->transnoentities($this->statuts[$status]);
637
638
        if ($mode == 5)
639
            return '<span class="hideonsmartphone">'.$langs->transnoentities($this->statuts_short[$status]).' </span>'.img_picto($langs->transnoentities($this->statuts_short[$status]),$this->statuts_logo[$status]);
640
641
        if ($mode == 6)
642
            return $langs->transnoentities($this->statuts[$status]).' '.img_picto($langs->transnoentities($this->statuts_short[$status]),$this->statuts_logo[$status]);
643
    }
644
645
646
    /**
647
     *  Load information on object
648
     *
649
     *  @param  int     $id      Id of object
650
     *  @return void
651
     */
652
    function info($id)
653
    {
654
        global $conf;
655
656
        $sql = "SELECT f.rowid,";
657
        $sql.= " f.date_create as datec,";
658
        $sql.= " f.tms as date_modification,";
659
        $sql.= " f.date_valid as datev,";
660
        $sql.= " f.date_approve as datea,";
661
        //$sql.= " f.fk_user_author as fk_user_creation,";      // This is not user of creation but user the expense is for.
662
        $sql.= " f.fk_user_modif as fk_user_modification,";
663
        $sql.= " f.fk_user_valid,";
664
        $sql.= " f.fk_user_approve";
665
        $sql.= " FROM ".MAIN_DB_PREFIX."expensereport as f";
666
        $sql.= " WHERE f.rowid = ".$id;
667
        $sql.= " AND f.entity = ".$conf->entity;
668
669
        $resql = $this->db->query($sql);
670
        if ($resql)
671
        {
672
            if ($this->db->num_rows($resql))
673
            {
674
                $obj = $this->db->fetch_object($resql);
675
676
                $this->id                = $obj->rowid;
677
678
                $this->date_creation     = $this->db->jdate($obj->datec);
679
                $this->date_modification = $this->db->jdate($obj->date_modification);
680
                $this->date_validation   = $this->db->jdate($obj->datev);
681
                $this->date_approbation  = $this->db->jdate($obj->datea);
682
683
                $cuser = new User($this->db);
684
                $cuser->fetch($obj->fk_user_author);
685
                $this->user_creation     = $cuser;
686
687
                if ($obj->fk_user_creation)
688
                {
689
                    $cuser = new User($this->db);
690
                    $cuser->fetch($obj->fk_user_creation);
691
                    $this->user_creation     = $cuser;
692
                }
693
                if ($obj->fk_user_valid)
694
                {
695
                    $vuser = new User($this->db);
696
                    $vuser->fetch($obj->fk_user_valid);
697
                    $this->user_validation     = $vuser;
698
                }
699
                if ($obj->fk_user_modification)
700
                {
701
                    $muser = new User($this->db);
702
                    $muser->fetch($obj->fk_user_modification);
703
                    $this->user_modification   = $muser;
704
                }
705
                if ($obj->fk_user_approve)
706
                {
707
                    $auser = new User($this->db);
708
                    $auser->fetch($obj->fk_user_approve);
709
                    $this->user_approve   = $auser;
710
                }
711
712
            }
713
            $this->db->free($resql);
714
        }
715
        else
716
        {
717
            dol_print_error($this->db);
718
        }
719
    }
720
721
722
723
    /**
724
     *  Initialise an instance with random values.
725
     *  Used to build previews or test instances.
726
     *  id must be 0 if object instance is a specimen.
727
     *
728
     *  @return void
729
     */
730
    function initAsSpecimen()
731
    {
732
        global $user,$langs,$conf;
733
734
        $now=dol_now();
735
736
        // Initialise parametres
737
        $this->id=0;
738
        $this->ref = 'SPECIMEN';
739
        $this->specimen=1;
740
        $this->date_create = $now;
741
        $this->date_debut = $now;
742
        $this->date_fin = $now;
743
        $this->date_valid = $now;
744
        $this->date_approve = $now;
745
746
        $type_fees_id = 2;  // TF_TRIP
747
748
        $this->status = 5;
749
        $this->fk_statut = 5;
750
751
        $this->fk_user_author = $user->id;
752
        $this->fk_user_validator = $user->id;
753
        $this->fk_user_valid = $user->id;
754
        $this->fk_user_approve = $user->id;
755
756
        $this->note_private='Private note';
757
        $this->note_public='SPECIMEN';
758
        $nbp = 5;
759
        $xnbp = 0;
760
        while ($xnbp < $nbp)
761
        {
762
            $line=new ExpenseReportLine($this->db);
763
            $line->comments=$langs->trans("Comment")." ".$xnbp;
764
            $line->date=($now-3600*(1+$xnbp));
765
            $line->total_ht=100;
766
            $line->total_tva=20;
767
            $line->total_ttc=120;
768
            $line->qty=1;
769
            $line->vatrate=20;
770
            $line->value_unit=120;
771
            $line->fk_expensereport=0;
772
            $line->type_fees_code='TRA';
773
            $line->fk_c_type_fees=$type_fees_id;
774
775
            $line->projet_ref = 'ABC';
776
777
            $this->lines[$xnbp]=$line;
778
            $xnbp++;
779
780
            $this->total_ht+=$line->total_ht;
781
            $this->total_tva+=$line->total_tva;
782
            $this->total_ttc+=$line->total_ttc;
783
        }
784
    }
785
786
    /**
787
     * fetch_line_by_project
788
     *
789
     * @param   int     $projectid      Project id
790
     * @param   User    $user           User
791
     * @return  int                     <0 if KO, >0 if OK
792
     */
793
    function fetch_line_by_project($projectid,$user='')
794
    {
795
        global $conf,$db,$langs;
796
797
        $langs->load('trips');
798
799
        if ($user->rights->expensereport->lire) {
800
801
            $sql = "SELECT de.fk_expensereport, de.date, de.comments, de.total_ht, de.total_ttc";
802
            $sql.= " FROM ".MAIN_DB_PREFIX."expensereport_det as de";
803
            $sql.= " WHERE de.fk_projet = ".$projectid;
804
805
            dol_syslog(get_class($this)."::fetch sql=".$sql, LOG_DEBUG);
806
            $result = $db->query($sql) ;
807
            if ($result)
808
            {
809
                $num = $db->num_rows($result);
810
                $i = 0;
811
                $total_HT = 0;
812
                $total_TTC = 0;
813
814
                while ($i < $num)
815
                {
816
817
                    $objp = $db->fetch_object($result);
818
819
                    $sql2 = "SELECT d.rowid, d.fk_user_author, d.ref, d.fk_statut";
820
                    $sql2.= " FROM ".MAIN_DB_PREFIX."expensereport as d";
821
                    $sql2.= " WHERE d.rowid = '".$objp->fk_expensereport."'";
822
823
                    $result2 = $db->query($sql2);
824
                    $obj = $db->fetch_object($result2);
825
826
                    $objp->fk_user_author = $obj->fk_user_author;
827
                    $objp->ref = $obj->ref;
828
                    $objp->fk_c_expensereport_status = $obj->fk_statut;
829
                    $objp->rowid = $obj->rowid;
830
831
                    $total_HT = $total_HT + $objp->total_ht;
832
                    $total_TTC = $total_TTC + $objp->total_ttc;
833
                    $author = new User($db);
834
                    $author->fetch($objp->fk_user_author);
835
836
                    print '<tr>';
837
                    print '<td><a href="'.DOL_URL_ROOT.'/expensereport/card.php?id='.$objp->rowid.'">'.$objp->ref_num.'</a></td>';
838
                    print '<td align="center">'.dol_print_date($objp->date,'day').'</td>';
839
                    print '<td>'.$author->getNomUrl(1).'</td>';
840
                    print '<td>'.$objp->comments.'</td>';
841
                    print '<td align="right">'.price($objp->total_ht).'</td>';
842
                    print '<td align="right">'.price($objp->total_ttc).'</td>';
843
                    print '<td align="right">';
844
845
                    switch($objp->fk_c_expensereport_status) {
846
                        case 4:
847
                            print img_picto($langs->trans('StatusOrderCanceled'),'statut5');
848
                            break;
849
                        case 1:
850
                            print $langs->trans('Draft').' '.img_picto($langs->trans('Draft'),'statut0');
851
                            break;
852
                        case 2:
853
                            print $langs->trans('TripForValid').' '.img_picto($langs->trans('TripForValid'),'statut3');
854
                            break;
855
                        case 5:
856
                            print $langs->trans('TripForPaid').' '.img_picto($langs->trans('TripForPaid'),'statut3');
857
                            break;
858
                        case 6:
859
                            print $langs->trans('TripPaid').' '.img_picto($langs->trans('TripPaid'),'statut4');
860
                            break;
861
                    }
862
                    /*
863
                     if ($status==4) return img_picto($langs->trans('StatusOrderCanceled'),'statut5');
864
                    if ($status==1) return img_picto($langs->trans('StatusOrderDraft'),'statut0');
865
                    if ($status==2) return img_picto($langs->trans('StatusOrderValidated'),'statut1');
866
                    if ($status==2) return img_picto($langs->trans('StatusOrderOnProcess'),'statut3');
867
                    if ($status==5) return img_picto($langs->trans('StatusOrderToBill'),'statut4');
868
                    if ($status==6) return img_picto($langs->trans('StatusOrderOnProcess'),'statut6');
869
                    */
870
                    print '</td>';
871
                    print '</tr>';
872
873
                    $i++;
874
                }
875
876
                print '<tr class="liste_total"><td colspan="4">'.$langs->trans("Number").': '.$i.'</td>';
877
                print '<td align="right" width="100">'.$langs->trans("TotalHT").' : '.price($total_HT).'</td>';
878
                print '<td align="right" width="100">'.$langs->trans("TotalTTC").' : '.price($total_TTC).'</td>';
879
                print '<td>&nbsp;</td>';
880
                print '</tr>';
881
882
            }
883
            else
884
            {
885
                $this->error=$db->lasterror();
886
                return -1;
887
            }
888
        }
889
890
    }
891
892
    /**
893
     * recalculer
894
     * TODO Replace this with call to update_price if not already done
895
     *
896
     * @param   int         $id     Id of expense report
897
     * @return  int                 <0 if KO, >0 if OK
898
     */
899
    function recalculer($id)
900
    {
901
        $sql = 'SELECT tt.total_ht, tt.total_ttc, tt.total_tva';
902
        $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as tt';
903
        $sql.= ' WHERE tt.'.$this->fk_element.' = '.$id;
904
905
        $total_ht = 0; $total_tva = 0; $total_ttc = 0;
906
907
        $result = $this->db->query($sql);
908
        if($result)
909
        {
910
            $num = $this->db->num_rows($result);
911
            $i = 0;
912
            while ($i < $num):
913
            $objp = $this->db->fetch_object($result);
914
            $total_ht+=$objp->total_ht;
915
            $total_tva+=$objp->total_tva;
916
            $i++;
917
            endwhile;
918
919
            $total_ttc = $total_ht + $total_tva;
920
            $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
921
            $sql.= " total_ht = ".$total_ht;
922
            $sql.= " , total_ttc = ".$total_ttc;
923
            $sql.= " , total_tva = ".$total_tva;
924
            $sql.= " WHERE rowid = ".$id;
925
            $result = $this->db->query($sql);
926
            if($result):
927
            $this->db->free($result);
928
            return 1;
929
            else:
930
            $this->error=$this->db->lasterror();
931
            dol_syslog(get_class($this)."::recalculer: Error ".$this->error,LOG_ERR);
932
            return -3;
933
            endif;
934
        }
935
        else
936
        {
937
            $this->error=$this->db->lasterror();
938
            dol_syslog(get_class($this)."::recalculer: Error ".$this->error,LOG_ERR);
939
            return -3;
940
        }
941
    }
942
943
    /**
944
     * fetch_lines
945
     *
946
     * @return  int     <0 if OK, >0 if KO
947
     */
948
    function fetch_lines()
949
    {
950
        $this->lines=array();
951
952
        $sql = ' SELECT de.rowid, de.comments, de.qty, de.value_unit, de.date, de.rang,';
953
        $sql.= ' de.'.$this->fk_element.', de.fk_c_type_fees, de.fk_c_exp_tax_cat, de.fk_projet, de.tva_tx,';
954
        $sql.= ' de.total_ht, de.total_tva, de.total_ttc,';
955
        $sql.= ' ctf.code as code_type_fees, ctf.label as libelle_type_fees,';
956
        $sql.= ' p.ref as ref_projet, p.title as title_projet';
957
        $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as de';
958
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_type_fees as ctf ON de.fk_c_type_fees = ctf.id';
959
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as p ON de.fk_projet = p.rowid';
960
        $sql.= ' WHERE de.'.$this->fk_element.' = '.$this->id;
961
        if (! empty($conf->global->EXPENSEREPORT_LINES_SORTED_BY_ROWID))
0 ignored issues
show
Bug introduced by
The variable $conf does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
962
        {
963
        	$sql.= ' ORDER BY de.rang ASC, de.rowid ASC';
964
        }
965
        else
966
        {
967
        	$sql.= ' ORDER BY de.rang ASC, de.date ASC';
968
        }
969
970
        $resql = $this->db->query($sql);
971
        if ($resql)
972
        {
973
            $num = $this->db->num_rows($resql);
974
            $i = 0;
975
            while ($i < $num)
976
            {
977
                $objp = $this->db->fetch_object($resql);
978
979
                $deplig = new ExpenseReportLine($this->db);
980
981
                $deplig->rowid          = $objp->rowid;
982
                $deplig->id             = $objp->id;
983
                $deplig->comments       = $objp->comments;
984
                $deplig->qty            = $objp->qty;
985
                $deplig->value_unit     = $objp->value_unit;
986
                $deplig->date           = $objp->date;
987
                $deplig->dates          = $this->db->jdate($objp->date);
988
989
                $deplig->fk_expensereport = $objp->fk_expensereport;
990
                $deplig->fk_c_type_fees   = $objp->fk_c_type_fees;
991
                $deplig->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
992
                $deplig->fk_projet        = $objp->fk_projet;
993
994
                $deplig->total_ht         = $objp->total_ht;
995
                $deplig->total_tva        = $objp->total_tva;
996
                $deplig->total_ttc        = $objp->total_ttc;
997
998
                $deplig->type_fees_code     = empty($objp->code_type_fees)?'TF_OTHER':$objp->code_type_fees;
999
                $deplig->type_fees_libelle  = $objp->libelle_type_fees;
1000
				$deplig->tva_tx			    = $objp->tva_tx;
1001
                $deplig->vatrate            = $objp->tva_tx;
1002
                $deplig->projet_ref         = $objp->ref_projet;
1003
                $deplig->projet_title       = $objp->title_projet;
1004
1005
                $deplig->rang               = $objp->rang;
1006
1007
                $this->lines[$i] = $deplig;
1008
1009
                $i++;
1010
            }
1011
            $this->db->free($resql);
1012
            return 1;
1013
        }
1014
        else
1015
        {
1016
            $this->error=$this->db->lasterror();
1017
            dol_syslog(get_class($this)."::fetch_lines: Error ".$this->error, LOG_ERR);
1018
            return -3;
1019
        }
1020
    }
1021
1022
1023
    /**
1024
     * delete
1025
     *
1026
     * @param   User    $fuser      User that delete
1027
     * @return  int                 <0 if KO, >0 if OK
1028
     */
1029
    function delete(User $fuser=null)
1030
    {
1031
        global $user,$langs,$conf;
1032
1033
        if (! $rowid) $rowid=$this->id;
0 ignored issues
show
Bug introduced by
The variable $rowid seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
1034
1035
        $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element_line.' WHERE '.$this->fk_element.' = '.$rowid;
0 ignored issues
show
Bug introduced by
The variable $rowid does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1036
        if ($this->db->query($sql))
1037
        {
1038
            $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid = '.$rowid;
1039
            $resql=$this->db->query($sql);
1040
            if ($resql)
1041
            {
1042
                $this->db->commit();
1043
                return 1;
1044
            }
1045
            else
1046
            {
1047
                $this->error=$this->db->error()." sql=".$sql;
1048
                dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR);
1049
                $this->db->rollback();
1050
                return -6;
1051
            }
1052
        }
1053
        else
1054
        {
1055
            $this->error=$this->db->error()." sql=".$sql;
1056
            dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR);
1057
            $this->db->rollback();
1058
            return -4;
1059
        }
1060
    }
1061
1062
    /**
1063
     * Set to status validate
1064
     *
1065
     * @param   User    $fuser      User
1066
	 * @param   int     $notrigger  Disable triggers
1067
     * @return  int                 <0 if KO, 0 if nothing done, >0 if OK
1068
     */
1069
    function setValidate($fuser, $notrigger=0)
1070
    {
1071
        global $conf,$langs,$user;
1072
1073
		$error = 0;
1074
		$now = dol_now();
1075
1076
        // Protection
1077
        if ($this->statut == self::STATUS_VALIDATED)
1078
        {
1079
            dol_syslog(get_class($this)."::valid action abandonned: already validated", LOG_WARNING);
1080
            return 0;
1081
        }
1082
1083
        $this->date_valid = $now;		// Required for the getNextNum later.
1084
1085
		// Define new ref
1086
        if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life
1087
        {
1088
            $num = $this->getNextNumRef();
1089
        }
1090
        else
1091
		{
1092
            $num = $this->ref;
1093
        }
1094
        if (empty($num) || $num < 0) return -1;
1095
1096
        $this->newref = $num;
1097
1098
		$this->db->begin();
1099
1100
        // Validate
1101
        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1102
        $sql.= " SET ref = '".$num."',";
1103
        $sql.= " fk_statut = ".self::STATUS_VALIDATED.",";
1104
        $sql.= " date_valid='".$this->db->idate($this->date_valid)."',";
1105
        $sql.= " fk_user_valid = ".$user->id;
1106
        $sql.= " WHERE rowid = ".$this->id;
1107
1108
        $resql=$this->db->query($sql);
1109
        if ($resql)
1110
        {
1111
			if (!$notrigger)
1112
			{
1113
				// Call trigger
1114
				$result=$this->call_trigger('EXPENSE_REPORT_VALIDATE',$fuser);
1115
1116
				if ($result < 0) {
1117
					$error++;
1118
				}
1119
				// End call triggers
1120
			}
1121
1122
			if (! $error)
1123
			{
1124
			    $this->oldref = $this->ref;
1125
1126
			    // Rename directory if dir was a temporary ref
1127
			    if (preg_match('/^[\(]?PROV/i', $this->ref))
1128
			    {
1129
			    	require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1130
1131
			    	// On renomme repertoire ($this->ref = ancienne ref, $num = nouvelle ref)
1132
					// in order not to lose the attachments
1133
					$oldref = dol_sanitizeFileName($this->ref);
1134
					$newref = dol_sanitizeFileName($num);
1135
					$dirsource = $conf->expensereport->dir_output.'/'.$oldref;
1136
					$dirdest = $conf->expensereport->dir_output.'/'.$newref;
1137
					if (file_exists($dirsource))
1138
					{
1139
					    dol_syslog(get_class($this)."::valid() rename dir ".$dirsource." into ".$dirdest);
1140
1141
					    if (@rename($dirsource, $dirdest))
1142
					    {
1143
					        dol_syslog("Rename ok");
1144
					        // Rename docs starting with $oldref with $newref
1145
					        $listoffiles=dol_dir_list($conf->expensereport->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref,'/'));
1146
					        foreach($listoffiles as $fileentry)
1147
					        {
1148
					        	$dirsource=$fileentry['name'];
1149
					        	$dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource);
1150
					        	$dirsource=$fileentry['path'].'/'.$dirsource;
1151
					        	$dirdest=$fileentry['path'].'/'.$dirdest;
1152
					        	@rename($dirsource, $dirdest);
1153
					        }
1154
					    }
1155
					}
1156
				}
1157
			}
1158
1159
			// Set new ref and current status
1160
			if (! $error)
1161
			{
1162
			    $this->ref = $num;
1163
			    $this->statut = self::STATUS_VALIDATED;
1164
			}
1165
1166
			if (empty($error))
1167
			{
1168
				$this->db->commit();
1169
				return 1;
1170
			}
1171
			else
1172
			{
1173
				$this->db->rollback();
1174
				$this->error=$this->db->error();
1175
				return -2;
1176
			}
1177
        }
1178
        else
1179
        {
1180
			$this->db->rollback();
1181
            $this->error=$this->db->lasterror();
1182
            return -1;
1183
        }
1184
    }
1185
1186
    /**
1187
     * set_save_from_refuse
1188
     *
1189
     * @param   User    $fuser      User
1190
     * @return  int                 <0 if KO, >0 if OK
1191
     */
1192
    function set_save_from_refuse($fuser)
1193
    {
1194
        global $conf,$langs;
1195
1196
        // Sélection de la date de début de la NDF
1197
        $sql = 'SELECT date_debut';
1198
        $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
1199
        $sql.= ' WHERE rowid = '.$this->id;
1200
1201
        $result = $this->db->query($sql);
1202
1203
        $objp = $this->db->fetch_object($result);
1204
1205
        $this->date_debut = $this->db->jdate($objp->date_debut);
1206
1207
        if ($this->fk_statut != 2)
1208
        {
1209
            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1210
            $sql.= " SET fk_statut = 2";
1211
            $sql.= ' WHERE rowid = '.$this->id;
1212
1213
            dol_syslog(get_class($this)."::set_save_from_refuse sql=".$sql, LOG_DEBUG);
1214
1215
            if ($this->db->query($sql))
1216
            {
1217
                return 1;
1218
            }
1219
            else
1220
            {
1221
                $this->error=$this->db->lasterror();
1222
                return -1;
1223
            }
1224
        }
1225
        else
1226
        {
1227
            dol_syslog(get_class($this)."::set_save_from_refuse expensereport already with save status", LOG_WARNING);
1228
        }
1229
    }
1230
1231
    /**
1232
     * Set status to approved
1233
     *
1234
     * @param   User    $fuser      User
1235
	 * @param   int     $notrigger  Disable triggers
1236
     * @return  int                 <0 if KO, 0 if nothing done, >0 if OK
1237
     */
1238
    function setApproved($fuser, $notrigger=0)
1239
    {
1240
        $now=dol_now();
1241
		$error = 0;
1242
1243
        // date approval
1244
        $this->date_approve = $now;
1245
        if ($this->fk_statut != 5)
1246
        {
1247
			$this->db->begin();
1248
1249
            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1250
            $sql.= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = 5, fk_user_approve = ".$fuser->id.",";
1251
            $sql.= " date_approve='".$this->db->idate($this->date_approve)."'";
1252
            $sql.= ' WHERE rowid = '.$this->id;
1253
            if ($this->db->query($sql))
1254
            {
1255
                if (!$notrigger)
1256
				{
1257
					// Call trigger
1258
					$result=$this->call_trigger('EXPENSE_REPORT_APPROVE',$fuser);
1259
1260
					if ($result < 0) {
1261
						$error++;
1262
					}
1263
					// End call triggers
1264
				}
1265
1266
				if (empty($error))
1267
				{
1268
					$this->db->commit();
1269
					return 1;
1270
				}
1271
				else
1272
				{
1273
					$this->db->rollback();
1274
					$this->error=$this->db->error();
1275
					return -2;
1276
				}
1277
            }
1278
            else
1279
            {
1280
				$this->db->rollback();
1281
                $this->error=$this->db->lasterror();
1282
                return -1;
1283
            }
1284
        }
1285
        else
1286
        {
1287
            dol_syslog(get_class($this)."::setApproved expensereport already with approve status", LOG_WARNING);
1288
        }
1289
1290
        return 0;
1291
    }
1292
1293
    /**
1294
     * setDeny
1295
     *
1296
     * @param User      $fuser      User
1297
     * @param Details   $details    Details
1298
	 * @param int       $notrigger  Disable triggers
1299
     */
1300
    function setDeny($fuser,$details,$notrigger=0)
1301
    {
1302
        $now = dol_now();
1303
		$error = 0;
1304
1305
        // date de refus
1306
        if ($this->fk_statut != 99)
1307
        {
1308
            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1309
            $sql.= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = 99, fk_user_refuse = ".$fuser->id.",";
1310
            $sql.= " date_refuse='".$this->db->idate($now)."',";
1311
            $sql.= " detail_refuse='".$this->db->escape($details)."',";
1312
            $sql.= " fk_user_approve = NULL";
1313
            $sql.= ' WHERE rowid = '.$this->id;
1314
            if ($this->db->query($sql))
1315
            {
1316
                $this->fk_statut = 99;
1317
                $this->fk_user_refuse = $fuser->id;
1318
                $this->detail_refuse = $details;
1319
                $this->date_refuse = $now;
1320
1321
				if (!$notrigger)
1322
				{
1323
					// Call trigger
1324
					$result=$this->call_trigger('EXPENSE_REPORT_DENY',$fuser);
1325
1326
					if ($result < 0) {
1327
						$error++;
1328
					}
1329
					// End call triggers
1330
				}
1331
1332
				if (empty($error))
1333
				{
1334
					$this->db->commit();
1335
					return 1;
1336
				}
1337
				else
1338
				{
1339
					$this->db->rollback();
1340
					$this->error=$this->db->error();
1341
					return -2;
1342
				}
1343
            }
1344
            else
1345
            {
1346
				$this->db->rollback();
1347
                $this->error=$this->db->lasterror();
1348
                return -1;
1349
            }
1350
        }
1351
        else
1352
        {
1353
            dol_syslog(get_class($this)."::setDeny expensereport already with refuse status", LOG_WARNING);
1354
        }
1355
    }
1356
1357
    /**
1358
     * set_unpaid
1359
     *
1360
     * @param   User    $fuser      User
1361
	 * @param   int     $notrigger  Disable triggers
1362
     * @return  int                 <0 if KO, >0 if OK
1363
     */
1364
    function set_unpaid($fuser, $notrigger = 0)
1365
    {
1366
		$error = 0;
1367
1368
        if ($this->fk_c_deplacement_statuts != 5)
1369
        {
1370
			$this->db->begin();
1371
1372
            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1373
            $sql.= " SET fk_statut = 5";
1374
            $sql.= ' WHERE rowid = '.$this->id;
1375
1376
            dol_syslog(get_class($this)."::set_unpaid sql=".$sql, LOG_DEBUG);
1377
1378
			if ($this->db->query($sql))
1379
			{
1380
				if (!$notrigger)
1381
				{
1382
					// Call trigger
1383
					$result=$this->call_trigger('EXPENSE_REPORT_UNPAID',$fuser);
1384
1385
					if ($result < 0) {
1386
						$error++;
1387
					}
1388
					// End call triggers
1389
				}
1390
1391
				if (empty($error))
1392
				{
1393
					$this->db->commit();
1394
					return 1;
1395
				}
1396
				else
1397
				{
1398
					$this->db->rollback();
1399
					$this->error=$this->db->error();
1400
					return -2;
1401
				}
1402
			}
1403
			else
1404
			{
1405
				$this->db->rollback();
1406
				$this->error=$this->db->error();
1407
				return -1;
1408
			}
1409
        }
1410
        else
1411
        {
1412
            dol_syslog(get_class($this)."::set_unpaid expensereport already with unpaid status", LOG_WARNING);
1413
        }
1414
    }
1415
1416
    /**
1417
     * set_cancel
1418
     *
1419
     * @param   User    $fuser      User
1420
     * @param   string  $detail     Detail
1421
	 * @param   int     $notrigger  Disable triggers
1422
     * @return  int                 <0 if KO, >0 if OK
1423
     */
1424
    function set_cancel($fuser,$detail, $notrigger=0)
1425
    {
1426
		$error = 0;
1427
        $this->date_cancel = $this->db->idate(gmmktime());
1428
        if ($this->fk_statut != 4)
1429
        {
1430
			$this->db->begin();
1431
1432
            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1433
            $sql.= " SET fk_statut = 4, fk_user_cancel = ".$fuser->id;
1434
            $sql.= ", date_cancel='".$this->db->idate($this->date_cancel)."'";
1435
            $sql.= " ,detail_cancel='".$this->db->escape($detail)."'";
1436
            $sql.= ' WHERE rowid = '.$this->id;
1437
1438
            dol_syslog(get_class($this)."::set_cancel sql=".$sql, LOG_DEBUG);
1439
1440
            if ($this->db->query($sql))
1441
            {
1442
				if (!$notrigger)
1443
				{
1444
					// Call trigger
1445
					$result=$this->call_trigger('EXPENSE_REPORT_CANCEL',$fuser);
1446
1447
					if ($result < 0) {
1448
						$error++;
1449
					}
1450
					// End call triggers
1451
				}
1452
1453
				if (empty($error))
1454
				{
1455
					$this->db->commit();
1456
					return 1;
1457
				}
1458
				else
1459
				{
1460
					$this->db->rollback();
1461
					$this->error=$this->db->error();
1462
					return -2;
1463
				}
1464
            }
1465
            else
1466
            {
1467
				$this->db->rollback();
1468
                $this->error=$this->db->error();
1469
                return -1;
1470
            }
1471
        }
1472
        else
1473
        {
1474
            dol_syslog(get_class($this)."::set_cancel expensereport already with cancel status", LOG_WARNING);
1475
        }
1476
    }
1477
1478
    /**
1479
     * Return next reference of expense report not already used
1480
     *
1481
     * @return    string            free ref
1482
     */
1483
    function getNextNumRef()
1484
    {
1485
        global $langs, $conf;
1486
        $langs->load("trips");
1487
1488
        if (! empty($conf->global->EXPENSEREPORT_ADDON))
1489
        {
1490
        	$mybool=false;
1491
1492
        	$file = $conf->global->EXPENSEREPORT_ADDON.".php";
1493
			$classname = $conf->global->EXPENSEREPORT_ADDON;
1494
1495
			// Include file with class
1496
			$dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']);
1497
			foreach ($dirmodels as $reldir)
1498
			{
1499
                $dir = dol_buildpath($reldir."core/modules/expensereport/");
1500
1501
                // Load file with numbering class (if found)
1502
                $mybool|=@include_once $dir.$file;
1503
            }
1504
1505
            if (! $mybool)
1506
            {
1507
                dol_print_error('',"Failed to include file ".$file);
1508
                return '';
1509
            }
1510
1511
            $obj = new $classname();
1512
            $numref = $obj->getNextValue($this);
1513
1514
            if ($numref != "")
1515
            {
1516
            	return $numref;
1517
            }
1518
            else
1519
			{
1520
				$this->error=$obj->error;
1521
				$this->errors=$obj->errors;
1522
            	//dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1523
            	return -1;
1524
            }
1525
        }
1526
        else
1527
        {
1528
            $this->error = "Error_EXPENSEREPORT_ADDON_NotDefined";
1529
            return -2;
1530
        }
1531
    }
1532
1533
    /**
1534
     *  Return clicable name (with picto eventually)
1535
     *
1536
     *	@param		int		$withpicto					0=No picto, 1=Include picto into link, 2=Only picto
1537
     *	@param		int		$max						Max length of shown ref
1538
     *	@param		int		$short						1=Return just URL
1539
     *	@param		string	$moretitle					Add more text to title tooltip
1540
     *	@param		int		$notooltip					1=Disable tooltip
1541
     *  @param  	int     $save_lastsearch_value    	-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
1542
     *	@return		string								String with URL
1543
     */
1544
    function getNomUrl($withpicto=0, $max=0, $short=0, $moretitle='', $notooltip=0, $save_lastsearch_value=-1)
1545
    {
1546
        global $langs, $conf;
1547
1548
        $result='';
1549
1550
        $url = DOL_URL_ROOT.'/expensereport/card.php?id='.$this->id;
1551
1552
        if ($short) return $url;
1553
1554
        $label = '<u>' . $langs->trans("ShowExpenseReport") . '</u>';
1555
        if (! empty($this->ref))
1556
            $label .= '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
1557
        if (! empty($this->total_ht))
1558
            $label.= '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
1559
        if (! empty($this->total_tva))
1560
            $label.= '<br><b>' . $langs->trans('VAT') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
1561
        if (! empty($this->total_ttc))
1562
            $label.= '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
1563
        if ($moretitle) $label.=' - '.$moretitle;
1564
1565
        //if ($option != 'nolink')
1566
        //{
1567
        // Add param to save lastsearch_values or not
1568
        	$add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
1569
        	if ($save_lastsearch_value == -1 && preg_match('/list\.php/',$_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
1570
        	if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
1571
        //}
1572
1573
        $ref=$this->ref;
1574
        if (empty($ref)) $ref=$this->id;
1575
1576
        $linkclose='';
1577
        if (empty($notooltip))
1578
        {
1579
            if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
1580
            {
1581
                $label=$langs->trans("ShowExpenseReport");
1582
                $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
1583
            }
1584
            $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
1585
            $linkclose.=' class="classfortooltip"';
1586
        }
1587
1588
        $linkstart = '<a href="'.$url.'"';
1589
        $linkstart.=$linkclose.'>';
1590
        $linkend='</a>';
1591
1592
        $result .= $linkstart;
1593
        if ($withpicto) $result.=img_object(($notooltip?'':$label), $this->picto, ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
1594
        if ($withpicto != 2) $result.=($max?dol_trunc($ref,$max):$ref);
1595
        $result .= $linkend;
1596
1597
        return $result;
1598
    }
1599
1600
    /**
1601
     *  Update total of an expense report when you add a line.
1602
     *
1603
     *  @param    string    $ligne_total_ht    Amount without taxes
1604
     *  @param    string    $ligne_total_tva    Amount of all taxes
1605
     *  @return    void
1606
     */
1607
    function update_totaux_add($ligne_total_ht,$ligne_total_tva)
1608
    {
1609
        $this->total_ht = $this->total_ht + $ligne_total_ht;
1610
        $this->total_tva = $this->total_tva + $ligne_total_tva;
1611
        $this->total_ttc = $this->total_ht + $this->total_tva;
1612
1613
        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
1614
        $sql.= " total_ht = ".$this->total_ht;
1615
        $sql.= " , total_ttc = ".$this->total_ttc;
1616
        $sql.= " , total_tva = ".$this->total_tva;
1617
        $sql.= " WHERE rowid = ".$this->id;
1618
1619
        $result = $this->db->query($sql);
1620
        if ($result):
1621
        return 1;
1622
        else:
1623
        $this->error=$this->db->error();
1624
        return -1;
1625
        endif;
1626
    }
1627
1628
    /**
1629
     *  Update total of an expense report when you delete a line.
1630
     *
1631
     *  @param    string    $ligne_total_ht    Amount without taxes
1632
     *  @param    string    $ligne_total_tva    Amount of all taxes
1633
     *  @return    void
1634
     */
1635
    function update_totaux_del($ligne_total_ht,$ligne_total_tva)
1636
    {
1637
        $this->total_ht = $this->total_ht - $ligne_total_ht;
1638
        $this->total_tva = $this->total_tva - $ligne_total_tva;
1639
        $this->total_ttc = $this->total_ht + $this->total_tva;
1640
1641
        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
1642
        $sql.= " total_ht = ".$this->total_ht;
1643
        $sql.= " , total_ttc = ".$this->total_ttc;
1644
        $sql.= " , total_tva = ".$this->total_tva;
1645
        $sql.= " WHERE rowid = ".$this->id;
1646
1647
        $result = $this->db->query($sql);
1648
        if ($result):
1649
        return 1;
1650
        else:
1651
        $this->error=$this->db->error();
1652
        return -1;
1653
        endif;
1654
    }
1655
1656
	/**
1657
	 * addline
1658
	 *
1659
	 * @param    real        $qty                Qty
1660
	 * @param    double      $up                 Value init
1661
	 * @param    int         $fk_c_type_fees     Type payment
1662
	 * @param    double      $vatrate            Vat rate
1663
	 * @param    string      $date               Date
1664
	 * @param    string      $comments           Description
1665
	 * @param    int         $fk_project         Project id
1666
	 * @param    int         $fk_c_exp_tax_cat   Car category id
1667
	 * @param    int         $type               Type line
1668
	 * @return   int                             <0 if KO, >0 if OK
1669
	 */
1670
	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)
1671
	{
1672
		global $conf,$langs;
1673
1674
        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);
1675
1676
		if (empty($qty)) $qty = 0;
1677
		if (empty($fk_c_type_fees) || $fk_c_type_fees < 0) $fk_c_type_fees = 0;
1678
		if (empty($fk_c_exp_tax_cat) || $fk_c_exp_tax_cat < 0) $fk_c_exp_tax_cat = 0;
1679
		if (empty($vatrate) || $vatrate < 0) $vatrate = 0;
1680
		if (empty($date)) $date = '';
1681
		if (empty($fk_project)) $fk_project = 0;
1682
1683
		$qty = price2num($qty);
1684
		$vatrate = price2num($vatrate);
1685
		$up = price2num($up);
1686
1687
		if ($this->fk_statut == self::STATUS_DRAFT)
1688
        {
1689
			$this->db->begin();
1690
1691
			$this->line = new ExpenseReportLine($this->db);
1692
1693
			if (preg_match('/\((.*)\)/', $vatrate, $reg))
1694
			{
1695
				$vat_src_code = $reg[1];
1696
				$vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate);    // Remove code into vatrate.
1697
			}
1698
			$vatrate = preg_replace('/\*/','',$vatrate);
1699
1700
			$seller = '';  // seller is unknown
1701
			$tmp = calcul_price_total($qty, $up, 0, $vatrate, 0, 0, 0, 'TTC', 0, $type, $seller);
1702
1703
			$this->line->value_unit = $up;
1704
			$this->line->vatrate = price2num($vatrate);
1705
			$this->line->total_ttc = $tmp[2];
1706
			$this->line->total_ht = $tmp[0];
1707
			$this->line->total_tva = $tmp[1];
1708
1709
			$this->line->fk_expensereport = $this->id;
1710
			$this->line->qty = $qty;
1711
			$this->line->date = $date;
1712
			$this->line->fk_c_type_fees = $fk_c_type_fees;
1713
			$this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
1714
			$this->line->comments = $comments;
1715
			$this->line->fk_projet = $fk_project;
1716
1717
			$this->applyOffset();
1718
			$this->checkRules($type, $seller);
1719
1720
			$result=$this->line->insert(0, true);
1721
            if ($result > 0)
1722
            {
1723
                $result=$this->update_price();	// This method is designed to add line from user input so total calculation must be done using 'auto' mode.
1724
                if ($result > 0)
1725
                {
1726
                    $this->db->commit();
1727
                    return $this->line->rowid;
1728
                }
1729
                else
1730
                {
1731
                    $this->db->rollback();
1732
                    return -1;
1733
                }
1734
            }
1735
            else
1736
            {
1737
                $this->error=$this->line->error;
1738
                dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1739
                $this->db->rollback();
1740
                return -2;
1741
            }
1742
		}
1743
		else
1744
        {
1745
            dol_syslog(get_class($this)."::addline status of expense report must be Draft to allow use of ->addline()", LOG_ERR);
1746
			$this->error = 'ErrorExpenseNotDraft';
1747
            return -3;
1748
        }
1749
1750
1751
	}
1752
1753
	/**
1754
	 * Check constraint of rules and update price if needed
1755
	 *
1756
	 * @param	int		$type		type of line
1757
	 * @param	string	$seller		seller, but actually he is unknown
1758
	 * @return true or false
1759
	 */
1760
	function checkRules($type=0, $seller='')
1761
	{
1762
		global $user,$conf,$db,$langs;
1763
1764
		$langs->load('trips');
1765
1766
		if (empty($conf->global->MAIN_USE_EXPENSE_RULE)) return true; // if don't use rules
1767
1768
		$rulestocheck = ExpenseReportRule::getAllRule($this->line->fk_c_type_fees, $this->line->date, $this->fk_user_author);
1769
1770
		$violation = 0;
1771
		$rule_warning_message_tab = array();
1772
1773
		$current_total_ttc = $this->line->total_ttc;
1774
		$new_current_total_ttc = $this->line->total_ttc;
1775
1776
		// check if one is violated
1777
		foreach ($rulestocheck as $rule)
1778
		{
1779
			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);
1780
			else $amount_to_test = $current_total_ttc; // EX_EXP
1781
1782
			$amount_to_test = $amount_to_test - $current_total_ttc + $new_current_total_ttc; // if amount as been modified by a previous rule
1783
1784
			if ($amount_to_test > $rule->amount)
1785
			{
1786
				$violation++;
1787
1788
				if ($rule->restrictive)
1789
				{
1790
					$this->error = 'ExpenseReportConstraintViolationError';
1791
					$this->errors[] = $this->error;
1792
1793
					$new_current_total_ttc -= $amount_to_test - $rule->amount; // ex, entered 16€, limit 12€, subtracts 4€;
1794
					$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)));
1795
				}
1796
				else
1797
				{
1798
					$this->error = 'ExpenseReportConstraintViolationWarning';
1799
					$this->errors[] = $this->error;
1800
1801
					$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));
1802
				}
1803
1804
				// No break, we sould test if another rule is violated
1805
			}
1806
		}
1807
1808
		$this->line->rule_warning_message = implode('\n', $rule_warning_message_tab);
1809
1810
		if ($violation > 0)
1811
		{
1812
			$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);
1813
1814
			$this->line->value_unit = $tmp[5];
1815
			$this->line->total_ttc = $tmp[2];
1816
			$this->line->total_ht = $tmp[0];
1817
			$this->line->total_tva = $tmp[1];
1818
1819
			return false;
1820
		}
1821
		else return true;
1822
	}
1823
1824
	/**
1825
	 * Method to apply the offset if needed
1826
	 *
1827
	 * @return boolean		true=applied, false=not applied
1828
	 */
1829
	function applyOffset()
1830
	{
1831
		global $conf;
1832
1833
		if (empty($conf->global->MAIN_USE_EXPENSE_IK)) return false;
1834
1835
		$userauthor = new User($this->db);
1836
		if ($userauthor->fetch($this->fk_user_author) <= 0)
1837
		{
1838
			$this->error = 'ErrorCantFetchUser';
1839
			$this->errors[] = 'ErrorCantFetchUser';
1840
			return false;
1841
		}
1842
1843
		$range = ExpenseReportIk::getRangeByUser($userauthor, $this->line->fk_c_exp_tax_cat);
1844
1845
		if (empty($range))
1846
		{
1847
			$this->error = 'ErrorNoRangeAvailable';
1848
			$this->errors[] = 'ErrorNoRangeAvailable';
1849
			return false;
1850
		}
1851
1852
		if (!empty($conf->global->MAIN_EXPENSE_APPLY_ENTIRE_OFFSET)) $ikoffset = $range->ikoffset;
1853
		else $ikoffset = $range->ikoffset / 12; // The amount of offset is a global value for the year
1854
1855
		// Test if ikoffset has been applied for the current month
1856
		if (!$this->offsetAlreadyGiven())
1857
		{
1858
			$new_up = $range->coef + ($ikoffset / $this->line->qty);
1859
			$tmp = calcul_price_total($this->line->qty, $new_up, 0, $this->line->vatrate, 0, 0, 0, 'TTC', 0, $type, $seller);
0 ignored issues
show
Bug introduced by
The variable $type does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $seller does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1860
1861
			$this->line->value_unit = $tmp[5];
1862
			$this->line->total_ttc = $tmp[2];
1863
			$this->line->total_ht = $tmp[0];
1864
			$this->line->total_tva = $tmp[1];
1865
1866
			return true;
1867
		}
1868
1869
		return false;
1870
	}
1871
1872
	/**
1873
	 * If the sql find any rows then the ikoffset is already given (ikoffset is applied at the first expense report line)
1874
	 *
1875
	 * @return bool
1876
	 */
1877
	function offsetAlreadyGiven()
1878
	{
1879
		$sql = 'SELECT e.rowid FROM '.MAIN_DB_PREFIX.'expensereport e';
1880
		$sql.= ' INNER JOIN '.MAIN_DB_PREFIX.'expensereport_det d ON (e.rowid = d.fk_expensereport)';
1881
		$sql.= ' INNER JOIN '.MAIN_DB_PREFIX.'c_type_fees f ON (d.fk_c_type_fees = f.id AND f.code = "EX_KME")';
1882
		$sql.= ' WHERE e.fk_user_author = '.(int) $this->fk_user_author;
1883
		$sql.= ' AND YEAR(d.date) = "'.dol_print_date($this->line->date, '%Y').'" AND MONTH(d.date) = "'.dol_print_date($this->line->date, '%m').'"';
1884
		if (!empty($this->line->id)) $sql.= ' AND d.rowid <> '.$this->line->id;
1885
1886
		dol_syslog(get_class($this)."::offsetAlreadyGiven sql=".$sql);
1887
		$resql = $this->db->query($sql);
1888
		if ($resql)
1889
		{
1890
			$num = $this->db->num_rows($resql);
1891
			if ($num > 0) return true;
1892
		}
1893
		else
1894
		{
1895
			dol_print_error($this->db);
1896
		}
1897
1898
		return false;
1899
	}
1900
1901
    /**
1902
     * updateline
1903
     *
1904
     * @param   int         $rowid                  Line to edit
1905
     * @param   int         $type_fees_id           Type payment
1906
     * @param   int         $projet_id              Project id
1907
     * @param   double      $vatrate                Vat rate. Can be '8.5* (8.5NPROM...)'
1908
     * @param   string      $comments               Description
1909
     * @param   real        $qty                    Qty
1910
     * @param   double      $value_unit             Value init
1911
     * @param   int         $date                   Date
1912
     * @param   int         $expensereport_id       Expense report id
1913
     * @param   int         $fk_c_exp_tax_cat       id of category of car
1914
     * @return  int                                 <0 if KO, >0 if OK
1915
     */
1916
    function updateline($rowid, $type_fees_id, $projet_id, $vatrate, $comments, $qty, $value_unit, $date, $expensereport_id, $fk_c_exp_tax_cat=0)
1917
    {
1918
        global $user, $mysoc;
1919
1920
        if ($this->fk_statut==0 || $this->fk_statut==99)
1921
        {
1922
            $this->db->begin();
1923
1924
            $type = 0;      // TODO What if type is service ?
1925
1926
            // We don't know seller and buyer for expense reports
1927
            $seller = $mysoc;
1928
            $buyer = new Societe($this->db);
1929
1930
            $localtaxes_type=getLocalTaxesFromRate($vatrate,0,$buyer,$seller);
1931
1932
            // Clean vat code
1933
            $vat_src_code='';
1934
            if (preg_match('/\((.*)\)/', $vatrate, $reg))
1935
            {
1936
                $vat_src_code = $reg[1];
1937
                $vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate);    // Remove code into vatrate.
1938
            }
1939
            $vatrate = preg_replace('/\*/','',$vatrate);
1940
1941
            $tmp = calcul_price_total($qty, $value_unit, 0, $vatrate, 0, 0, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
1942
1943
            // calcul total of line
1944
            //$total_ttc  = price2num($qty*$value_unit, 'MT');
1945
1946
            $tx_tva = $vatrate / 100;
1947
            $tx_tva = $tx_tva + 1;
1948
            $total_ht   = price2num($total_ttc/$tx_tva, 'MT');
0 ignored issues
show
Bug introduced by
The variable $total_ttc does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1949
1950
            $total_tva = price2num($total_ttc - $total_ht, 'MT');
1951
            // fin calculs
1952
1953
            $this->line = new ExpenseReportLine($this->db);
1954
            $this->line->comments        = $comments;
1955
            $this->line->qty             = $qty;
1956
            $this->line->value_unit      = $value_unit;
1957
            $this->line->date            = $date;
1958
1959
            $this->line->fk_expensereport= $expensereport_id;
1960
            $this->line->fk_c_type_fees  = $type_fees_id;
1961
            $this->line->fk_c_exp_tax_cat  = $fk_c_exp_tax_cat;
1962
            $this->line->fk_projet       = $projet_id;
1963
1964
            $this->line->vat_src_code = $vat_src_code;
1965
            $this->line->vatrate = price2num($vatrate);
1966
            $this->line->total_ttc = $tmp[2];
1967
            $this->line->total_ht = $tmp[0];
1968
            $this->line->total_tva = $tmp[1];
1969
            $this->line->localtax1_tx = $localtaxes_type[1];
1970
            $this->line->localtax2_tx = $localtaxes_type[3];
1971
            $this->line->localtax1_type = $localtaxes_type[0];
1972
            $this->line->localtax2_type = $localtaxes_type[2];
1973
1974
            $this->line->rowid           = $rowid;
1975
            $this->line->id              = $rowid;
1976
1977
            // Select des infos sur le type fees
1978
            $sql = "SELECT c.code as code_type_fees, c.label as libelle_type_fees";
1979
            $sql.= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
1980
            $sql.= " WHERE c.id = ".$type_fees_id;
1981
            $result = $this->db->query($sql);
1982
            $objp_fees = $this->db->fetch_object($result);
1983
            $this->line->type_fees_code      = $objp_fees->code_type_fees;
1984
            $this->line->type_fees_libelle   = $objp_fees->libelle_type_fees;
1985
1986
            // Select des informations du projet
1987
            $sql = "SELECT p.ref as ref_projet, p.title as title_projet";
1988
            $sql.= " FROM ".MAIN_DB_PREFIX."projet as p";
1989
            $sql.= " WHERE p.rowid = ".$projet_id;
1990
            $result = $this->db->query($sql);
1991
            if ($result) {
1992
            	$objp_projet = $this->db->fetch_object($result);
1993
            }
1994
            $this->line->projet_ref          = $objp_projet->ref_projet;
0 ignored issues
show
Bug introduced by
The variable $objp_projet does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1995
            $this->line->projet_title        = $objp_projet->title_projet;
1996
1997
			$this->applyOffset();
1998
			$this->checkRules();
1999
2000
            $result = $this->line->update($user);
2001
            if ($result > 0)
2002
            {
2003
                $this->db->commit();
2004
                return 1;
2005
            }
2006
            else
2007
            {
2008
                $this->error=$this->line->error;
2009
                $this->errors=$this->line->errors;
2010
                $this->db->rollback();
2011
                return -2;
2012
            }
2013
        }
2014
    }
2015
2016
    /**
2017
     * deleteline
2018
     *
2019
     * @param   int     $rowid      Row id
2020
     * @param   User    $fuser      User
2021
     * @return  int                 <0 if KO, >0 if OK
2022
     */
2023
    function deleteline($rowid, $fuser='')
2024
    {
2025
        $this->db->begin();
2026
2027
        $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2028
        $sql.= ' WHERE rowid = '.$rowid;
2029
2030
        dol_syslog(get_class($this)."::deleteline sql=".$sql);
2031
        $result = $this->db->query($sql);
2032
        if (!$result)
2033
        {
2034
            $this->error=$this->db->error();
2035
            dol_syslog(get_class($this)."::deleteline  Error ".$this->error, LOG_ERR);
2036
            $this->db->rollback();
2037
            return -1;
2038
        }
2039
2040
        $this->db->commit();
2041
2042
        return 1;
2043
    }
2044
2045
    /**
2046
     * periode_existe
2047
     *
2048
     * @param   User    $fuser          User
2049
     * @param   Date    $date_debut     Start date
2050
     * @param   Date    $date_fin       End date
2051
     * @return  int                     <0 if KO, >0 if OK
2052
     */
2053
    function periode_existe($fuser, $date_debut, $date_fin)
2054
    {
2055
        $sql = "SELECT rowid, date_debut, date_fin";
2056
        $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element;
2057
        $sql.= " WHERE fk_user_author = '{$fuser->id}'";
2058
2059
        dol_syslog(get_class($this)."::periode_existe sql=".$sql);
2060
        $result = $this->db->query($sql);
2061
        if($result)
2062
        {
2063
            $num_lignes = $this->db->num_rows($result); $i = 0;
2064
2065
            if ($num_lignes>0)
2066
            {
2067
                $date_d_form = $date_debut;
2068
                $date_f_form = $date_fin;
2069
2070
                $existe = false;
2071
2072
                while ($i < $num_lignes)
2073
                {
2074
                    $objp = $this->db->fetch_object($result);
2075
2076
                    $date_d_req = $this->db->jdate($objp->date_debut); // 3
2077
                    $date_f_req = $this->db->jdate($objp->date_fin);      // 4
2078
2079
                    if (!($date_f_form < $date_d_req || $date_d_form > $date_f_req)) $existe = true;
2080
2081
                    $i++;
2082
                }
2083
2084
                if($existe) return 1;
2085
                else return 0;
2086
            }
2087
            else
2088
            {
2089
                return 0;
2090
            }
2091
        }
2092
        else
2093
        {
2094
            $this->error=$this->db->lasterror();
2095
            dol_syslog(get_class($this)."::periode_existe  Error ".$this->error, LOG_ERR);
2096
            return -1;
2097
        }
2098
    }
2099
2100
2101
    /**
2102
     * Return list of people with permission to validate expense reports.
2103
     * Search for permission "approve expense report"
2104
     *
2105
     * @return  array       Array of user ids
2106
     */
2107
    function fetch_users_approver_expensereport()
2108
    {
2109
        $users_validator=array();
2110
2111
        $sql = "SELECT DISTINCT ur.fk_user";
2112
        $sql.= " FROM ".MAIN_DB_PREFIX."user_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2113
        $sql.= " WHERE ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'";                                              // Permission 'Approve';
2114
        $sql.= "UNION";
2115
        $sql.= " SELECT DISTINCT ugu.fk_user";
2116
        $sql.= " FROM ".MAIN_DB_PREFIX."usergroup_user as ugu, ".MAIN_DB_PREFIX."usergroup_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2117
        $sql.= " WHERE ugu.fk_usergroup = ur.fk_usergroup AND ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'";       // Permission 'Approve';
2118
        //print $sql;
2119
2120
        dol_syslog(get_class($this)."::fetch_users_approver_expensereport sql=".$sql);
2121
        $result = $this->db->query($sql);
2122
        if($result)
2123
        {
2124
            $num_lignes = $this->db->num_rows($result); $i = 0;
2125
            while ($i < $num_lignes)
2126
            {
2127
                $objp = $this->db->fetch_object($result);
2128
                array_push($users_validator,$objp->fk_user);
2129
                $i++;
2130
            }
2131
            return $users_validator;
2132
        }
2133
        else
2134
        {
2135
            $this->error=$this->db->lasterror();
2136
            dol_syslog(get_class($this)."::fetch_users_approver_expensereport  Error ".$this->error, LOG_ERR);
2137
            return -1;
2138
        }
2139
    }
2140
2141
    /**
2142
     *  Create a document onto disk accordign to template module.
2143
     *
2144
     *  @param      string      $modele         Force le mnodele a utiliser ('' to not force)
2145
     *  @param      Translate   $outputlangs    objet lang a utiliser pour traduction
2146
     *  @param      int         $hidedetails    Hide details of lines
2147
     *  @param      int         $hidedesc       Hide description
2148
     *  @param      int         $hideref        Hide ref
2149
     *  @return     int                         0 if KO, 1 if OK
2150
     */
2151
    public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
2152
    {
2153
        global $conf,$langs;
2154
2155
        $langs->load("trips");
2156
2157
	    if (! dol_strlen($modele)) {
2158
2159
		    $modele = 'standard';
2160
2161
		    if ($this->modelpdf) {
2162
			    $modele = $this->modelpdf;
2163
		    } elseif (! empty($conf->global->EXPENSEREPORT_ADDON_PDF)) {
2164
			    $modele = $conf->global->EXPENSEREPORT_ADDON_PDF;
2165
		    }
2166
	    }
2167
2168
        $modelpath = "core/modules/expensereport/doc/";
2169
2170
        return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
2171
    }
2172
2173
    /**
2174
     * List of types
2175
     *
2176
     * @param   int     $active     Active or not
2177
     * @return  array
2178
     */
2179
    function listOfTypes($active=1)
2180
    {
2181
        global $langs;
2182
        $ret=array();
2183
        $sql = "SELECT id, code, label";
2184
        $sql.= " FROM ".MAIN_DB_PREFIX."c_type_fees";
2185
        $sql.= " WHERE active = ".$active;
2186
        dol_syslog(get_class($this)."::listOfTypes", LOG_DEBUG);
2187
        $result = $this->db->query($sql);
2188
        if ( $result )
2189
        {
2190
            $num = $this->db->num_rows($result);
2191
            $i=0;
2192
            while ($i < $num)
2193
            {
2194
                $obj = $this->db->fetch_object($result);
2195
                $ret[$obj->code]=(($langs->trans($obj->code)!=$obj->code)?$langs->trans($obj->code):$obj->label);
2196
                $i++;
2197
            }
2198
        }
2199
        else
2200
        {
2201
            dol_print_error($this->db);
2202
        }
2203
        return $ret;
2204
    }
2205
2206
	/**
2207
     *      Charge indicateurs this->nb pour le tableau de bord
2208
     *
2209
     *      @return     int         <0 if KO, >0 if OK
2210
     */
2211
    function load_state_board()
2212
    {
2213
        global $conf;
2214
2215
        $this->nb=array();
2216
2217
        $sql = "SELECT count(ex.rowid) as nb";
2218
        $sql.= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2219
        $sql.= " WHERE ex.fk_statut > 0";
2220
        $sql.= " AND ex.entity IN (".getEntity('expensereport').")";
2221
2222
        $resql=$this->db->query($sql);
2223
        if ($resql)
2224
        {
2225
            while ($obj=$this->db->fetch_object($resql))
2226
            {
2227
                $this->nb["expensereports"]=$obj->nb;
2228
            }
2229
            $this->db->free($resql);
2230
            return 1;
2231
        }
2232
        else
2233
        {
2234
            dol_print_error($this->db);
2235
            $this->error=$this->db->error();
2236
            return -1;
2237
        }
2238
    }
2239
2240
    /**
2241
     *      Load indicators for dashboard (this->nbtodo and this->nbtodolate)
2242
     *
2243
     *      @param	User	$user   		Objet user
2244
     *      @param  string  $option         'topay' or 'toapprove'
2245
     *      @return WorkboardResponse|int 	<0 if KO, WorkboardResponse if OK
2246
     */
2247
    function load_board($user, $option='topay')
2248
    {
2249
        global $conf, $langs;
2250
2251
        if ($user->societe_id) return -1;   // protection pour eviter appel par utilisateur externe
2252
2253
	    $now=dol_now();
2254
2255
	    $userchildids = $user->getAllChildIds(1);
2256
2257
        $sql = "SELECT ex.rowid, ex.date_valid";
2258
        $sql.= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2259
        if ($option == 'toapprove') $sql.= " WHERE ex.fk_statut = 2";
2260
        else $sql.= " WHERE ex.fk_statut = 5";
2261
        $sql.= " AND ex.entity IN (".getEntity('expensereport').")";
2262
        $sql.= " AND (ex.fk_user_author IN (".join(',',$userchildids).")";
2263
        $sql.= " OR ex.fk_user_validator IN (".join(',',$userchildids)."))";
2264
2265
        $resql=$this->db->query($sql);
2266
        if ($resql)
2267
        {
2268
	        $langs->load("members");
2269
2270
	        $response = new WorkboardResponse();
2271
	        if ($option == 'toapprove')
2272
	        {
2273
	           $response->warning_delay=$conf->expensereport->approve->warning_delay/60/60/24;
2274
	           $response->label=$langs->trans("ExpenseReportsToApprove");
2275
	           $response->url=DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut=2';
2276
	        }
2277
	        else
2278
	        {
2279
	            $response->warning_delay=$conf->expensereport->payment->warning_delay/60/60/24;
2280
	            $response->label=$langs->trans("ExpenseReportsToPay");
2281
	            $response->url=DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut=5';
2282
	        }
2283
	        $response->img=img_object('',"trip");
2284
2285
            while ($obj=$this->db->fetch_object($resql))
2286
            {
2287
	            $response->nbtodo++;
2288
2289
	            if ($option == 'toapprove')
2290
	            {
2291
	                if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->approve->warning_delay)) {
2292
	                    $response->nbtodolate++;
2293
	                }
2294
	            }
2295
	            else
2296
	            {
2297
                    if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->payment->warning_delay)) {
2298
    	                $response->nbtodolate++;
2299
                    }
2300
	            }
2301
            }
2302
2303
            return $response;
2304
        }
2305
        else
2306
        {
2307
            dol_print_error($this->db);
2308
            $this->error=$this->db->error();
2309
            return -1;
2310
        }
2311
    }
2312
2313
    /**
2314
     * Return if an expense report is late or not
2315
     *
2316
     * @param  string  $option          'topay' or 'toapprove'
2317
     * @return boolean                  True if late, False if not late
2318
     */
2319
    public function hasDelay($option)
2320
    {
2321
        global $conf;
2322
2323
        //Only valid members
2324
        if ($option == 'toapprove' && $this->status != 2) return false;
2325
        if ($option == 'topay' && $this->status != 5) return false;
2326
2327
        $now = dol_now();
2328
        if ($option == 'toapprove')
2329
        {
2330
            return ($this->datevalid?$this->datevalid:$this->date_valid) < ($now - $conf->expensereport->approve->warning_delay);
2331
        }
2332
        else
2333
            return ($this->datevalid?$this->datevalid:$this->date_valid) < ($now - $conf->expensereport->payment->warning_delay);
2334
    }
2335
2336
    /**
2337
     *	Return if an expensereport was dispatched into bookkeeping
2338
     *
2339
     *	@return     int         <0 if KO, 0=no, 1=yes
2340
     */
2341
    public function getVentilExportCompta()
2342
    {
2343
    	$alreadydispatched = 0;
2344
2345
    	$type = 'expense_report';
2346
2347
    	$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;
2348
    	$resql = $this->db->query($sql);
2349
    	if ($resql)
2350
    	{
2351
    		$obj = $this->db->fetch_object($resql);
2352
    		if ($obj)
2353
    		{
2354
    			$alreadydispatched = $obj->nb;
2355
    		}
2356
    	}
2357
    	else
2358
    	{
2359
    		$this->error = $this->db->lasterror();
2360
    		return -1;
2361
    	}
2362
2363
    	if ($alreadydispatched)
2364
    	{
2365
    		return 1;
2366
    	}
2367
    	return 0;
2368
    }
2369
2370
}
2371
2372
2373
/**
2374
 * Class of expense report details lines
2375
 */
2376
class ExpenseReportLine
2377
{
2378
    var $db;
2379
    var $error;
2380
2381
    var $rowid;
2382
    var $comments;
2383
    var $qty;
2384
    var $value_unit;
2385
    var $date;
2386
2387
    var $fk_c_type_fees;
2388
    var $fk_c_exp_tax_cat;
2389
    var $fk_projet;
2390
    var $fk_expensereport;
2391
2392
    var $type_fees_code;
2393
    var $type_fees_libelle;
2394
2395
    var $projet_ref;
2396
    var $projet_title;
2397
2398
    var $vatrate;
2399
    var $total_ht;
2400
    var $total_tva;
2401
    var $total_ttc;
2402
2403
    /**
2404
     * Constructor
2405
     *
2406
     * @param DoliDB    $db     Handlet database
2407
     */
2408
    function __construct($db)
2409
    {
2410
        $this->db= $db;
2411
    }
2412
2413
    /**
2414
     * Fetch record for expense report detailed line
2415
     *
2416
     * @param   int     $rowid      Id of object to load
2417
     * @return  int                 <0 if KO, >0 if OK
2418
     */
2419
    function fetch($rowid)
2420
    {
2421
        $sql = 'SELECT fde.rowid, fde.fk_expensereport, fde.fk_c_type_fees, fde.fk_c_exp_tax_cat, fde.fk_projet, fde.date,';
2422
        $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,';
2423
        $sql.= ' ctf.code as type_fees_code, ctf.label as type_fees_libelle,';
2424
        $sql.= ' pjt.rowid as projet_id, pjt.title as projet_title, pjt.ref as projet_ref';
2425
        $sql.= ' FROM '.MAIN_DB_PREFIX.'expensereport_det as fde';
2426
        $sql.= ' INNER JOIN '.MAIN_DB_PREFIX.'c_type_fees as ctf ON fde.fk_c_type_fees=ctf.id';
2427
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as pjt ON fde.fk_projet=pjt.rowid';
2428
        $sql.= ' WHERE fde.rowid = '.$rowid;
2429
2430
        $result = $this->db->query($sql);
2431
2432
        if($result)
2433
        {
2434
            $objp = $this->db->fetch_object($result);
2435
2436
            $this->rowid = $objp->rowid;
2437
            $this->id = $obj->rowid;
0 ignored issues
show
Bug introduced by
The variable $obj does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
2438
            $this->ref = $obj->ref;
2439
            $this->fk_expensereport = $objp->fk_expensereport;
2440
            $this->comments = $objp->comments;
2441
            $this->qty = $objp->qty;
2442
            $this->date = $objp->date;
2443
            $this->dates = $this->db->jdate($objp->date);
2444
            $this->value_unit = $objp->value_unit;
2445
            $this->fk_c_type_fees = $objp->fk_c_type_fees;
2446
            $this->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
2447
            $this->fk_projet = $objp->fk_projet;
2448
            $this->type_fees_code = $objp->type_fees_code;
2449
            $this->type_fees_libelle = $objp->type_fees_libelle;
2450
            $this->projet_ref = $objp->projet_ref;
2451
            $this->projet_title = $objp->projet_title;
2452
            $this->vatrate = $objp->vatrate;
2453
            $this->vat_src_code = $objp->vat_src_code;
2454
            $this->total_ht = $objp->total_ht;
2455
            $this->total_tva = $objp->total_tva;
2456
            $this->total_ttc = $objp->total_ttc;
2457
2458
            $this->db->free($result);
2459
        } else {
2460
            dol_print_error($this->db);
2461
        }
2462
    }
2463
2464
    /**
2465
     * insert
2466
     *
2467
     * @param   int     $notrigger      1=No trigger
2468
     * @param   bool    $fromaddline    false=keep default behavior, true=exclude the update_price() of parent object
2469
     * @return  int                     <0 if KO, >0 if OK
2470
     */
2471
    function insert($notrigger=0,$fromaddline=false)
2472
    {
2473
        global $langs,$user,$conf;
2474
2475
        $error=0;
2476
2477
        dol_syslog("ExpenseReportLine::Insert rang=".$this->rang, LOG_DEBUG);
2478
2479
        // Clean parameters
2480
        $this->comments=trim($this->comments);
2481
        if (!$this->value_unit_HT) $this->value_unit_HT=0;
2482
        $this->qty = price2num($this->qty);
2483
        $this->vatrate = price2num($this->vatrate);
2484
		if (empty($this->fk_c_exp_tax_cat)) $this->fk_c_exp_tax_cat = 0;
2485
2486
        $this->db->begin();
2487
2488
        $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'expensereport_det';
2489
        $sql.= ' (fk_expensereport, fk_c_type_fees, fk_projet,';
2490
        $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)';
2491
        $sql.= " VALUES (".$this->db->escape($this->fk_expensereport).",";
2492
        $sql.= " ".$this->db->escape($this->fk_c_type_fees).",";
2493
        $sql.= " ".$this->db->escape($this->fk_projet>0?$this->fk_projet:'null').",";
2494
        $sql.= " ".$this->db->escape($this->vatrate).",";
2495
        $sql.= " '".$this->db->escape($this->vat_src_code)."',";
2496
        $sql.= " '".$this->db->escape($this->comments)."',";
2497
        $sql.= " ".$this->db->escape($this->qty).",";
2498
        $sql.= " ".$this->db->escape($this->value_unit).",";
2499
        $sql.= " ".$this->db->escape($this->total_ht).",";
2500
        $sql.= " ".$this->db->escape($this->total_tva).",";
2501
        $sql.= " ".$this->db->escape($this->total_ttc).",";
2502
        $sql.= "'".$this->db->idate($this->date)."',";
2503
		$sql.= " '".$this->db->escape($this->rule_warning_message)."',";
2504
		$sql.= " ".$this->db->escape($this->fk_c_exp_tax_cat);
2505
        $sql.= ")";
2506
2507
        $resql=$this->db->query($sql);
2508
        if ($resql)
2509
        {
2510
            $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'expensereport_det');
2511
2512
			if (! $fromaddline)
2513
			{
2514
				$tmpparent=new ExpenseReport($this->db);
2515
				$tmpparent->fetch($this->fk_expensereport);
2516
				$result = $tmpparent->update_price();
2517
				if ($result < 0)
2518
				{
2519
					$error++;
2520
					$this->error = $tmpparent->error;
2521
					$this->errors = $tmpparent->errors;
2522
				}
2523
			}
2524
        }
2525
		else
2526
		{
2527
			$error++;
2528
		}
2529
2530
        if (! $error)
2531
        {
2532
            $this->db->commit();
2533
            return $this->rowid;
2534
        }
2535
        else
2536
        {
2537
            $this->error=$this->db->lasterror();
2538
            dol_syslog("ExpenseReportLine::insert Error ".$this->error, LOG_ERR);
2539
            $this->db->rollback();
2540
            return -2;
2541
        }
2542
    }
2543
2544
	/**
2545
	 * Function to get total amount in expense reports for a same rule
2546
	 *
2547
	 * @param ExpenseReportRule $rule		object rule to check
2548
	 * @param int				$fk_user	user author id
2549
	 * @param string			$mode		day|EX_DAY / month|EX_MON / year|EX_YEA to get amount
2550
	 * @return amount
2551
	 */
2552
	public function getExpAmount(ExpenseReportRule $rule, $fk_user, $mode='day')
2553
	{
2554
		$amount = 0;
2555
2556
		$sql = 'SELECT SUM(d.total_ttc) as total_amount';
2557
		$sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det d';
2558
		$sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'expensereport e ON (d.fk_expensereport = e.rowid)';
2559
		$sql .= ' WHERE e.fk_user_author = '.$fk_user;
2560
		if (!empty($this->id)) $sql.= ' AND d.rowid <> '.$this->id;
2561
		$sql .= ' AND d.fk_c_type_fees = '.$rule->fk_c_type_fees;
2562
		if ($mode == 'day' || $mode == 'EX_DAY') $sql .= ' AND d.date = \''.dol_print_date($this->date, '%Y-%m-%d').'\'';
2563
		elseif ($mode == 'mon' || $mode == 'EX_MON') $sql .= ' AND DATE_FORMAT(d.date, \'%Y-%m\') = \''.dol_print_date($this->date, '%Y-%m').'\'';
2564
		elseif ($mode == 'year' || $mode == 'EX_YEA') $sql .= ' AND DATE_FORMAT(d.date, \'%Y\') = \''.dol_print_date($this->date, '%Y').'\'';
2565
2566
		dol_syslog('ExpenseReportLine::getExpAmountByDay sql='.$sql);
2567
2568
		$resql = $this->db->query($sql);
2569
		if ($resql)
2570
		{
2571
			$num = $this->db->num_rows($resql);
2572
			if ($num > 0)
2573
			{
2574
				$obj = $this->db->fetch_object($resql);
2575
				$amount = (double) $obj->total_amount;
2576
			}
2577
		}
2578
		else
2579
		{
2580
			dol_print_error($this->db);
2581
		}
2582
2583
2584
		return $amount + $this->total_ttc;
2585
	}
2586
2587
    /**
2588
     * update
2589
     *
2590
     * @param   User    $fuser      User
2591
     * @return  int                 <0 if KO, >0 if OK
2592
     */
2593
    function update($fuser)
2594
    {
2595
        global $fuser,$langs,$conf;
2596
2597
        $error=0;
2598
2599
        // Clean parameters
2600
        $this->comments=trim($this->comments);
2601
        $this->vatrate = price2num($this->vatrate);
2602
        $this->value_unit = price2num($this->value_unit);
2603
		if (empty($this->fk_c_exp_tax_cat)) $this->fk_c_exp_tax_cat = 0;
2604
2605
        $this->db->begin();
2606
2607
        // Update line in database
2608
        $sql = "UPDATE ".MAIN_DB_PREFIX."expensereport_det SET";
2609
        $sql.= " comments='".$this->db->escape($this->comments)."'";
2610
        $sql.= ",value_unit=".$this->db->escape($this->value_unit);
2611
        $sql.= ",qty=".$this->db->escape($this->qty);
2612
        $sql.= ",date='".$this->db->idate($this->date)."'";
2613
        $sql.= ",total_ht=".$this->db->escape($this->total_ht)."";
2614
        $sql.= ",total_tva=".$this->db->escape($this->total_tva)."";
2615
        $sql.= ",total_ttc=".$this->db->escape($this->total_ttc)."";
2616
        $sql.= ",tva_tx=".$this->db->escape($this->vatrate);
2617
		$sql.= ",vat_src_code='".$this->db->escape($this->vat_src_code)."'";
2618
        $sql.= ",rule_warning_message='".$this->db->escape($this->rule_warning_message)."'";
2619
		$sql.= ",fk_c_exp_tax_cat=".$this->db->escape($this->fk_c_exp_tax_cat);
2620
        if ($this->fk_c_type_fees) $sql.= ",fk_c_type_fees=".$this->db->escape($this->fk_c_type_fees);
2621
        else $sql.= ",fk_c_type_fees=null";
2622
        if ($this->fk_projet) $sql.= ",fk_projet=".$this->db->escape($this->fk_projet);
2623
        else $sql.= ",fk_projet=null";
2624
        $sql.= " WHERE rowid = ".$this->db->escape($this->rowid);
2625
2626
        dol_syslog("ExpenseReportLine::update sql=".$sql);
2627
2628
        $resql=$this->db->query($sql);
2629
        if ($resql)
2630
        {
2631
            $tmpparent=new ExpenseReport($this->db);
2632
            $result = $tmpparent->fetch($this->fk_expensereport);
2633
            if ($result > 0)
2634
            {
2635
                $result = $tmpparent->update_price();
2636
                if ($result < 0)
2637
                {
2638
                    $error++;
2639
                    $this->error = $tmpparent->error;
2640
                    $this->errors = $tmpparent->errors;
2641
                }
2642
            }
2643
            else
2644
            {
2645
                $error++;
2646
                $this->error = $tmpparent->error;
2647
                $this->errors = $tmpparent->errors;
2648
            }
2649
        }
2650
        else
2651
        {
2652
            $error++;
2653
            dol_print_error($this->db);
2654
        }
2655
2656
        if (! $error)
2657
        {
2658
            $this->db->commit();
2659
            return 1;
2660
        }
2661
        else
2662
        {
2663
            $this->error=$this->db->lasterror();
2664
            dol_syslog("ExpenseReportLine::update Error ".$this->error, LOG_ERR);
2665
            $this->db->rollback();
2666
            return -2;
2667
        }
2668
    }
2669
}
2670
2671
2672
/**
2673
 *    Retourne la liste deroulante des differents etats d'une note de frais.
2674
 *    Les valeurs de la liste sont les id de la table c_expensereport_statuts
2675
 *
2676
 *    @param    int     $selected       preselect status
2677
 *    @param    string  $htmlname       Name of HTML select
2678
 *    @param    int     $useempty       1=Add empty line
2679
 *    @param    int     $useshortlabel  Use short labels
2680
 *    @return   string                  HTML select with status
2681
 */
2682
function select_expensereport_statut($selected='',$htmlname='fk_statut',$useempty=1, $useshortlabel=0)
2683
{
2684
    global $db, $langs;
2685
2686
    $tmpep=new ExpenseReport($db);
2687
2688
    print '<select class="flat" name="'.$htmlname.'">';
2689
    if ($useempty) print '<option value="-1">&nbsp;</option>';
2690
    $arrayoflabels=$tmpep->statuts;
2691
    if ($useshortlabel) $arrayoflabels=$tmpep->statuts_short;
2692
    foreach ($arrayoflabels as $key => $val)
2693
    {
2694
        if ($selected != '' && $selected == $key)
2695
        {
2696
            print '<option value="'.$key.'" selected>';
2697
        }
2698
        else
2699
        {
2700
            print '<option value="'.$key.'">';
2701
        }
2702
        print $langs->trans($val);
2703
        print '</option>';
2704
    }
2705
    print '</select>';
2706
}
2707
2708
/**
2709
 *  Return list of types of notes with select value = id
2710
 *
2711
 *  @param      int     $selected       Preselected type
2712
 *  @param      string  $htmlname       Name of field in form
2713
 *  @param      int     $showempty      Add an empty field
2714
 *  @param      int     $active         1=Active only, 0=Unactive only, -1=All
2715
 *  @return     string                  Select html
2716
 */
2717
function select_type_fees_id($selected='',$htmlname='type',$showempty=0, $active=1)
2718
{
2719
    global $db,$langs,$user;
2720
    $langs->load("trips");
2721
2722
    print '<select class="flat" name="'.$htmlname.'">';
2723
    if ($showempty)
2724
    {
2725
        print '<option value="-1"';
2726
        if ($selected == -1) print ' selected';
2727
        print '>&nbsp;</option>';
2728
    }
2729
2730
    $sql = "SELECT c.id, c.code, c.label as type FROM ".MAIN_DB_PREFIX."c_type_fees as c";
2731
    if ($active >= 0) $sql.= " WHERE c.active = ".$active;
2732
    $sql.= " ORDER BY c.label ASC";
2733
    $resql=$db->query($sql);
2734
    if ($resql)
2735
    {
2736
        $num = $db->num_rows($resql);
2737
        $i = 0;
2738
2739
        while ($i < $num)
2740
        {
2741
            $obj = $db->fetch_object($resql);
2742
            print '<option value="'.$obj->id.'"';
2743
            if ($obj->code == $selected || $obj->id == $selected) print ' selected';
2744
            print '>';
2745
            if ($obj->code != $langs->trans($obj->code)) print $langs->trans($obj->code);
2746
            else print $langs->trans($obj->type);
2747
            $i++;
2748
        }
2749
    }
2750
    print '</select>';
2751
}
2752