Passed
Branch develop (944e2a)
by
unknown
27:19
created

ExpenseReport::addline()   F

Complexity

Conditions 15
Paths 769

Size

Total Lines 82
Code Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 58
nc 769
nop 10
dl 0
loc 82
rs 2.0708
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) 2018       Nicolas ZABOURI         <[email protected]>
6
 * Copyright (c) 2018       Frédéric France         <[email protected]>
7
 * Copyright (C) 2016-2020 	Ferran Marcet       	<[email protected]>
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21
 */
22
23
/**
24
 *       \file       htdocs/expensereport/class/expensereport.class.php
25
 *       \ingroup    expensereport
26
 *       \brief      File to manage Expense Reports
27
 */
28
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
29
require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport_ik.class.php';
30
require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport_rule.class.php';
31
32
/**
33
 * Class to manage Trips and Expenses
34
 */
35
class ExpenseReport extends CommonObject
36
{
37
	/**
38
	 * @var string ID to identify managed object
39
	 */
40
	public $element = 'expensereport';
41
42
	/**
43
	 * @var string Name of table without prefix where object is stored
44
	 */
45
	public $table_element = 'expensereport';
46
47
	public $table_element_line = 'expensereport_det';
48
	public $fk_element = 'fk_expensereport';
49
50
	/**
51
	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
52
	 */
53
	public $picto = 'trip';
54
55
	public $lines = array();
56
57
	public $date_debut;
58
59
	public $date_fin;
60
61
	/**
62
	 * 0=draft, 2=validated (attente approb), 4=canceled, 5=approved, 6=payed, 99=denied
63
	 *
64
	 * @var int		Status
65
	 */
66
	public $status;
67
68
	/**
69
	 * 0=draft, 2=validated (attente approb), 4=canceled, 5=approved, 6=payed, 99=denied
70
	 *
71
	 * @var int		Status
72
	 * @deprecated
73
	 */
74
	public $fk_statut;
75
76
	public $fk_c_paiement;
77
	public $paid;
78
79
	public $user_author_infos;
80
	public $user_validator_infos;
81
82
	// ACTIONS
83
84
	// Create
85
	public $date_create;
86
	public $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
87
88
	// Update
89
	public $date_modif;
90
	public $fk_user_modif;
91
92
	// Refus
93
	public $date_refuse;
94
	public $detail_refuse;
95
	public $fk_user_refuse;
96
97
	// Annulation
98
	public $date_cancel;
99
	public $detail_cancel;
100
	public $fk_user_cancel;
101
102
	public $fk_user_validator; // User that is defined to approve
103
104
	// Validation
105
	public $date_valid; // User making validation
106
	public $fk_user_valid;
107
	public $user_valid_infos;
108
109
	// Approve
110
	public $date_approve;
111
	public $fk_user_approve; // User that has approved
112
113
	// Paiement
114
	public $user_paid_infos;
115
116
117
	/**
118
	 * Draft status
119
	 */
120
	const STATUS_DRAFT = 0;
121
122
	/**
123
	 * Validated (need to be paid)
124
	 */
125
	const STATUS_VALIDATED = 2;
126
127
	/**
128
	 * Classified canceled
129
	 */
130
	const STATUS_CANCELED = 4;
131
132
	/**
133
	 * Classified approved
134
	 */
135
	const STATUS_APPROVED = 5;
136
137
	/**
138
	 * Classified refused
139
	 */
140
	const STATUS_REFUSED = 99;
141
142
	/**
143
	 * Classified paid.
144
	 */
145
	const STATUS_CLOSED = 6;
146
147
148
	public $fields = array(
149
		'rowid' =>array('type'=>'integer', 'label'=>'ID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
150
		'ref' =>array('type'=>'varchar(50)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>15),
151
		'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>20),
152
		'ref_number_int' =>array('type'=>'integer', 'label'=>'Ref number int', 'enabled'=>1, 'visible'=>-1, 'position'=>25),
153
		'ref_ext' =>array('type'=>'integer', 'label'=>'Ref ext', 'enabled'=>1, 'visible'=>-1, 'position'=>30),
154
		'total_ht' =>array('type'=>'double(24,8)', 'label'=>'Total ht', 'enabled'=>1, 'visible'=>-1, 'position'=>35),
155
		'total_tva' =>array('type'=>'double(24,8)', 'label'=>'Total tva', 'enabled'=>1, 'visible'=>-1, 'position'=>40),
156
		'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
157
		'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>-1, 'position'=>50),
158
		'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Total ttc', 'enabled'=>1, 'visible'=>-1, 'position'=>55),
159
		'date_debut' =>array('type'=>'date', 'label'=>'Date debut', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>60),
160
		'date_fin' =>array('type'=>'date', 'label'=>'Date fin', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>65),
161
		'date_valid' =>array('type'=>'datetime', 'label'=>'Date valid', 'enabled'=>1, 'visible'=>-1, 'position'=>75),
162
		'date_approve' =>array('type'=>'datetime', 'label'=>'Date approve', 'enabled'=>1, 'visible'=>-1, 'position'=>80),
163
		'date_refuse' =>array('type'=>'datetime', 'label'=>'Date refuse', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
164
		'date_cancel' =>array('type'=>'datetime', 'label'=>'Date cancel', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
165
		'fk_user_author' =>array('type'=>'integer', 'label'=>'Fk user author', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>100),
166
		'fk_user_modif' =>array('type'=>'integer', 'label'=>'Fk user modif', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
167
		'fk_user_valid' =>array('type'=>'integer', 'label'=>'Fk user valid', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
168
		'fk_user_validator' =>array('type'=>'integer', 'label'=>'Fk user validator', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
169
		'fk_user_approve' =>array('type'=>'integer', 'label'=>'Fk user approve', 'enabled'=>1, 'visible'=>-1, 'position'=>120),
170
		'fk_user_refuse' =>array('type'=>'integer', 'label'=>'Fk user refuse', 'enabled'=>1, 'visible'=>-1, 'position'=>125),
171
		'fk_user_cancel' =>array('type'=>'integer', 'label'=>'Fk user cancel', 'enabled'=>1, 'visible'=>-1, 'position'=>130),
172
		'fk_c_paiement' =>array('type'=>'integer', 'label'=>'Fk c paiement', 'enabled'=>1, 'visible'=>-1, 'position'=>140),
173
		'paid' =>array('type'=>'integer', 'label'=>'Paid', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>145),
174
		'note_public' =>array('type'=>'text', 'label'=>'Note public', 'enabled'=>1, 'visible'=>0, 'position'=>150),
175
		'note_private' =>array('type'=>'text', 'label'=>'Note private', 'enabled'=>1, 'visible'=>0, 'position'=>155),
176
		'detail_refuse' =>array('type'=>'varchar(255)', 'label'=>'Detail refuse', 'enabled'=>1, 'visible'=>-1, 'position'=>160),
177
		'detail_cancel' =>array('type'=>'varchar(255)', 'label'=>'Detail cancel', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
178
		'integration_compta' =>array('type'=>'integer', 'label'=>'Integration compta', 'enabled'=>1, 'visible'=>-1, 'position'=>170),
179
		'fk_bank_account' =>array('type'=>'integer', 'label'=>'Fk bank account', 'enabled'=>1, 'visible'=>-1, 'position'=>175),
180
		'fk_multicurrency' =>array('type'=>'integer', 'label'=>'Fk multicurrency', 'enabled'=>1, 'visible'=>-1, 'position'=>185),
181
		'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'Multicurrency code', 'enabled'=>1, 'visible'=>-1, 'position'=>190),
182
		'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency tx', 'enabled'=>1, 'visible'=>-1, 'position'=>195),
183
		'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ht', 'enabled'=>1, 'visible'=>-1, 'position'=>200),
184
		'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total tva', 'enabled'=>1, 'visible'=>-1, 'position'=>205),
185
		'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ttc', 'enabled'=>1, 'visible'=>-1, 'position'=>210),
186
		'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>220),
187
		'date_create' =>array('type'=>'datetime', 'label'=>'Date create', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>300),
188
		'tms' =>array('type'=>'timestamp', 'label'=>'Tms', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>305),
189
		'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-1, 'position'=>1000),
190
		'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>1010),
191
		'fk_statut' =>array('type'=>'integer', 'label'=>'Fk statut', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>500),
192
	);
193
194
	/**
195
	 *  Constructor
196
	 *
197
	 *  @param  DoliDB  $db     Handler acces base de donnees
198
	 */
199
	public function __construct($db)
200
	{
201
		$this->db = $db;
202
		$this->total_ht = 0;
203
		$this->total_ttc = 0;
204
		$this->total_tva = 0;
205
		$this->modepaymentid = 0;
206
207
		// List of language codes for status
208
		$this->statuts_short = array(0 => 'Draft', 2 => 'Validated', 4 => 'Canceled', 5 => 'Approved', 6 => 'Paid', 99 => 'Refused');
209
		$this->statuts = array(0 => 'Draft', 2 => 'ValidatedWaitingApproval', 4 => 'Canceled', 5 => 'Approved', 6 => 'Paid', 99 => 'Refused');
210
		$this->statuts_logo = array(0 => 'status0', 2 => 'status1', 4 => 'status6', 5 => 'status4', 6 => 'status6', 99 => 'status5');
211
	}
212
213
	/**
214
	 * Create object in database
215
	 *
216
	 * @param   User    $user   User that create
217
	 * @param   int     $notrigger   Disable triggers
218
	 * @return  int             <0 if KO, >0 if OK
219
	 */
220
	public function create($user, $notrigger = 0)
221
	{
222
		global $conf, $langs;
223
224
		$now = dol_now();
225
226
		$error = 0;
227
228
		// Check parameters
229
		if (empty($this->date_debut) || empty($this->date_fin))
230
		{
231
			$this->error = $langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Date'));
232
			return -1;
233
		}
234
235
		$fuserid = $this->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
236
		if (empty($fuserid)) $fuserid = $user->id;
237
238
		$this->db->begin();
239
240
		$sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
241
		$sql .= "ref";
242
		$sql .= ",total_ht";
243
		$sql .= ",total_ttc";
244
		$sql .= ",total_tva";
245
		$sql .= ",date_debut";
246
		$sql .= ",date_fin";
247
		$sql .= ",date_create";
248
		$sql .= ",fk_user_author";
249
		$sql .= ",fk_user_validator";
250
		$sql .= ",fk_user_approve";
251
		$sql .= ",fk_user_modif";
252
		$sql .= ",fk_statut";
253
		$sql .= ",fk_c_paiement";
254
		$sql .= ",paid";
255
		$sql .= ",note_public";
256
		$sql .= ",note_private";
257
		$sql .= ",entity";
258
		$sql .= ") VALUES(";
259
		$sql .= "'(PROV)'";
260
		$sql .= ", ".$this->total_ht;
261
		$sql .= ", ".$this->total_ttc;
262
		$sql .= ", ".$this->total_tva;
263
		$sql .= ", '".$this->db->idate($this->date_debut)."'";
264
		$sql .= ", '".$this->db->idate($this->date_fin)."'";
265
		$sql .= ", '".$this->db->idate($now)."'";
266
		$sql .= ", ".$fuserid;
267
		$sql .= ", ".($this->fk_user_validator > 0 ? $this->fk_user_validator : "null");
268
		$sql .= ", ".($this->fk_user_approve > 0 ? $this->fk_user_approve : "null");
269
		$sql .= ", ".($this->fk_user_modif > 0 ? $this->fk_user_modif : "null");
270
		$sql .= ", ".($this->fk_statut > 1 ? $this->fk_statut : 0);
1 ignored issue
show
Deprecated Code introduced by
The property ExpenseReport::$fk_statut has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

270
		$sql .= ", ".($this->fk_statut > 1 ? /** @scrutinizer ignore-deprecated */ $this->fk_statut : 0);
Loading history...
271
		$sql .= ", ".($this->modepaymentid ? $this->modepaymentid : "null");
272
		$sql .= ", 0";
273
		$sql .= ", ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : "null");
274
		$sql .= ", ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "null");
275
		$sql .= ", ".$conf->entity;
276
		$sql .= ")";
277
278
		$result = $this->db->query($sql);
279
		if ($result)
280
		{
281
			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
282
			$this->ref = '(PROV'.$this->id.')';
283
284
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET ref='".$this->db->escape($this->ref)."' WHERE rowid=".$this->id;
285
			$resql = $this->db->query($sql);
286
			if (!$resql)
287
			{
288
				$this->error = $this->db->lasterror();
289
				$error++;
290
			}
291
292
			if (!$error)
293
			{
294
				if (is_array($this->lines) && count($this->lines) > 0)
295
				{
296
					foreach ($this->lines as $line)
297
					{
298
						// Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
299
						//if (! is_object($line)) $line=json_decode(json_encode($line), false);  // convert recursively array into object.
300
						if (!is_object($line)) {
301
							$line = (object) $line;
302
							$newndfline = new ExpenseReportLine($this->db);
303
							$newndfline->fk_expensereport = $line->fk_expensereport;
304
							$newndfline->fk_c_type_fees = $line->fk_c_type_fees;
305
							$newndfline->fk_project = $line->fk_project;
306
							$newndfline->vatrate = $line->vatrate;
307
							$newndfline->vat_src_code = $line->vat_src_code;
308
							$newndfline->comments = $line->comments;
309
							$newndfline->qty = $line->qty;
310
							$newndfline->value_unit = $line->value_unit;
311
							$newndfline->total_ht = $line->total_ht;
312
							$newndfline->total_ttc = $line->total_ttc;
313
							$newndfline->total_tva = $line->total_tva;
314
							$newndfline->date = $line->date;
315
							$newndfline->rule_warning_message = $line->rule_warning_message;
316
							$newndfline->fk_c_exp_tax_cat = $line->fk_c_exp_tax_cat;
317
							$newndfline->fk_ecm_files = $line->fk_ecm_files;
318
						} else {
319
							$newndfline = $line;
320
						}
321
						//$newndfline=new ExpenseReportLine($this->db);
322
						$newndfline->fk_expensereport = $this->id;
323
						$result = $newndfline->insert();
324
						if ($result < 0)
325
						{
326
							$this->error = $newndfline->error;
327
							$error++;
328
							break;
329
						}
330
					}
331
				}
332
			}
333
334
			if (!$error)
335
			{
336
				$result = $this->insertExtraFields();
337
		   		if ($result < 0) $error++;
338
			}
339
340
			if (!$error)
341
			{
342
				$result = $this->update_price();
343
				if ($result > 0)
344
				{
345
					if (!$notrigger)
346
					{
347
						// Call trigger
348
						$result = $this->call_trigger('EXPENSE_REPORT_CREATE', $user);
349
350
						if ($result < 0) {
351
							$error++;
352
						}
353
						// End call triggers
354
					}
355
356
					if (empty($error))
357
					{
358
						$this->db->commit();
359
						return $this->id;
360
					} else {
361
						$this->db->rollback();
362
						return -4;
363
					}
364
				} else {
365
					$this->db->rollback();
366
					return -3;
367
				}
368
			} else {
369
				dol_syslog(get_class($this)."::create error ".$this->error, LOG_ERR);
370
				$this->db->rollback();
371
				return -2;
372
			}
373
		} else {
374
			$this->error = $this->db->lasterror()." sql=".$sql;
375
			$this->db->rollback();
376
			return -1;
377
		}
378
	}
379
380
381
	/**
382
	 *	Load an object from its id and create a new one in database
383
	 *
384
	 *  @param	    User	$user		        User making the clone
385
	 *	@param		int     $fk_user_author		Id of new user
386
	 *	@return		int							New id of clone
387
	 */
388
	public function createFromClone(User $user, $fk_user_author)
389
	{
390
		global $hookmanager;
391
392
		$error = 0;
393
394
		if (empty($fk_user_author)) $fk_user_author = $user->id;
395
396
		$this->db->begin();
397
398
		// get extrafields so they will be clone
399
		//foreach($this->lines as $line)
400
			//$line->fetch_optionals();
401
402
		// Load source object
403
		$objFrom = clone $this;
404
405
		$this->id = 0;
406
		$this->ref = '';
407
		$this->status = 0;
408
		$this->fk_statut = 0; // deprecated
1 ignored issue
show
Deprecated Code introduced by
The property ExpenseReport::$fk_statut has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

408
		/** @scrutinizer ignore-deprecated */ $this->fk_statut = 0; // deprecated
Loading history...
409
410
		// Clear fields
411
		$this->fk_user_author     = $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
412
		$this->fk_user_valid      = '';
413
		$this->date_create = '';
414
		$this->date_creation      = '';
415
		$this->date_validation    = '';
416
417
		// Remove link on lines to a joined file
418
		if (is_array($this->lines) && count($this->lines) > 0)
419
		{
420
			foreach ($this->lines as $key => $line)
421
			{
422
				$this->lines[$key]->fk_ecm_files = 0;
423
			}
424
		}
425
426
		// Create clone
427
		$this->context['createfromclone'] = 'createfromclone';
428
		$result = $this->create($user);
429
		if ($result < 0) $error++;
430
431
		if (!$error)
432
		{
433
			// Hook of thirdparty module
434
			if (is_object($hookmanager))
435
			{
436
				$parameters = array('objFrom'=>$objFrom);
437
				$action = '';
438
				$reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
439
				if ($reshook < 0) $error++;
440
			}
441
		}
442
443
		unset($this->context['createfromclone']);
444
445
		// End
446
		if (!$error)
447
		{
448
			$this->db->commit();
449
			return $this->id;
450
		} else {
451
			$this->db->rollback();
452
			return -1;
453
		}
454
	}
455
456
457
	/**
458
	 * update
459
	 *
460
	 * @param   User    $user                   User making change
461
	 * @param   int     $notrigger              Disable triggers
462
	 * @param   User    $userofexpensereport    New user we want to have the expense report on.
463
	 * @return  int                             <0 if KO, >0 if OK
464
	 */
465
	public function update($user, $notrigger = 0, $userofexpensereport = null)
466
	{
467
		global $langs;
468
469
		$error = 0;
470
		$this->db->begin();
471
472
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
473
		$sql .= " total_ht = ".$this->total_ht;
474
		$sql .= " , total_ttc = ".$this->total_ttc;
475
		$sql .= " , total_tva = ".$this->total_tva;
476
		$sql .= " , date_debut = '".$this->db->idate($this->date_debut)."'";
477
		$sql .= " , date_fin = '".$this->db->idate($this->date_fin)."'";
478
		if ($userofexpensereport && is_object($userofexpensereport))
479
		{
480
			$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.
481
		}
482
		$sql .= " , fk_user_validator = ".($this->fk_user_validator > 0 ? $this->fk_user_validator : "null");
483
		$sql .= " , fk_user_valid = ".($this->fk_user_valid > 0 ? $this->fk_user_valid : "null");
484
		$sql .= " , fk_user_approve = ".($this->fk_user_approve > 0 ? $this->fk_user_approve : "null");
485
		$sql .= " , fk_user_modif = ".$user->id;
486
		$sql .= " , fk_statut = ".($this->fk_statut >= 0 ? $this->fk_statut : '0');
1 ignored issue
show
Deprecated Code introduced by
The property ExpenseReport::$fk_statut has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

486
		$sql .= " , fk_statut = ".($this->fk_statut >= 0 ? /** @scrutinizer ignore-deprecated */ $this->fk_statut : '0');
Loading history...
487
		$sql .= " , fk_c_paiement = ".($this->fk_c_paiement > 0 ? $this->fk_c_paiement : "null");
488
		$sql .= " , note_public = ".(!empty($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "''");
489
		$sql .= " , note_private = ".(!empty($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "''");
490
		$sql .= " , detail_refuse = ".(!empty($this->detail_refuse) ? "'".$this->db->escape($this->detail_refuse)."'" : "''");
491
		$sql .= " WHERE rowid = ".$this->id;
492
493
		dol_syslog(get_class($this)."::update sql=".$sql, LOG_DEBUG);
494
		$result = $this->db->query($sql);
495
		if ($result)
496
		{
497
			if (!$notrigger)
498
			{
499
				// Call trigger
500
				$result = $this->call_trigger('EXPENSE_REPORT_UPDATE', $user);
501
502
				if ($result < 0) {
503
					$error++;
504
				}
505
				// End call triggers
506
			}
507
508
			if (empty($error))
509
			{
510
				$this->db->commit();
511
				return 1;
512
			} else {
513
				$this->db->rollback();
514
				$this->error = $this->db->error();
515
				return -2;
516
			}
517
		} else {
518
			$this->db->rollback();
519
			$this->error = $this->db->error();
520
			return -1;
521
		}
522
	}
523
524
	/**
525
	 *  Load an object from database
526
	 *
527
	 *  @param  int     $id     Id                      {@min 1}
528
	 *  @param  string  $ref    Ref                     {@name ref}
529
	 *  @return int             <0 if KO, >0 if OK
530
	 */
531
	public function fetch($id, $ref = '')
532
	{
533
		global $conf;
534
535
		$sql = "SELECT d.rowid, d.ref, d.note_public, d.note_private,"; // DEFAULT
536
		$sql .= " d.detail_refuse, d.detail_cancel, d.fk_user_refuse, d.fk_user_cancel,"; // ACTIONS
537
		$sql .= " d.date_refuse, d.date_cancel,"; // ACTIONS
538
		$sql .= " d.total_ht, d.total_ttc, d.total_tva,"; // TOTAUX (int)
539
		$sql .= " d.date_debut, d.date_fin, d.date_create, d.tms as date_modif, d.date_valid, d.date_approve,"; // DATES (datetime)
540
		$sql .= " d.fk_user_author, d.fk_user_modif, d.fk_user_validator,";
541
		$sql .= " d.fk_user_valid, d.fk_user_approve,";
542
		$sql .= " d.fk_statut as status, d.fk_c_paiement, d.paid";
543
		$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as d";
544
		if ($ref) $sql .= " WHERE d.ref = '".$this->db->escape($ref)."'";
545
		else $sql .= " WHERE d.rowid = ".$id;
546
		//$sql.= $restrict;
547
548
		dol_syslog(get_class($this)."::fetch sql=".$sql, LOG_DEBUG);
549
		$resql = $this->db->query($sql);
550
		if ($resql)
551
		{
552
			$obj = $this->db->fetch_object($resql);
553
			if ($obj)
554
			{
555
				$this->id           = $obj->rowid;
556
				$this->ref          = $obj->ref;
557
				$this->total_ht     = $obj->total_ht;
558
				$this->total_tva    = $obj->total_tva;
559
				$this->total_ttc    = $obj->total_ttc;
560
				$this->note_public  = $obj->note_public;
561
				$this->note_private = $obj->note_private;
562
				$this->detail_refuse = $obj->detail_refuse;
563
				$this->detail_cancel = $obj->detail_cancel;
564
565
				$this->date_debut       = $this->db->jdate($obj->date_debut);
566
				$this->date_fin         = $this->db->jdate($obj->date_fin);
567
				$this->date_valid       = $this->db->jdate($obj->date_valid);
568
				$this->date_approve     = $this->db->jdate($obj->date_approve);
569
				$this->date_create      = $this->db->jdate($obj->date_create);
570
				$this->date_modif       = $this->db->jdate($obj->date_modif);
571
				$this->date_refuse      = $this->db->jdate($obj->date_refuse);
572
				$this->date_cancel      = $this->db->jdate($obj->date_cancel);
573
574
				$this->fk_user_author           = $obj->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for.
575
				$this->fk_user_modif            = $obj->fk_user_modif;
576
				$this->fk_user_validator        = $obj->fk_user_validator;
577
				$this->fk_user_valid            = $obj->fk_user_valid;
578
				$this->fk_user_refuse           = $obj->fk_user_refuse;
579
				$this->fk_user_cancel           = $obj->fk_user_cancel;
580
				$this->fk_user_approve          = $obj->fk_user_approve;
581
582
				$user_author = new User($this->db);
583
				if ($this->fk_user_author > 0) $user_author->fetch($this->fk_user_author);
584
585
				$this->user_author_infos = dolGetFirstLastname($user_author->firstname, $user_author->lastname);
586
587
				$user_approver = new User($this->db);
588
				if ($this->fk_user_approve > 0) $user_approver->fetch($this->fk_user_approve);
589
				elseif ($this->fk_user_validator > 0) $user_approver->fetch($this->fk_user_validator); // For backward compatibility
590
				$this->user_validator_infos = dolGetFirstLastname($user_approver->firstname, $user_approver->lastname);
591
592
				$this->fk_statut                = $obj->status; // deprecated
593
				$this->status                   = $obj->status;
594
				$this->fk_c_paiement            = $obj->fk_c_paiement;
595
				$this->paid                     = $obj->paid;
596
597
				if ($this->status == self::STATUS_APPROVED || $this->status == self::STATUS_CLOSED)
598
				{
599
					$user_valid = new User($this->db);
600
					if ($this->fk_user_valid > 0) $user_valid->fetch($this->fk_user_valid);
601
					$this->user_valid_infos = dolGetFirstLastname($user_valid->firstname, $user_valid->lastname);
602
				}
603
604
				$this->fetch_optionals();
605
606
				$result = $this->fetch_lines();
607
608
				return $result;
609
			} else {
610
				return 0;
611
			}
612
		} else {
613
			$this->error = $this->db->lasterror();
614
			return -1;
615
		}
616
	}
617
618
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
619
	/**
620
	 *    Classify the expense report as paid
621
	 *
622
	 *    @param    int     $id                 Id of expense report
623
	 *    @param    user    $fuser              User making change
624
	 *    @param    int     $notrigger          Disable triggers
625
	 *    @return   int                         <0 if KO, >0 if OK
626
	 */
627
	public function set_paid($id, $fuser, $notrigger = 0)
628
	{
629
		// phpcs:enable
630
		$error = 0;
631
		$this->db->begin();
632
633
		$sql = "UPDATE ".MAIN_DB_PREFIX."expensereport";
634
		$sql .= " SET fk_statut = ".self::STATUS_CLOSED.", paid=1";
635
		$sql .= " WHERE rowid = ".$id." AND fk_statut = ".self::STATUS_APPROVED;
636
637
		dol_syslog(get_class($this)."::set_paid sql=".$sql, LOG_DEBUG);
638
		$resql = $this->db->query($sql);
639
		if ($resql)
640
		{
641
			if ($this->db->affected_rows($resql))
642
			{
643
				if (!$notrigger)
644
				{
645
					// Call trigger
646
					$result = $this->call_trigger('EXPENSE_REPORT_PAID', $fuser);
647
648
					if ($result < 0) {
649
						$error++;
650
					}
651
					// End call triggers
652
				}
653
654
				if (empty($error))
655
				{
656
					$this->db->commit();
657
					return 1;
658
				} else {
659
					$this->db->rollback();
660
					$this->error = $this->db->error();
661
					return -2;
662
				}
663
			} else {
664
				$this->db->commit();
665
				return 0;
666
			}
667
		} else {
668
			$this->db->rollback();
669
			dol_print_error($this->db);
670
			return -1;
671
		}
672
	}
673
674
	/**
675
	 *  Returns the label status
676
	 *
677
	 *  @param      int     $mode       0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
678
	 *  @return     string              Label
679
	 */
680
	public function getLibStatut($mode = 0)
681
	{
682
		return $this->LibStatut($this->status, $mode);
683
	}
684
685
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
686
	/**
687
	 *  Returns the label of a status
688
	 *
689
	 *  @param      int     $status     ID status
690
	 *  @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
691
	 *  @return     string              Label
692
	 */
693
	public function LibStatut($status, $mode = 0)
694
	{
695
		// phpcs:enable
696
		global $langs;
697
698
		$labelStatus = $langs->transnoentitiesnoconv($this->statuts[$status]);
699
		$labelStatusShort = $langs->transnoentitiesnoconv($this->statuts_short[$status]);
700
701
		$statusType = $this->statuts_logo[$status];
702
703
		return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
704
	}
705
706
707
	/**
708
	 *  Load information on object
709
	 *
710
	 *  @param  int     $id      Id of object
711
	 *  @return void
712
	 */
713
	public function info($id)
714
	{
715
		global $conf;
716
717
		$sql = "SELECT f.rowid,";
718
		$sql .= " f.date_create as datec,";
719
		$sql .= " f.tms as date_modification,";
720
		$sql .= " f.date_valid as datev,";
721
		$sql .= " f.date_approve as datea,";
722
		//$sql.= " f.fk_user_author as fk_user_creation,";      // This is not user of creation but user the expense is for.
723
		$sql .= " f.fk_user_modif as fk_user_modification,";
724
		$sql .= " f.fk_user_valid,";
725
		$sql .= " f.fk_user_approve";
726
		$sql .= " FROM ".MAIN_DB_PREFIX."expensereport as f";
727
		$sql .= " WHERE f.rowid = ".$id;
728
		$sql .= " AND f.entity = ".$conf->entity;
729
730
		$resql = $this->db->query($sql);
731
		if ($resql)
732
		{
733
			if ($this->db->num_rows($resql))
734
			{
735
				$obj = $this->db->fetch_object($resql);
736
737
				$this->id = $obj->rowid;
738
739
				$this->date_creation = $this->db->jdate($obj->datec);
740
				$this->date_modification = $this->db->jdate($obj->date_modification);
741
				$this->date_validation = $this->db->jdate($obj->datev);
742
				$this->date_approbation = $this->db->jdate($obj->datea);
743
744
				$cuser = new User($this->db);
745
				$cuser->fetch($obj->fk_user_author);
746
				$this->user_creation = $cuser;
747
748
				if ($obj->fk_user_creation)
749
				{
750
					$cuser = new User($this->db);
751
					$cuser->fetch($obj->fk_user_creation);
752
					$this->user_creation = $cuser;
753
				}
754
				if ($obj->fk_user_valid)
755
				{
756
					$vuser = new User($this->db);
757
					$vuser->fetch($obj->fk_user_valid);
758
					$this->user_validation = $vuser;
759
				}
760
				if ($obj->fk_user_modification)
761
				{
762
					$muser = new User($this->db);
763
					$muser->fetch($obj->fk_user_modification);
764
					$this->user_modification = $muser;
765
				}
766
				if ($obj->fk_user_approve)
767
				{
768
					$auser = new User($this->db);
769
					$auser->fetch($obj->fk_user_approve);
770
					$this->user_approve = $auser;
771
				}
772
			}
773
			$this->db->free($resql);
774
		} else {
775
			dol_print_error($this->db);
776
		}
777
	}
778
779
780
781
	/**
782
	 *  Initialise an instance with random values.
783
	 *  Used to build previews or test instances.
784
	 *  id must be 0 if object instance is a specimen.
785
	 *
786
	 *  @return void
787
	 */
788
	public function initAsSpecimen()
789
	{
790
		global $user, $langs, $conf;
791
792
		$now = dol_now();
793
794
		// Initialise parametres
795
		$this->id = 0;
796
		$this->ref = 'SPECIMEN';
797
		$this->specimen = 1;
798
		$this->date_create = $now;
799
		$this->date_debut = $now;
800
		$this->date_fin = $now;
801
		$this->date_valid = $now;
802
		$this->date_approve = $now;
803
804
		$type_fees_id = 2; // TF_TRIP
805
806
		$this->status = 5;
807
		$this->fk_statut = 5;
1 ignored issue
show
Deprecated Code introduced by
The property ExpenseReport::$fk_statut has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

807
		/** @scrutinizer ignore-deprecated */ $this->fk_statut = 5;
Loading history...
808
809
		$this->fk_user_author = $user->id;
810
		$this->fk_user_validator = $user->id;
811
		$this->fk_user_valid = $user->id;
812
		$this->fk_user_approve = $user->id;
813
814
		$this->note_private = 'Private note';
815
		$this->note_public = 'SPECIMEN';
816
		$nbp = 5;
817
		$xnbp = 0;
818
		while ($xnbp < $nbp) {
819
			$line = new ExpenseReportLine($this->db);
820
			$line->comments = $langs->trans("Comment")." ".$xnbp;
821
			$line->date = ($now - 3600 * (1 + $xnbp));
822
			$line->total_ht = 100;
823
			$line->total_tva = 20;
824
			$line->total_ttc = 120;
825
			$line->qty = 1;
826
			$line->vatrate = 20;
827
			$line->value_unit = 120;
828
			$line->fk_expensereport = 0;
829
			$line->type_fees_code = 'TRA';
830
			$line->fk_c_type_fees = $type_fees_id;
831
832
			$line->projet_ref = 'ABC';
833
834
			$this->lines[$xnbp] = $line;
835
			$xnbp++;
836
837
			$this->total_ht += $line->total_ht;
838
			$this->total_tva += $line->total_tva;
839
			$this->total_ttc += $line->total_ttc;
840
		}
841
	}
842
843
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
844
	/**
845
	 * fetch_line_by_project
846
	 *
847
	 * @param   int     $projectid      Project id
848
	 * @param   User    $user           User
849
	 * @return  int                     <0 if KO, >0 if OK
850
	 */
851
	public function fetch_line_by_project($projectid, $user = '')
852
	{
853
		// phpcs:enable
854
		global $conf, $db, $langs;
855
856
		$langs->load('trips');
857
858
		if ($user->rights->expensereport->lire) {
859
			$sql = "SELECT de.fk_expensereport, de.date, de.comments, de.total_ht, de.total_ttc";
860
			$sql .= " FROM ".MAIN_DB_PREFIX."expensereport_det as de";
861
			$sql .= " WHERE de.fk_projet = ".$projectid;
862
863
			dol_syslog(get_class($this)."::fetch sql=".$sql, LOG_DEBUG);
864
			$result = $this->db->query($sql);
865
			if ($result)
866
			{
867
				$num = $this->db->num_rows($result);
868
				$i = 0;
869
				$total_HT = 0;
870
				$total_TTC = 0;
871
872
				while ($i < $num)
873
				{
874
					$objp = $this->db->fetch_object($result);
875
876
					$sql2 = "SELECT d.rowid, d.fk_user_author, d.ref, d.fk_statut as status";
877
					$sql2 .= " FROM ".MAIN_DB_PREFIX."expensereport as d";
878
					$sql2 .= " WHERE d.rowid = ".((int) $objp->fk_expensereport);
879
880
					$result2 = $this->db->query($sql2);
881
					$obj = $this->db->fetch_object($result2);
882
883
					$objp->fk_user_author = $obj->fk_user_author;
884
					$objp->ref = $obj->ref;
885
					$objp->fk_c_expensereport_status = $obj->status;
886
					$objp->rowid = $obj->rowid;
887
888
					$total_HT = $total_HT + $objp->total_ht;
889
					$total_TTC = $total_TTC + $objp->total_ttc;
890
					$author = new User($this->db);
891
					$author->fetch($objp->fk_user_author);
892
893
					print '<tr>';
894
					print '<td><a href="'.DOL_URL_ROOT.'/expensereport/card.php?id='.$objp->rowid.'">'.$objp->ref_num.'</a></td>';
895
					print '<td class="center">'.dol_print_date($objp->date, 'day').'</td>';
896
					print '<td>'.$author->getNomUrl(1).'</td>';
897
					print '<td>'.$objp->comments.'</td>';
898
					print '<td class="right">'.price($objp->total_ht).'</td>';
899
					print '<td class="right">'.price($objp->total_ttc).'</td>';
900
					print '<td class="right">';
901
902
					switch ($objp->fk_c_expensereport_status) {
903
						case 4:
904
							print img_picto($langs->trans('StatusOrderCanceled'), 'statut5');
905
							break;
906
						case 1:
907
							print $langs->trans('Draft').' '.img_picto($langs->trans('Draft'), 'statut0');
908
							break;
909
						case 2:
910
							print $langs->trans('TripForValid').' '.img_picto($langs->trans('TripForValid'), 'statut3');
911
							break;
912
						case 5:
913
							print $langs->trans('TripForPaid').' '.img_picto($langs->trans('TripForPaid'), 'statut3');
914
							break;
915
						case 6:
916
							print $langs->trans('TripPaid').' '.img_picto($langs->trans('TripPaid'), 'statut4');
917
							break;
918
					}
919
					/*
920
                     if ($status==4) return img_picto($langs->trans('StatusOrderCanceled'),'statut5');
921
                    if ($status==1) return img_picto($langs->trans('StatusOrderDraft'),'statut0');
922
                    if ($status==2) return img_picto($langs->trans('StatusOrderValidated'),'statut1');
923
                    if ($status==2) return img_picto($langs->trans('StatusOrderOnProcess'),'statut3');
924
                    if ($status==5) return img_picto($langs->trans('StatusOrderToBill'),'statut4');
925
                    if ($status==6) return img_picto($langs->trans('StatusOrderOnProcess'),'statut6');
926
                    */
927
					print '</td>';
928
					print '</tr>';
929
930
					$i++;
931
				}
932
933
				print '<tr class="liste_total"><td colspan="4">'.$langs->trans("Number").': '.$i.'</td>';
934
				print '<td class="right" width="100">'.$langs->trans("TotalHT").' : '.price($total_HT).'</td>';
935
				print '<td class="right" width="100">'.$langs->trans("TotalTTC").' : '.price($total_TTC).'</td>';
936
				print '<td>&nbsp;</td>';
937
				print '</tr>';
938
			} else {
939
				$this->error = $this->db->lasterror();
940
				return -1;
941
			}
942
		}
943
	}
944
945
	/**
946
	 * recalculer
947
	 * TODO Replace this with call to update_price if not already done
948
	 *
949
	 * @param   int         $id     Id of expense report
950
	 * @return  int                 <0 if KO, >0 if OK
951
	 */
952
	public function recalculer($id)
953
	{
954
		$sql = 'SELECT tt.total_ht, tt.total_ttc, tt.total_tva';
955
		$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as tt';
956
		$sql .= ' WHERE tt.'.$this->fk_element.' = '.$id;
957
958
		$total_ht = 0; $total_tva = 0; $total_ttc = 0;
959
960
		$result = $this->db->query($sql);
961
		if ($result)
962
		{
963
			$num = $this->db->num_rows($result);
964
			$i = 0;
965
			while ($i < $num):
966
				$objp = $this->db->fetch_object($result);
967
				$total_ht += $objp->total_ht;
968
				$total_tva += $objp->total_tva;
969
				$i++;
970
			endwhile;
971
972
			$total_ttc = $total_ht + $total_tva;
973
			$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
974
			$sql .= " total_ht = ".$total_ht;
975
			$sql .= " , total_ttc = ".$total_ttc;
976
			$sql .= " , total_tva = ".$total_tva;
977
			$sql .= " WHERE rowid = ".$id;
978
			$result = $this->db->query($sql);
979
			if ($result):
980
				$this->db->free($result);
981
				return 1;
982
			else :
983
				$this->error = $this->db->lasterror();
984
				dol_syslog(get_class($this)."::recalculer: Error ".$this->error, LOG_ERR);
985
				return -3;
986
			endif;
987
		} else {
988
			$this->error = $this->db->lasterror();
989
			dol_syslog(get_class($this)."::recalculer: Error ".$this->error, LOG_ERR);
990
			return -3;
991
		}
992
	}
993
994
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
995
	/**
996
	 * fetch_lines
997
	 *
998
	 * @return  int     <0 if OK, >0 if KO
999
	 */
1000
	public function fetch_lines()
1001
	{
1002
		// phpcs:enable
1003
		global $conf;
1004
1005
		$this->lines = array();
1006
1007
		$sql = ' SELECT de.rowid, de.comments, de.qty, de.value_unit, de.date, de.rang,';
1008
		$sql .= ' de.'.$this->fk_element.', de.fk_c_type_fees, de.fk_c_exp_tax_cat, de.fk_projet as fk_project, de.tva_tx, de.fk_ecm_files,';
1009
		$sql .= ' de.total_ht, de.total_tva, de.total_ttc,';
1010
		$sql .= ' ctf.code as code_type_fees, ctf.label as libelle_type_fees,';
1011
		$sql .= ' p.ref as ref_projet, p.title as title_projet';
1012
		$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as de';
1013
		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_type_fees as ctf ON de.fk_c_type_fees = ctf.id';
1014
		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as p ON de.fk_projet = p.rowid';
1015
		$sql .= ' WHERE de.'.$this->fk_element.' = '.$this->id;
1016
		if (!empty($conf->global->EXPENSEREPORT_LINES_SORTED_BY_ROWID))
1017
		{
1018
			$sql .= ' ORDER BY de.rang ASC, de.rowid ASC';
1019
		} else {
1020
			$sql .= ' ORDER BY de.rang ASC, de.date ASC';
1021
		}
1022
1023
		$resql = $this->db->query($sql);
1024
		if ($resql)
1025
		{
1026
			$num = $this->db->num_rows($resql);
1027
			$i = 0;
1028
			while ($i < $num)
1029
			{
1030
				$objp = $this->db->fetch_object($resql);
1031
1032
				$deplig = new ExpenseReportLine($this->db);
1033
1034
				$deplig->rowid          = $objp->rowid;
1035
				$deplig->id             = $objp->rowid;
1036
				$deplig->comments       = $objp->comments;
1037
				$deplig->qty            = $objp->qty;
1038
				$deplig->value_unit     = $objp->value_unit;
1039
				$deplig->date           = $objp->date;
1040
				$deplig->dates          = $this->db->jdate($objp->date);
1041
1042
				$deplig->fk_expensereport = $objp->fk_expensereport;
1043
				$deplig->fk_c_type_fees   = $objp->fk_c_type_fees;
1044
				$deplig->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
1045
				$deplig->fk_projet        = $objp->fk_project; // deprecated
1046
				$deplig->fk_project       = $objp->fk_project;
1047
				$deplig->fk_ecm_files     = $objp->fk_ecm_files;
1048
1049
				$deplig->total_ht         = $objp->total_ht;
1050
				$deplig->total_tva        = $objp->total_tva;
1051
				$deplig->total_ttc        = $objp->total_ttc;
1052
1053
				$deplig->type_fees_code     = empty($objp->code_type_fees) ? 'TF_OTHER' : $objp->code_type_fees;
1054
				$deplig->type_fees_libelle  = $objp->libelle_type_fees;
1055
				$deplig->tva_tx = $objp->tva_tx;
1056
				$deplig->vatrate            = $objp->tva_tx;
1057
				$deplig->projet_ref         = $objp->ref_projet;
1058
				$deplig->projet_title       = $objp->title_projet;
1059
1060
				$deplig->rang               = $objp->rang;
1061
1062
				$this->lines[$i] = $deplig;
1063
1064
				$i++;
1065
			}
1066
			$this->db->free($resql);
1067
			return 1;
1068
		} else {
1069
			$this->error = $this->db->lasterror();
1070
			dol_syslog(get_class($this)."::fetch_lines: Error ".$this->error, LOG_ERR);
1071
			return -3;
1072
		}
1073
	}
1074
1075
1076
	/**
1077
	 * Delete object in database
1078
	 *
1079
	 * @param   User    $fuser      User that delete
1080
	 * @param 	bool 	$notrigger  false=launch triggers after, true=disable triggers
1081
	 * @return  int                 <0 if KO, >0 if OK
1082
	 */
1083
	public function delete(User $fuser = null, $notrigger = false)
1084
	{
1085
		global $conf;
1086
		require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1087
1088
		$error = 0;
1089
1090
		$this->db->begin();
1091
1092
		if (!$notrigger) {
1093
			// Call trigger
1094
			$result = $this->call_trigger('EXPENSEREPORT_DELETE', $user);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $user does not exist. Did you maybe mean $fuser?
Loading history...
1095
			if ($result < 0) { $error++; }
1096
			// End call triggers
1097
		}
1098
1099
		// Delete extrafields of lines and lines
1100
		if (!$error && !empty($this->table_element_line)) {
1101
			$tabletodelete = $this->table_element_line;
1102
			//$sqlef = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete."_extrafields WHERE fk_object IN (SELECT rowid FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".$this->id.")";
1103
			$sql = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".$this->id;
1104
			if (! $this->db->query($sql)) {
1105
				$error++;
1106
				$this->error = $this->db->lasterror();
1107
				dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1108
			}
1109
		}
1110
1111
		// Removed extrafields of object
1112
		if (!$error) {
1113
			$result = $this->deleteExtraFields();
1114
			if ($result < 0) {
1115
				$error++;
1116
				dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1117
			}
1118
		}
1119
1120
		// Delete main record
1121
		if (!$error) {
1122
			$sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".$this->id;
1123
			$res = $this->db->query($sql);
1124
			if (! $res) {
1125
				$error++;
1126
				dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
1127
			}
1128
		}
1129
1130
		if (! $error) {
1131
			// Delete linked object
1132
			$res = $this->deleteObjectLinked();
1133
			if ($res < 0) $error++;
1134
		}
1135
1136
		if (! $error) {
1137
			// Delete linked contacts
1138
			$res = $this->delete_linked_contact();
1139
			if ($res < 0) $error++;
1140
		}
1141
1142
		// Delete record into ECM index and physically
1143
		if (!$error) {
1144
			$res = $this->deleteEcmFiles(); // Deleting files physically is done later with the dol_delete_dir_recursive
1145
			if (! $res) {
1146
				$error++;
1147
			}
1148
		}
1149
1150
		if (!$error) {
1151
			// We remove directory
1152
			$ref = dol_sanitizeFileName($this->ref);
1153
			if ($conf->propal->multidir_output[$this->entity] && !empty($this->ref)) {
1154
				$dir = $conf->propal->multidir_output[$this->entity]."/".$ref;
1155
				$file = $dir."/".$ref.".pdf";
1156
				if (file_exists($file)) {
1157
					dol_delete_preview($this);
1158
1159
					if (!dol_delete_file($file, 0, 0, 0, $this)) {
1160
						$this->error = 'ErrorFailToDeleteFile';
1161
						$this->errors = array('ErrorFailToDeleteFile');
1162
						$this->db->rollback();
1163
						return 0;
1164
					}
1165
				}
1166
				if (file_exists($dir)) {
1167
					$res = @dol_delete_dir_recursive($dir);
1168
					if (!$res) {
1169
						$this->error = 'ErrorFailToDeleteDir';
1170
						$this->errors = array('ErrorFailToDeleteDir');
1171
						$this->db->rollback();
1172
						return 0;
1173
					}
1174
				}
1175
			}
1176
		}
1177
1178
		if (!$error) {
1179
			dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
1180
			$this->db->commit();
1181
			return 1;
1182
		} else {
1183
			$this->db->rollback();
1184
			return -1;
1185
		}
1186
    }
1187
1188
	/**
1189
	 * Set to status validate
1190
	 *
1191
	 * @param   User    $fuser      User
1192
	 * @param   int     $notrigger  Disable triggers
1193
	 * @return  int                 <0 if KO, 0 if nothing done, >0 if OK
1194
	 */
1195
	public function setValidate($fuser, $notrigger = 0)
1196
	{
1197
		global $conf, $langs, $user;
1198
1199
		$error = 0;
1200
		$now = dol_now();
1201
1202
		// Protection
1203
		if ($this->status == self::STATUS_VALIDATED)
1204
		{
1205
			dol_syslog(get_class($this)."::valid action abandonned: already validated", LOG_WARNING);
1206
			return 0;
1207
		}
1208
1209
		$this->date_valid = $now; // Required for the getNextNum later.
1210
1211
		// Define new ref
1212
		if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life
1213
		{
1214
			$num = $this->getNextNumRef();
1215
		} else {
1216
			$num = $this->ref;
1217
		}
1218
		if (empty($num) || $num < 0) return -1;
1219
1220
		$this->newref = dol_sanitizeFileName($num);
1221
1222
		$this->db->begin();
1223
1224
		// Validate
1225
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1226
		$sql .= " SET ref = '".$this->db->escape($num)."',";
1227
		$sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
1228
		$sql .= " date_valid='".$this->db->idate($this->date_valid)."',";
1229
		$sql .= " fk_user_valid = ".$user->id;
1230
		$sql .= " WHERE rowid = ".$this->id;
1231
1232
		$resql = $this->db->query($sql);
1233
		if ($resql)
1234
		{
1235
			if (!$error && !$notrigger)
1236
			{
1237
				// Call trigger
1238
				$result = $this->call_trigger('EXPENSE_REPORT_VALIDATE', $fuser);
1239
				if ($result < 0) {
1240
					$error++;
1241
				}
1242
				// End call triggers
1243
			}
1244
1245
			if (!$error)
1246
			{
1247
				$this->oldref = $this->ref;
1248
1249
				// Rename directory if dir was a temporary ref
1250
				if (preg_match('/^[\(]?PROV/i', $this->ref))
1251
				{
1252
					require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1253
1254
					// Now we rename also files into index
1255
					$sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'expensereport/".$this->db->escape($this->newref)."'";
1256
					$sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'expensereport/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
1257
					$resql = $this->db->query($sql);
1258
					if (!$resql) { $error++; $this->error = $this->db->lasterror(); }
1259
1260
					// We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
1261
					$oldref = dol_sanitizeFileName($this->ref);
1262
					$newref = dol_sanitizeFileName($num);
1263
					$dirsource = $conf->expensereport->dir_output.'/'.$oldref;
1264
					$dirdest = $conf->expensereport->dir_output.'/'.$newref;
1265
					if (!$error && file_exists($dirsource))
1266
					{
1267
						dol_syslog(get_class($this)."::setValidate() rename dir ".$dirsource." into ".$dirdest);
1268
1269
						if (@rename($dirsource, $dirdest))
1270
						{
1271
							dol_syslog("Rename ok");
1272
							// Rename docs starting with $oldref with $newref
1273
							$listoffiles = dol_dir_list($conf->expensereport->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
1274
							foreach ($listoffiles as $fileentry)
1275
							{
1276
								$dirsource = $fileentry['name'];
1277
								$dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
1278
								$dirsource = $fileentry['path'].'/'.$dirsource;
1279
								$dirdest = $fileentry['path'].'/'.$dirdest;
1280
								@rename($dirsource, $dirdest);
1281
							}
1282
						}
1283
					}
1284
				}
1285
			}
1286
1287
			// Set new ref and current status
1288
			if (!$error)
1289
			{
1290
				$this->ref = $num;
1291
				$this->status = self::STATUS_VALIDATED;
1292
			}
1293
1294
			if (empty($error))
1295
			{
1296
				$this->db->commit();
1297
				return 1;
1298
			} else {
1299
				$this->db->rollback();
1300
				$this->error = $this->db->error();
1301
				return -2;
1302
			}
1303
		} else {
1304
			$this->db->rollback();
1305
			$this->error = $this->db->lasterror();
1306
			return -1;
1307
		}
1308
	}
1309
1310
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1311
	/**
1312
	 * set_save_from_refuse
1313
	 *
1314
	 * @param   User    $fuser      User
1315
	 * @return  int                 <0 if KO, >0 if OK
1316
	 */
1317
	public function set_save_from_refuse($fuser)
1318
	{
1319
		// phpcs:enable
1320
		global $conf, $langs;
1321
1322
		// Sélection de la date de début de la NDF
1323
		$sql = 'SELECT date_debut';
1324
		$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
1325
		$sql .= ' WHERE rowid = '.$this->id;
1326
1327
		$result = $this->db->query($sql);
1328
1329
		$objp = $this->db->fetch_object($result);
1330
1331
		$this->date_debut = $this->db->jdate($objp->date_debut);
1332
1333
		if ($this->status != self::STATUS_VALIDATED)
1334
		{
1335
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1336
			$sql .= " SET fk_statut = ".self::STATUS_VALIDATED;
1337
			$sql .= ' WHERE rowid = '.$this->id;
1338
1339
			dol_syslog(get_class($this)."::set_save_from_refuse sql=".$sql, LOG_DEBUG);
1340
1341
			if ($this->db->query($sql))
1342
			{
1343
				return 1;
1344
			} else {
1345
				$this->error = $this->db->lasterror();
1346
				return -1;
1347
			}
1348
		} else {
1349
			dol_syslog(get_class($this)."::set_save_from_refuse expensereport already with save status", LOG_WARNING);
1350
		}
1351
	}
1352
1353
	/**
1354
	 * Set status to approved
1355
	 *
1356
	 * @param   User    $fuser      User
1357
	 * @param   int     $notrigger  Disable triggers
1358
	 * @return  int                 <0 if KO, 0 if nothing done, >0 if OK
1359
	 */
1360
	public function setApproved($fuser, $notrigger = 0)
1361
	{
1362
		$now = dol_now();
1363
		$error = 0;
1364
1365
		// date approval
1366
		$this->date_approve = $now;
1367
		if ($this->status != self::STATUS_APPROVED)
1368
		{
1369
			$this->db->begin();
1370
1371
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1372
			$sql .= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = ".self::STATUS_APPROVED.", fk_user_approve = ".$fuser->id.",";
1373
			$sql .= " date_approve='".$this->db->idate($this->date_approve)."'";
1374
			$sql .= ' WHERE rowid = '.$this->id;
1375
			if ($this->db->query($sql))
1376
			{
1377
				if (!$notrigger)
1378
				{
1379
					// Call trigger
1380
					$result = $this->call_trigger('EXPENSE_REPORT_APPROVE', $fuser);
1381
1382
					if ($result < 0) {
1383
						$error++;
1384
					}
1385
					// End call triggers
1386
				}
1387
1388
				if (empty($error))
1389
				{
1390
					$this->db->commit();
1391
					return 1;
1392
				} else {
1393
					$this->db->rollback();
1394
					$this->error = $this->db->error();
1395
					return -2;
1396
				}
1397
			} else {
1398
				$this->db->rollback();
1399
				$this->error = $this->db->lasterror();
1400
				return -1;
1401
			}
1402
		} else {
1403
			dol_syslog(get_class($this)."::setApproved expensereport already with approve status", LOG_WARNING);
1404
		}
1405
1406
		return 0;
1407
	}
1408
1409
	/**
1410
	 * setDeny
1411
	 *
1412
	 * @param User      $fuser      User
1413
	 * @param string    $details    Details
1414
	 * @param int       $notrigger  Disable triggers
1415
	 * @return int
1416
	 */
1417
	public function setDeny($fuser, $details, $notrigger = 0)
1418
	{
1419
		$now = dol_now();
1420
		$error = 0;
1421
1422
		// date de refus
1423
		if ($this->status != self::STATUS_REFUSED)
1424
		{
1425
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1426
			$sql .= " SET ref = '".$this->db->escape($this->ref)."', fk_statut = ".self::STATUS_REFUSED.", fk_user_refuse = ".$fuser->id.",";
1427
			$sql .= " date_refuse='".$this->db->idate($now)."',";
1428
			$sql .= " detail_refuse='".$this->db->escape($details)."',";
1429
			$sql .= " fk_user_approve = NULL";
1430
			$sql .= ' WHERE rowid = '.$this->id;
1431
			if ($this->db->query($sql))
1432
			{
1433
				$this->fk_statut = 99; // deprecated
1 ignored issue
show
Deprecated Code introduced by
The property ExpenseReport::$fk_statut has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1433
				/** @scrutinizer ignore-deprecated */ $this->fk_statut = 99; // deprecated
Loading history...
1434
				$this->status = 99;
1435
				$this->fk_user_refuse = $fuser->id;
1436
				$this->detail_refuse = $details;
1437
				$this->date_refuse = $now;
1438
1439
				if (!$notrigger)
1440
				{
1441
					// Call trigger
1442
					$result = $this->call_trigger('EXPENSE_REPORT_DENY', $fuser);
1443
1444
					if ($result < 0) {
1445
						$error++;
1446
					}
1447
					// End call triggers
1448
				}
1449
1450
				if (empty($error))
1451
				{
1452
					$this->db->commit();
1453
					return 1;
1454
				} else {
1455
					$this->db->rollback();
1456
					$this->error = $this->db->error();
1457
					return -2;
1458
				}
1459
			} else {
1460
				$this->db->rollback();
1461
				$this->error = $this->db->lasterror();
1462
				return -1;
1463
			}
1464
		} else {
1465
			dol_syslog(get_class($this)."::setDeny expensereport already with refuse status", LOG_WARNING);
1466
		}
1467
	}
1468
1469
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1470
	/**
1471
	 * set_unpaid
1472
	 *
1473
	 * @param   User    $fuser      User
1474
	 * @param   int     $notrigger  Disable triggers
1475
	 * @return  int                 <0 if KO, >0 if OK
1476
	 */
1477
	public function set_unpaid($fuser, $notrigger = 0)
1478
	{
1479
		// phpcs:enable
1480
		$error = 0;
1481
1482
		if ($this->paid)
1483
		{
1484
			$this->db->begin();
1485
1486
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1487
			$sql .= " SET paid = 0, fk_statut = ".self::STATUS_APPROVED;
1488
			$sql .= ' WHERE rowid = '.$this->id;
1489
1490
			dol_syslog(get_class($this)."::set_unpaid sql=".$sql, LOG_DEBUG);
1491
1492
			if ($this->db->query($sql))
1493
			{
1494
				if (!$notrigger)
1495
				{
1496
					// Call trigger
1497
					$result = $this->call_trigger('EXPENSE_REPORT_UNPAID', $fuser);
1498
1499
					if ($result < 0) {
1500
						$error++;
1501
					}
1502
					// End call triggers
1503
				}
1504
1505
				if (empty($error))
1506
				{
1507
					$this->db->commit();
1508
					return 1;
1509
				} else {
1510
					$this->db->rollback();
1511
					$this->error = $this->db->error();
1512
					return -2;
1513
				}
1514
			} else {
1515
				$this->db->rollback();
1516
				$this->error = $this->db->error();
1517
				return -1;
1518
			}
1519
		} else {
1520
			dol_syslog(get_class($this)."::set_unpaid expensereport already with unpaid status", LOG_WARNING);
1521
		}
1522
	}
1523
1524
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1525
	/**
1526
	 * set_cancel
1527
	 *
1528
	 * @param   User    $fuser      User
1529
	 * @param   string  $detail     Detail
1530
	 * @param   int     $notrigger  Disable triggers
1531
	 * @return  int                 <0 if KO, >0 if OK
1532
	 */
1533
	public function set_cancel($fuser, $detail, $notrigger = 0)
1534
	{
1535
		// phpcs:enable
1536
		$error = 0;
1537
		$this->date_cancel = $this->db->idate(dol_now());
1538
		if ($this->status != self::STATUS_CANCELED)
1539
		{
1540
			$this->db->begin();
1541
1542
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1543
			$sql .= " SET fk_statut = ".self::STATUS_CANCELED.", fk_user_cancel = ".$fuser->id;
1544
			$sql .= ", date_cancel='".$this->db->idate($this->date_cancel)."'";
1545
			$sql .= " ,detail_cancel='".$this->db->escape($detail)."'";
1546
			$sql .= ' WHERE rowid = '.$this->id;
1547
1548
			dol_syslog(get_class($this)."::set_cancel sql=".$sql, LOG_DEBUG);
1549
1550
			if ($this->db->query($sql))
1551
			{
1552
				if (!$notrigger)
1553
				{
1554
					// Call trigger
1555
					$result = $this->call_trigger('EXPENSE_REPORT_CANCEL', $fuser);
1556
1557
					if ($result < 0) {
1558
						$error++;
1559
					}
1560
					// End call triggers
1561
				}
1562
1563
				if (empty($error))
1564
				{
1565
					$this->db->commit();
1566
					return 1;
1567
				} else {
1568
					$this->db->rollback();
1569
					$this->error = $this->db->error();
1570
					return -2;
1571
				}
1572
			} else {
1573
				$this->db->rollback();
1574
				$this->error = $this->db->error();
1575
				return -1;
1576
			}
1577
		} else {
1578
			dol_syslog(get_class($this)."::set_cancel expensereport already with cancel status", LOG_WARNING);
1579
		}
1580
	}
1581
1582
	/**
1583
	 * Return next reference of expense report not already used
1584
	 *
1585
	 * @return    string            free ref
1586
	 */
1587
	public function getNextNumRef()
1588
	{
1589
		global $langs, $conf;
1590
		$langs->load("trips");
1591
1592
		if (!empty($conf->global->EXPENSEREPORT_ADDON))
1593
		{
1594
			$mybool = false;
1595
1596
			$file = $conf->global->EXPENSEREPORT_ADDON.".php";
1597
			$classname = $conf->global->EXPENSEREPORT_ADDON;
1598
1599
			// Include file with class
1600
			$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1601
			foreach ($dirmodels as $reldir)
1602
			{
1603
				$dir = dol_buildpath($reldir."core/modules/expensereport/");
1604
1605
				// Load file with numbering class (if found)
1606
				$mybool |= @include_once $dir.$file;
1607
			}
1608
1609
			if ($mybool === false) {
1610
				dol_print_error('', "Failed to include file ".$file);
1611
				return '';
1612
			}
1613
1614
			$obj = new $classname();
1615
			$numref = $obj->getNextValue($this);
1616
1617
			if ($numref != "")
1618
			{
1619
				return $numref;
1620
			} else {
1621
				$this->error = $obj->error;
1622
				$this->errors = $obj->errors;
1623
				//dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1624
				return -1;
1625
			}
1626
		} else {
1627
			$this->error = "Error_EXPENSEREPORT_ADDON_NotDefined";
1628
			return -2;
1629
		}
1630
	}
1631
1632
	/**
1633
	 *  Return clicable name (with picto eventually)
1634
	 *
1635
	 *	@param		int		$withpicto					0=No picto, 1=Include picto into link, 2=Only picto
1636
	 *	@param		int		$max						Max length of shown ref
1637
	 *	@param		int		$short						1=Return just URL
1638
	 *	@param		string	$moretitle					Add more text to title tooltip
1639
	 *	@param		int		$notooltip					1=Disable tooltip
1640
	 *  @param  	int     $save_lastsearch_value    	-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
1641
	 *	@return		string								String with URL
1642
	 */
1643
	public function getNomUrl($withpicto = 0, $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1)
1644
	{
1645
		global $langs, $conf;
1646
1647
		$result = '';
1648
1649
		$url = DOL_URL_ROOT.'/expensereport/card.php?id='.$this->id;
1650
1651
		if ($short) return $url;
1652
1653
		$label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("ExpenseReport").'</u>';
1654
		if (isset($this->status)) {
1655
			$label .= ' '.$this->getLibStatut(5);
1656
		}
1657
		if (!empty($this->ref))
1658
			$label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1659
		if (!empty($this->total_ht))
1660
			$label .= '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
1661
		if (!empty($this->total_tva))
1662
			$label .= '<br><b>'.$langs->trans('VAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
1663
		if (!empty($this->total_ttc))
1664
			$label .= '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
1665
		if ($moretitle) $label .= ' - '.$moretitle;
1666
1667
		//if ($option != 'nolink')
1668
		//{
1669
		// Add param to save lastsearch_values or not
1670
			$add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1671
			if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values = 1;
1672
			if ($add_save_lastsearch_values) $url .= '&save_lastsearch_values=1';
1673
		//}
1674
1675
		$ref = $this->ref;
1676
		if (empty($ref)) $ref = $this->id;
1677
1678
		$linkclose = '';
1679
		if (empty($notooltip))
1680
		{
1681
			if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
1682
			{
1683
				$label = $langs->trans("ShowExpenseReport");
1684
				$linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1685
			}
1686
			$linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1687
			$linkclose .= ' class="classfortooltip"';
1688
		}
1689
1690
		$linkstart = '<a href="'.$url.'"';
1691
		$linkstart .= $linkclose.'>';
1692
		$linkend = '</a>';
1693
1694
		$result .= $linkstart;
1695
		if ($withpicto) $result .= img_object(($notooltip ? '' : $label), $this->picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
1696
		if ($withpicto != 2) $result .= ($max ?dol_trunc($ref, $max) : $ref);
1697
		$result .= $linkend;
1698
1699
		return $result;
1700
	}
1701
1702
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1703
	/**
1704
	 *  Update total of an expense report when you add a line.
1705
	 *
1706
	 *  @param    string    $ligne_total_ht    Amount without taxes
1707
	 *  @param    string    $ligne_total_tva    Amount of all taxes
1708
	 *  @return    void
1709
	 */
1710
	public function update_totaux_add($ligne_total_ht, $ligne_total_tva)
1711
	{
1712
		// phpcs:enable
1713
		$this->total_ht = $this->total_ht + $ligne_total_ht;
1714
		$this->total_tva = $this->total_tva + $ligne_total_tva;
1715
		$this->total_ttc = $this->total_ht + $this->total_tva;
1716
1717
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
1718
		$sql .= " total_ht = ".$this->total_ht;
1719
		$sql .= " , total_ttc = ".$this->total_ttc;
1720
		$sql .= " , total_tva = ".$this->total_tva;
1721
		$sql .= " WHERE rowid = ".$this->id;
1722
1723
		$result = $this->db->query($sql);
1724
		if ($result):
1725
			return 1;
1726
		else :
1727
			$this->error = $this->db->error();
1728
			return -1;
1729
		endif;
1730
	}
1731
1732
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1733
	/**
1734
	 *  Update total of an expense report when you delete a line.
1735
	 *
1736
	 *  @param    string    $ligne_total_ht    Amount without taxes
1737
	 *  @param    string    $ligne_total_tva    Amount of all taxes
1738
	 *  @return    void
1739
	 */
1740
	public function update_totaux_del($ligne_total_ht, $ligne_total_tva)
1741
	{
1742
		// phpcs:enable
1743
		$this->total_ht = $this->total_ht - $ligne_total_ht;
1744
		$this->total_tva = $this->total_tva - $ligne_total_tva;
1745
		$this->total_ttc = $this->total_ht + $this->total_tva;
1746
1747
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
1748
		$sql .= " total_ht = ".$this->total_ht;
1749
		$sql .= " , total_ttc = ".$this->total_ttc;
1750
		$sql .= " , total_tva = ".$this->total_tva;
1751
		$sql .= " WHERE rowid = ".$this->id;
1752
1753
		$result = $this->db->query($sql);
1754
		if ($result):
1755
			return 1;
1756
		else :
1757
			$this->error = $this->db->error();
1758
			return -1;
1759
		endif;
1760
	}
1761
1762
	/**
1763
	 * addline
1764
	 *
1765
	 * @param    float       $qty                      Qty
1766
	 * @param    double      $up                       Value init
1767
	 * @param    int         $fk_c_type_fees           Type payment
1768
	 * @param    string      $vatrate                  Vat rate (Can be '10' or '10 (ABC)')
1769
	 * @param    string      $date                     Date
1770
	 * @param    string      $comments                 Description
1771
	 * @param    int         $fk_project               Project id
1772
	 * @param    int         $fk_c_exp_tax_cat         Car category id
1773
	 * @param    int         $type                     Type line
1774
	 * @param    int         $fk_ecm_files             Id of ECM file to link to this expensereport line
1775
	 * @return   int                                   <0 if KO, >0 if OK
1776
	 */
1777
	public function addline($qty = 0, $up = 0, $fk_c_type_fees = 0, $vatrate = 0, $date = '', $comments = '', $fk_project = 0, $fk_c_exp_tax_cat = 0, $type = 0, $fk_ecm_files = 0)
1778
	{
1779
		global $conf, $langs, $mysoc;
1780
1781
		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);
1782
1783
		if ($this->status == self::STATUS_DRAFT)
1784
		{
1785
			if (empty($qty)) $qty = 0;
1786
			if (empty($fk_c_type_fees) || $fk_c_type_fees < 0) $fk_c_type_fees = 0;
1787
			if (empty($fk_c_exp_tax_cat) || $fk_c_exp_tax_cat < 0) $fk_c_exp_tax_cat = 0;
1788
			if (empty($vatrate) || $vatrate < 0) $vatrate = 0;
1789
			if (empty($date)) $date = '';
1790
			if (empty($fk_project)) $fk_project = 0;
1791
1792
			$qty = price2num($qty);
1793
			if (!preg_match('/\s*\((.*)\)/', $vatrate)) {
1794
				$vatrate = price2num($vatrate); // $txtva can have format '5.0 (XXX)' or '5'
1795
			}
1796
			$up = price2num($up);
1797
1798
			$this->db->begin();
1799
1800
			$this->line = new ExpenseReportLine($this->db);
1801
1802
			$localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $mysoc, $this->thirdparty);
1803
1804
			$vat_src_code = '';
1805
			if (preg_match('/\s*\((.*)\)/', $vatrate, $reg))
1806
			{
1807
				$vat_src_code = $reg[1];
1808
				$vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate.
1809
			}
1810
			$vatrate = preg_replace('/\*/', '', $vatrate);
1811
1812
			$seller = ''; // seller is unknown
1813
1814
			$tmp = calcul_price_total($qty, $up, 0, $vatrate, 0, 0, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
1815
1816
			$this->line->value_unit = $up;
1817
			$this->line->vat_src_code = $vat_src_code;
1818
			$this->line->vatrate = price2num($vatrate);
1819
			$this->line->total_ttc = $tmp[2];
1820
			$this->line->total_ht = $tmp[0];
1821
			$this->line->total_tva = $tmp[1];
1822
1823
			$this->line->fk_expensereport = $this->id;
1824
			$this->line->qty = $qty;
1825
			$this->line->date = $date;
1826
			$this->line->fk_c_type_fees = $fk_c_type_fees;
1827
			$this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
1828
			$this->line->comments = $comments;
1829
			$this->line->fk_projet = $fk_project; // deprecated
1830
			$this->line->fk_project = $fk_project;
1831
1832
			$this->line->fk_ecm_files = $fk_ecm_files;
1833
1834
			$this->applyOffset();
1835
			$this->checkRules($type, $seller);
1836
1837
			$result = $this->line->insert(0, true);
1838
			if ($result > 0)
1839
			{
1840
				$result = $this->update_price(); // This method is designed to add line from user input so total calculation must be done using 'auto' mode.
1841
				if ($result > 0)
1842
				{
1843
					$this->db->commit();
1844
					return $this->line->id;
1845
				} else {
1846
					$this->db->rollback();
1847
					return -1;
1848
				}
1849
			} else {
1850
				$this->error = $this->line->error;
1851
				dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1852
				$this->db->rollback();
1853
				return -2;
1854
			}
1855
		} else {
1856
			dol_syslog(get_class($this)."::addline status of expense report must be Draft to allow use of ->addline()", LOG_ERR);
1857
			$this->error = 'ErrorExpenseNotDraft';
1858
			return -3;
1859
		}
1860
	}
1861
1862
	/**
1863
	 * Check constraint of rules and update price if needed
1864
	 *
1865
	 * @param	int		$type		type of line
1866
	 * @param	string	$seller		seller, but actually he is unknown
1867
	 * @return true or false
1868
	 */
1869
	public function checkRules($type = 0, $seller = '')
1870
	{
1871
		global $user, $conf, $db, $langs;
1872
1873
		$langs->load('trips');
1874
1875
		if (empty($conf->global->MAIN_USE_EXPENSE_RULE)) return true; // if don't use rules
1876
1877
		$rulestocheck = ExpenseReportRule::getAllRule($this->line->fk_c_type_fees, $this->line->date, $this->fk_user_author);
1878
1879
		$violation = 0;
1880
		$rule_warning_message_tab = array();
1881
1882
		$current_total_ttc = $this->line->total_ttc;
1883
		$new_current_total_ttc = $this->line->total_ttc;
1884
1885
		// check if one is violated
1886
		foreach ($rulestocheck as $rule)
1887
		{
1888
			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);
1889
			else $amount_to_test = $current_total_ttc; // EX_EXP
1890
1891
			$amount_to_test = $amount_to_test - $current_total_ttc + $new_current_total_ttc; // if amount as been modified by a previous rule
1892
1893
			if ($amount_to_test > $rule->amount)
1894
			{
1895
				$violation++;
1896
1897
				if ($rule->restrictive)
1898
				{
1899
					$this->error = 'ExpenseReportConstraintViolationError';
1900
					$this->errors[] = $this->error;
1901
1902
					$new_current_total_ttc -= $amount_to_test - $rule->amount; // ex, entered 16€, limit 12€, subtracts 4€;
1903
					$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)));
1904
				} else {
1905
					$this->error = 'ExpenseReportConstraintViolationWarning';
1906
					$this->errors[] = $this->error;
1907
1908
					$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));
1909
				}
1910
1911
				// No break, we sould test if another rule is violated
1912
			}
1913
		}
1914
1915
		$this->line->rule_warning_message = implode('\n', $rule_warning_message_tab);
1916
1917
		if ($violation > 0)
1918
		{
1919
			$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);
1920
1921
			$this->line->value_unit = $tmp[5];
1922
			$this->line->total_ttc = $tmp[2];
1923
			$this->line->total_ht = $tmp[0];
1924
			$this->line->total_tva = $tmp[1];
1925
1926
			return false;
1927
		} else return true;
1928
	}
1929
1930
	/**
1931
	 * Method to apply the offset if needed
1932
	 *
1933
	 * @return boolean		true=applied, false=not applied
1934
	 */
1935
	public function applyOffset()
1936
	{
1937
		global $conf;
1938
1939
		if (empty($conf->global->MAIN_USE_EXPENSE_IK)) return false;
1940
1941
		$userauthor = new User($this->db);
1942
		if ($userauthor->fetch($this->fk_user_author) <= 0)
1943
		{
1944
			$this->error = 'ErrorCantFetchUser';
1945
			$this->errors[] = 'ErrorCantFetchUser';
1946
			return false;
1947
		}
1948
1949
		$range = ExpenseReportIk::getRangeByUser($userauthor, $this->line->fk_c_exp_tax_cat);
1950
1951
		if (empty($range))
1952
		{
1953
			$this->error = 'ErrorNoRangeAvailable';
1954
			$this->errors[] = 'ErrorNoRangeAvailable';
1955
			return false;
1956
		}
1957
1958
		if (!empty($conf->global->MAIN_EXPENSE_APPLY_ENTIRE_OFFSET)) $ikoffset = $range->ikoffset;
0 ignored issues
show
Bug introduced by
The property ikoffset does not exist on boolean.
Loading history...
1959
		else $ikoffset = $range->ikoffset / 12; // The amount of offset is a global value for the year
1960
1961
		// Test if ikoffset has been applied for the current month
1962
		if (!$this->offsetAlreadyGiven())
1963
		{
1964
			$new_up = $range->coef + ($ikoffset / $this->line->qty);
0 ignored issues
show
Bug introduced by
The property coef does not exist on boolean.
Loading history...
1965
			$tmp = calcul_price_total($this->line->qty, $new_up, 0, $this->line->vatrate, 0, 0, 0, 'TTC', 0, $type, $seller);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $seller seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $type seems to be never defined.
Loading history...
1966
1967
			$this->line->value_unit = $tmp[5];
1968
			$this->line->total_ttc = $tmp[2];
1969
			$this->line->total_ht = $tmp[0];
1970
			$this->line->total_tva = $tmp[1];
1971
1972
			return true;
1973
		}
1974
1975
		return false;
1976
	}
1977
1978
	/**
1979
	 * If the sql find any rows then the ikoffset is already given (ikoffset is applied at the first expense report line)
1980
	 *
1981
	 * @return bool
1982
	 */
1983
	public function offsetAlreadyGiven()
1984
	{
1985
		$sql = 'SELECT e.rowid FROM '.MAIN_DB_PREFIX.'expensereport e';
1986
		$sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'expensereport_det d ON (e.rowid = d.fk_expensereport)';
1987
		$sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'c_type_fees f ON (d.fk_c_type_fees = f.id AND f.code = "EX_KME")';
1988
		$sql .= ' WHERE e.fk_user_author = '.(int) $this->fk_user_author;
1989
		$sql .= ' AND YEAR(d.date) = "'.dol_print_date($this->line->date, '%Y').'" AND MONTH(d.date) = "'.dol_print_date($this->line->date, '%m').'"';
1990
		if (!empty($this->line->id)) $sql .= ' AND d.rowid <> '.$this->line->id;
1991
1992
		dol_syslog(get_class($this)."::offsetAlreadyGiven sql=".$sql);
1993
		$resql = $this->db->query($sql);
1994
		if ($resql)
1995
		{
1996
			$num = $this->db->num_rows($resql);
1997
			if ($num > 0) return true;
1998
		} else {
1999
			dol_print_error($this->db);
2000
		}
2001
2002
		return false;
2003
	}
2004
2005
	/**
2006
	 * Update an expense report line
2007
	 *
2008
	 * @param   int         $rowid                  Line to edit
2009
	 * @param   int         $type_fees_id           Type payment
2010
	 * @param   int         $projet_id              Project id
2011
	 * @param   double      $vatrate                Vat rate. Can be '8.5' or '8.5* (8.5NPROM...)'
2012
	 * @param   string      $comments               Description
2013
	 * @param   float       $qty                    Qty
2014
	 * @param   double      $value_unit             Value init
2015
	 * @param   int         $date                   Date
2016
	 * @param   int         $expensereport_id       Expense report id
2017
	 * @param   int         $fk_c_exp_tax_cat       Id of category of car
2018
	 * @param   int         $fk_ecm_files           Id of ECM file to link to this expensereport line
2019
	 * @return  int                                 <0 if KO, >0 if OK
2020
	 */
2021
	public function updateline($rowid, $type_fees_id, $projet_id, $vatrate, $comments, $qty, $value_unit, $date, $expensereport_id, $fk_c_exp_tax_cat = 0, $fk_ecm_files = 0)
2022
	{
2023
		global $user, $mysoc;
2024
2025
		if ($this->status == self::STATUS_DRAFT || $this->status == self::STATUS_REFUSED)
2026
		{
2027
			$this->db->begin();
2028
2029
			$type = 0; // TODO What if type is service ?
2030
2031
			// We don't know seller and buyer for expense reports
2032
			$seller = $mysoc;
2033
			$buyer = new Societe($this->db);
2034
2035
			$localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller);
2036
2037
			// Clean vat code
2038
			$vat_src_code = '';
2039
			if (preg_match('/\((.*)\)/', $vatrate, $reg))
2040
			{
2041
				$vat_src_code = $reg[1];
2042
				$vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate.
2043
			}
2044
			$vatrate = preg_replace('/\*/', '', $vatrate);
2045
2046
			$tmp = calcul_price_total($qty, $value_unit, 0, $vatrate, 0, 0, 0, 'TTC', 0, $type, $seller, $localtaxes_type);
2047
2048
			// calcul total of line
2049
			//$total_ttc  = price2num($qty*$value_unit, 'MT');
2050
2051
			$tx_tva = $vatrate / 100;
2052
			$tx_tva = $tx_tva + 1;
2053
			$total_ht = price2num($total_ttc / $tx_tva, 'MT');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $total_ttc does not exist. Did you maybe mean $total_tva?
Loading history...
2054
2055
			$total_tva = price2num($total_ttc - $total_ht, 'MT');
2056
			// fin calculs
2057
2058
			$this->line = new ExpenseReportLine($this->db);
2059
			$this->line->comments        = $comments;
2060
			$this->line->qty             = $qty;
2061
			$this->line->value_unit      = $value_unit;
2062
			$this->line->date            = $date;
2063
2064
			$this->line->fk_expensereport = $expensereport_id;
2065
			$this->line->fk_c_type_fees  = $type_fees_id;
2066
			$this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat;
2067
			$this->line->fk_projet       = $projet_id; // deprecated
2068
			$this->line->fk_project      = $projet_id;
2069
2070
			$this->line->vat_src_code = $vat_src_code;
2071
			$this->line->vatrate = price2num($vatrate);
2072
			$this->line->total_ttc = $tmp[2];
2073
			$this->line->total_ht = $tmp[0];
2074
			$this->line->total_tva = $tmp[1];
2075
			$this->line->localtax1_tx = $localtaxes_type[1];
0 ignored issues
show
Bug introduced by
The property localtax1_tx does not seem to exist on ExpenseReportLine.
Loading history...
2076
			$this->line->localtax2_tx = $localtaxes_type[3];
0 ignored issues
show
Bug introduced by
The property localtax2_tx does not seem to exist on ExpenseReportLine.
Loading history...
2077
			$this->line->localtax1_type = $localtaxes_type[0];
0 ignored issues
show
Bug introduced by
The property localtax1_type does not seem to exist on ExpenseReportLine.
Loading history...
2078
			$this->line->localtax2_type = $localtaxes_type[2];
0 ignored issues
show
Bug introduced by
The property localtax2_type does not seem to exist on ExpenseReportLine.
Loading history...
2079
2080
			$this->line->fk_ecm_files = $fk_ecm_files;
2081
2082
			$this->line->id = $rowid;
2083
2084
			// Select des infos sur le type fees
2085
			$sql = "SELECT c.code as code_type_fees, c.label as libelle_type_fees";
2086
			$sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
2087
			$sql .= " WHERE c.id = ".$type_fees_id;
2088
			$resql = $this->db->query($sql);
2089
			if ($resql)
2090
			{
2091
				$objp_fees = $this->db->fetch_object($resql);
2092
				$this->line->type_fees_code      = $objp_fees->code_type_fees;
2093
				$this->line->type_fees_libelle   = $objp_fees->libelle_type_fees;
2094
				$this->db->free($resql);
2095
			}
2096
2097
			// Select des informations du projet
2098
			$sql = "SELECT p.ref as ref_projet, p.title as title_projet";
2099
			$sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
2100
			$sql .= " WHERE p.rowid = ".$projet_id;
2101
			$resql = $this->db->query($sql);
2102
			if ($resql) {
2103
				$objp_projet = $this->db->fetch_object($resql);
2104
				$this->line->projet_ref          = $objp_projet->ref_projet;
2105
				$this->line->projet_title        = $objp_projet->title_projet;
2106
				$this->db->free($resql);
2107
			}
2108
2109
			$this->applyOffset();
2110
			$this->checkRules();
2111
2112
			$result = $this->line->update($user);
2113
			if ($result > 0)
2114
			{
2115
				$this->db->commit();
2116
				return 1;
2117
			} else {
2118
				$this->error = $this->line->error;
2119
				$this->errors = $this->line->errors;
2120
				$this->db->rollback();
2121
				return -2;
2122
			}
2123
		}
2124
	}
2125
2126
	/**
2127
	 * deleteline
2128
	 *
2129
	 * @param   int     $rowid      Row id
2130
	 * @param   User    $fuser      User
2131
	 * @return  int                 <0 if KO, >0 if OK
2132
	 */
2133
	public function deleteline($rowid, $fuser = '')
2134
	{
2135
		$this->db->begin();
2136
2137
		$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2138
		$sql .= ' WHERE rowid = '.$rowid;
2139
2140
		dol_syslog(get_class($this)."::deleteline sql=".$sql);
2141
		$result = $this->db->query($sql);
2142
		if (!$result)
2143
		{
2144
			$this->error = $this->db->error();
2145
			dol_syslog(get_class($this)."::deleteline  Error ".$this->error, LOG_ERR);
2146
			$this->db->rollback();
2147
			return -1;
2148
		}
2149
2150
		$this->db->commit();
2151
2152
		return 1;
2153
	}
2154
2155
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2156
	/**
2157
	 * periode_existe
2158
	 *
2159
	 * @param   User       $fuser          User
2160
	 * @param   integer    $date_debut     Start date
2161
	 * @param   integer    $date_fin       End date
2162
	 * @return  int                        <0 if KO, >0 if OK
2163
	 */
2164
	public function periode_existe($fuser, $date_debut, $date_fin)
2165
	{
2166
		// phpcs:enable
2167
		$sql = "SELECT rowid, date_debut, date_fin";
2168
		$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
2169
		$sql .= " WHERE fk_user_author = '{$fuser->id}'";
2170
2171
		dol_syslog(get_class($this)."::periode_existe sql=".$sql);
2172
		$result = $this->db->query($sql);
2173
		if ($result) {
2174
			$num_rows = $this->db->num_rows($result); $i = 0;
2175
2176
			if ($num_rows > 0)
2177
			{
2178
				$date_d_form = $date_debut;
2179
				$date_f_form = $date_fin;
2180
2181
				$existe = false;
2182
2183
				while ($i < $num_rows)
2184
				{
2185
					$objp = $this->db->fetch_object($result);
2186
2187
					$date_d_req = $this->db->jdate($objp->date_debut); // 3
2188
					$date_f_req = $this->db->jdate($objp->date_fin); // 4
2189
2190
					if (!($date_f_form < $date_d_req || $date_d_form > $date_f_req)) $existe = true;
2191
2192
					$i++;
2193
				}
2194
2195
				if ($existe) return 1;
2196
				else return 0;
2197
			} else {
2198
				return 0;
2199
			}
2200
		} else {
2201
			$this->error = $this->db->lasterror();
2202
			dol_syslog(get_class($this)."::periode_existe  Error ".$this->error, LOG_ERR);
2203
			return -1;
2204
		}
2205
	}
2206
2207
2208
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2209
	/**
2210
	 * Return list of people with permission to validate expense reports.
2211
	 * Search for permission "approve expense report"
2212
	 *
2213
	 * @return  array       Array of user ids
2214
	 */
2215
	public function fetch_users_approver_expensereport()
2216
	{
2217
		// phpcs:enable
2218
		$users_validator = array();
2219
2220
		$sql = "SELECT DISTINCT ur.fk_user";
2221
		$sql .= " FROM ".MAIN_DB_PREFIX."user_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2222
		$sql .= " WHERE ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2223
		$sql .= "UNION";
2224
		$sql .= " SELECT DISTINCT ugu.fk_user";
2225
		$sql .= " FROM ".MAIN_DB_PREFIX."usergroup_user as ugu, ".MAIN_DB_PREFIX."usergroup_rights as ur, ".MAIN_DB_PREFIX."rights_def as rd";
2226
		$sql .= " WHERE ugu.fk_usergroup = ur.fk_usergroup AND ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve';
2227
		//print $sql;
2228
2229
		dol_syslog(get_class($this)."::fetch_users_approver_expensereport sql=".$sql);
2230
		$result = $this->db->query($sql);
2231
		if ($result)
2232
		{
2233
			$num_rows = $this->db->num_rows($result); $i = 0;
2234
			while ($i < $num_rows)
2235
			{
2236
				$objp = $this->db->fetch_object($result);
2237
				array_push($users_validator, $objp->fk_user);
2238
				$i++;
2239
			}
2240
			return $users_validator;
2241
		} else {
2242
			$this->error = $this->db->lasterror();
2243
			dol_syslog(get_class($this)."::fetch_users_approver_expensereport  Error ".$this->error, LOG_ERR);
2244
			return -1;
2245
		}
2246
	}
2247
2248
	/**
2249
	 *  Create a document onto disk accordign to template module.
2250
	 *
2251
	 *  @param      string      $modele         Force le mnodele a utiliser ('' to not force)
2252
	 *  @param      Translate   $outputlangs    objet lang a utiliser pour traduction
2253
	 *  @param      int         $hidedetails    Hide details of lines
2254
	 *  @param      int         $hidedesc       Hide description
2255
	 *  @param      int         $hideref        Hide ref
2256
	 *  @param   null|array  $moreparams     Array to provide more information
2257
	 *  @return     int                         0 if KO, 1 if OK
2258
	 */
2259
	public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
2260
	{
2261
		global $conf, $langs;
2262
2263
		$langs->load("trips");
2264
2265
		if (!dol_strlen($modele)) {
2266
			if (!empty($this->modelpdf)) {
2267
				$modele = $this->modelpdf;
2268
			} elseif (!empty($conf->global->EXPENSEREPORT_ADDON_PDF)) {
2269
				$modele = $conf->global->EXPENSEREPORT_ADDON_PDF;
2270
			}
2271
		}
2272
2273
		if (!empty($modele)) {
2274
			$modelpath = "core/modules/expensereport/doc/";
2275
2276
			return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2277
		} else {
2278
			return 0;
2279
		}
2280
	}
2281
2282
	/**
2283
	 * List of types
2284
	 *
2285
	 * @param   int     $active     Active or not
2286
	 * @return  array
2287
	 */
2288
	public function listOfTypes($active = 1)
2289
	{
2290
		global $langs;
2291
		$ret = array();
2292
		$sql = "SELECT id, code, label";
2293
		$sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees";
2294
		$sql .= " WHERE active = ".$active;
2295
		dol_syslog(get_class($this)."::listOfTypes", LOG_DEBUG);
2296
		$result = $this->db->query($sql);
2297
		if ($result)
2298
		{
2299
			$num = $this->db->num_rows($result);
2300
			$i = 0;
2301
			while ($i < $num)
2302
			{
2303
				$obj = $this->db->fetch_object($result);
2304
				$ret[$obj->code] = (($langs->trans($obj->code) != $obj->code) ? $langs->trans($obj->code) : $obj->label);
2305
				$i++;
2306
			}
2307
		} else {
2308
			dol_print_error($this->db);
2309
		}
2310
		return $ret;
2311
	}
2312
2313
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2314
	/**
2315
	 *      Charge indicateurs this->nb pour le tableau de bord
2316
	 *
2317
	 *      @return     int         <0 if KO, >0 if OK
2318
	 */
2319
	public function load_state_board()
2320
	{
2321
		// phpcs:enable
2322
		global $conf, $user;
2323
2324
		$this->nb = array();
2325
2326
		$sql = "SELECT count(ex.rowid) as nb";
2327
		$sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2328
		$sql .= " WHERE ex.fk_statut > 0";
2329
		$sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2330
		if (empty($user->rights->expensereport->readall))
2331
		{
2332
			$userchildids = $user->getAllChildIds(1);
2333
			$sql .= " AND (ex.fk_user_author IN (".join(',', $userchildids).")";
2334
			$sql .= " OR ex.fk_user_validator IN (".join(',', $userchildids)."))";
2335
		}
2336
2337
		$resql = $this->db->query($sql);
2338
		if ($resql) {
2339
			while ($obj = $this->db->fetch_object($resql)) {
2340
				$this->nb["expensereports"] = $obj->nb;
2341
			}
2342
			$this->db->free($resql);
2343
			return 1;
2344
		} else {
2345
			dol_print_error($this->db);
2346
			$this->error = $this->db->error();
2347
			return -1;
2348
		}
2349
	}
2350
2351
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2352
	/**
2353
	 *      Load indicators for dashboard (this->nbtodo and this->nbtodolate)
2354
	 *
2355
	 *      @param	User	$user   		Objet user
2356
	 *      @param  string  $option         'topay' or 'toapprove'
2357
	 *      @return WorkboardResponse|int 	<0 if KO, WorkboardResponse if OK
2358
	 */
2359
	public function load_board($user, $option = 'topay')
2360
	{
2361
		// phpcs:enable
2362
		global $conf, $langs;
2363
2364
		if ($user->socid) return -1; // protection pour eviter appel par utilisateur externe
2365
2366
		$now = dol_now();
2367
2368
		$sql = "SELECT ex.rowid, ex.date_valid";
2369
		$sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex";
2370
		if ($option == 'toapprove') $sql .= " WHERE ex.fk_statut = ".self::STATUS_VALIDATED;
2371
		else $sql .= " WHERE ex.fk_statut = ".self::STATUS_APPROVED;
2372
		$sql .= " AND ex.entity IN (".getEntity('expensereport').")";
2373
		if (empty($user->rights->expensereport->readall))
2374
		{
2375
			$userchildids = $user->getAllChildIds(1);
2376
			$sql .= " AND (ex.fk_user_author IN (".join(',', $userchildids).")";
2377
			$sql .= " OR ex.fk_user_validator IN (".join(',', $userchildids)."))";
2378
		}
2379
2380
		$resql = $this->db->query($sql);
2381
		if ($resql)
2382
		{
2383
			$langs->load("trips");
2384
2385
			$response = new WorkboardResponse();
2386
			if ($option == 'toapprove')
2387
			{
2388
				$response->warning_delay = $conf->expensereport->approve->warning_delay / 60 / 60 / 24;
2389
				$response->label = $langs->trans("ExpenseReportsToApprove");
2390
				$response->labelShort = $langs->trans("ToApprove");
2391
				$response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_VALIDATED;
2392
			} else {
2393
				$response->warning_delay = $conf->expensereport->payment->warning_delay / 60 / 60 / 24;
2394
				$response->label = $langs->trans("ExpenseReportsToPay");
2395
				$response->labelShort = $langs->trans("StatusToPay");
2396
				$response->url = DOL_URL_ROOT.'/expensereport/list.php?mainmenu=hrm&amp;statut='.self::STATUS_APPROVED;
2397
			}
2398
			$response->img = img_object('', "trip");
2399
2400
			while ($obj = $this->db->fetch_object($resql))
2401
			{
2402
				$response->nbtodo++;
2403
2404
				if ($option == 'toapprove')
2405
				{
2406
					if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->approve->warning_delay)) {
2407
						$response->nbtodolate++;
2408
					}
2409
				} else {
2410
					if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->payment->warning_delay)) {
2411
						$response->nbtodolate++;
2412
					}
2413
				}
2414
			}
2415
2416
			return $response;
2417
		} else {
2418
			dol_print_error($this->db);
2419
			$this->error = $this->db->error();
2420
			return -1;
2421
		}
2422
	}
2423
2424
	/**
2425
	 * Return if an expense report is late or not
2426
	 *
2427
	 * @param  string  $option          'topay' or 'toapprove'
2428
	 * @return boolean                  True if late, False if not late
2429
	 */
2430
	public function hasDelay($option)
2431
	{
2432
		global $conf;
2433
2434
		// Only valid expenses reports
2435
		if ($option == 'toapprove' && $this->status != 2) return false;
2436
		if ($option == 'topay' && $this->status != 5) return false;
2437
2438
		$now = dol_now();
2439
		if ($option == 'toapprove')
2440
		{
2441
			return ($this->datevalid ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->approve->warning_delay);
0 ignored issues
show
Bug introduced by
The property datevalid does not exist on ExpenseReport. Did you mean date_valid?
Loading history...
2442
		} else return ($this->datevalid ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->payment->warning_delay);
2443
	}
2444
2445
	/**
2446
	 *	Return if an expensereport was dispatched into bookkeeping
2447
	 *
2448
	 *	@return     int         <0 if KO, 0=no, 1=yes
2449
	 */
2450
	public function getVentilExportCompta()
2451
	{
2452
		$alreadydispatched = 0;
2453
2454
		$type = 'expense_report';
2455
2456
		$sql = " SELECT COUNT(ab.rowid) as nb FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab WHERE ab.doc_type='".$this->db->escape($type)."' AND ab.fk_doc = ".$this->id;
2457
		$resql = $this->db->query($sql);
2458
		if ($resql)
2459
		{
2460
			$obj = $this->db->fetch_object($resql);
2461
			if ($obj)
2462
			{
2463
				$alreadydispatched = $obj->nb;
2464
			}
2465
		} else {
2466
			$this->error = $this->db->lasterror();
2467
			return -1;
2468
		}
2469
2470
		if ($alreadydispatched)
2471
		{
2472
			return 1;
2473
		}
2474
		return 0;
2475
	}
2476
2477
	/**
2478
	 * 	Return amount of payments already done
2479
	 *
2480
	 *  @return		int						Amount of payment already done, <0 if KO
2481
	 */
2482
	public function getSumPayments()
2483
	{
2484
		$table = 'payment_expensereport';
2485
		$field = 'fk_expensereport';
2486
2487
		$sql = 'SELECT sum(amount) as amount';
2488
		$sql .= ' FROM '.MAIN_DB_PREFIX.$table;
2489
		$sql .= ' WHERE '.$field.' = '.$this->id;
2490
2491
		dol_syslog(get_class($this)."::getSumPayments", LOG_DEBUG);
2492
		$resql = $this->db->query($sql);
2493
		if ($resql)
2494
		{
2495
			$obj = $this->db->fetch_object($resql);
2496
			$this->db->free($resql);
2497
			return (empty($obj->amount) ? 0 : $obj->amount);
2498
		} else {
2499
			$this->error = $this->db->lasterror();
2500
			return -1;
2501
		}
2502
	}
2503
}
2504
2505
2506
/**
2507
 * Class of expense report details lines
2508
 */
2509
class ExpenseReportLine
2510
{
2511
	/**
2512
	 * @var DoliDB Database handler.
2513
	 */
2514
	public $db;
2515
2516
	/**
2517
	 * @var string Error code (or message)
2518
	 */
2519
	public $error = '';
2520
2521
	/**
2522
	 * @var int ID
2523
	 */
2524
	public $rowid;
2525
2526
	public $comments;
2527
	public $qty;
2528
	public $value_unit;
2529
	public $date;
2530
2531
	/**
2532
	 * @var int ID
2533
	 */
2534
	public $fk_c_type_fees;
2535
2536
	/**
2537
	 * @var int ID
2538
	 */
2539
	public $fk_c_exp_tax_cat;
2540
2541
	/**
2542
	 * @var int ID
2543
	 */
2544
	public $fk_projet;
2545
2546
	/**
2547
	 * @var int ID
2548
	 */
2549
	public $fk_expensereport;
2550
2551
	public $type_fees_code;
2552
	public $type_fees_libelle;
2553
2554
	public $projet_ref;
2555
	public $projet_title;
2556
2557
	public $vatrate;
2558
	public $total_ht;
2559
	public $total_tva;
2560
	public $total_ttc;
2561
2562
	/**
2563
	 * @var int ID into llx_ecm_files table to link line to attached file
2564
	 */
2565
	public $fk_ecm_files;
2566
2567
2568
	/**
2569
	 * Constructor
2570
	 *
2571
	 * @param DoliDB    $db     Handlet database
2572
	 */
2573
	public function __construct($db)
2574
	{
2575
		$this->db = $db;
2576
	}
2577
2578
	/**
2579
	 * Fetch record for expense report detailed line
2580
	 *
2581
	 * @param   int     $rowid      Id of object to load
2582
	 * @return  int                 <0 if KO, >0 if OK
2583
	 */
2584
	public function fetch($rowid)
2585
	{
2586
		$sql = 'SELECT fde.rowid, fde.fk_expensereport, fde.fk_c_type_fees, fde.fk_c_exp_tax_cat, fde.fk_projet as fk_project, fde.date,';
2587
		$sql .= ' fde.tva_tx as vatrate, fde.vat_src_code, fde.comments, fde.qty, fde.value_unit, fde.total_ht, fde.total_tva, fde.total_ttc, fde.fk_ecm_files,';
2588
		$sql .= ' ctf.code as type_fees_code, ctf.label as type_fees_libelle,';
2589
		$sql .= ' pjt.rowid as projet_id, pjt.title as projet_title, pjt.ref as projet_ref';
2590
		$sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det as fde';
2591
		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_type_fees as ctf ON fde.fk_c_type_fees=ctf.id'; // Sometimes type of expense report has been removed, so we use a left join here.
2592
		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as pjt ON fde.fk_projet=pjt.rowid';
2593
		$sql .= ' WHERE fde.rowid = '.$rowid;
2594
2595
		$result = $this->db->query($sql);
2596
2597
		if ($result)
2598
		{
2599
			$objp = $this->db->fetch_object($result);
2600
2601
			$this->rowid = $objp->rowid;
2602
			$this->id = $objp->rowid;
2603
			$this->ref = $objp->ref;
2604
			$this->fk_expensereport = $objp->fk_expensereport;
2605
			$this->comments = $objp->comments;
2606
			$this->qty = $objp->qty;
2607
			$this->date = $objp->date;
2608
			$this->dates = $this->db->jdate($objp->date);
2609
			$this->value_unit = $objp->value_unit;
2610
			$this->fk_c_type_fees = $objp->fk_c_type_fees;
2611
			$this->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat;
2612
			$this->fk_projet = $objp->fk_project; // deprecated
2613
			$this->fk_project = $objp->fk_project;
2614
			$this->type_fees_code = $objp->type_fees_code;
2615
			$this->type_fees_libelle = $objp->type_fees_libelle;
2616
			$this->projet_ref = $objp->projet_ref;
2617
			$this->projet_title = $objp->projet_title;
2618
			$this->vatrate = $objp->vatrate;
2619
			$this->vat_src_code = $objp->vat_src_code;
2620
			$this->total_ht = $objp->total_ht;
2621
			$this->total_tva = $objp->total_tva;
2622
			$this->total_ttc = $objp->total_ttc;
2623
			$this->fk_ecm_files = $objp->fk_ecm_files;
2624
2625
			$this->db->free($result);
2626
		} else {
2627
			dol_print_error($this->db);
2628
		}
2629
	}
2630
2631
	/**
2632
	 * insert
2633
	 *
2634
	 * @param   int     $notrigger      1=No trigger
2635
	 * @param   bool    $fromaddline    false=keep default behavior, true=exclude the update_price() of parent object
2636
	 * @return  int                     <0 if KO, >0 if OK
2637
	 */
2638
	public function insert($notrigger = 0, $fromaddline = false)
2639
	{
2640
		global $langs, $user, $conf;
2641
2642
		$error = 0;
2643
2644
		dol_syslog("ExpenseReportLine::Insert rang=".$this->rang, LOG_DEBUG);
0 ignored issues
show
Bug Best Practice introduced by
The property rang does not exist on ExpenseReportLine. Did you maybe forget to declare it?
Loading history...
2645
2646
		// Clean parameters
2647
		$this->comments = trim($this->comments);
2648
		if (!$this->value_unit_HT) $this->value_unit_HT = 0;
2649
		$this->qty = price2num($this->qty);
2650
		$this->vatrate = price2num($this->vatrate);
2651
		if (empty($this->fk_c_exp_tax_cat)) $this->fk_c_exp_tax_cat = 0;
2652
2653
		$this->db->begin();
2654
2655
		$sql = 'INSERT INTO '.MAIN_DB_PREFIX.'expensereport_det';
2656
		$sql .= ' (fk_expensereport, fk_c_type_fees, fk_projet,';
2657
		$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, fk_ecm_files)';
2658
		$sql .= " VALUES (".$this->db->escape($this->fk_expensereport).",";
2659
		$sql .= " ".$this->db->escape($this->fk_c_type_fees).",";
2660
		$sql .= " ".$this->db->escape($this->fk_project > 0 ? $this->fk_project : ($this->fk_projet > 0 ? $this->fk_projet : 'null')).",";
2661
		$sql .= " ".$this->db->escape($this->vatrate).",";
2662
		$sql .= " '".$this->db->escape($this->vat_src_code)."',";
2663
		$sql .= " '".$this->db->escape($this->comments)."',";
2664
		$sql .= " ".$this->db->escape($this->qty).",";
2665
		$sql .= " ".$this->db->escape($this->value_unit).",";
2666
		$sql .= " ".$this->db->escape($this->total_ht).",";
2667
		$sql .= " ".$this->db->escape($this->total_tva).",";
2668
		$sql .= " ".$this->db->escape($this->total_ttc).",";
2669
		$sql .= " '".$this->db->idate($this->date)."',";
2670
		$sql .= " '".$this->db->escape($this->rule_warning_message)."',";
0 ignored issues
show
Bug Best Practice introduced by
The property rule_warning_message does not exist on ExpenseReportLine. Did you maybe forget to declare it?
Loading history...
2671
		$sql .= " ".$this->db->escape($this->fk_c_exp_tax_cat).",";
2672
		$sql .= " ".($this->fk_ecm_files > 0 ? $this->fk_ecm_files : 'null');
2673
		$sql .= ")";
2674
2675
		$resql = $this->db->query($sql);
2676
		if ($resql)
2677
		{
2678
			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'expensereport_det');
2679
2680
			if (!$fromaddline)
2681
			{
2682
				$tmpparent = new ExpenseReport($this->db);
2683
				$tmpparent->fetch($this->fk_expensereport);
2684
				$result = $tmpparent->update_price();
2685
				if ($result < 0)
2686
				{
2687
					$error++;
2688
					$this->error = $tmpparent->error;
2689
					$this->errors = $tmpparent->errors;
2690
				}
2691
			}
2692
		} else {
2693
			$error++;
2694
		}
2695
2696
		if (!$error)
2697
		{
2698
			$this->db->commit();
2699
			return $this->id;
2700
		} else {
2701
			$this->error = $this->db->lasterror();
2702
			dol_syslog("ExpenseReportLine::insert Error ".$this->error, LOG_ERR);
2703
			$this->db->rollback();
2704
			return -2;
2705
		}
2706
	}
2707
2708
	/**
2709
	 * Function to get total amount in expense reports for a same rule
2710
	 *
2711
	 * @param  ExpenseReportRule $rule		object rule to check
2712
	 * @param  int				 $fk_user	user author id
2713
	 * @param  string			 $mode		day|EX_DAY / month|EX_MON / year|EX_YEA to get amount
2714
	 * @return float                        Amount
2715
	 */
2716
	public function getExpAmount(ExpenseReportRule $rule, $fk_user, $mode = 'day')
2717
	{
2718
		$amount = 0;
2719
2720
		$sql = 'SELECT SUM(d.total_ttc) as total_amount';
2721
		$sql .= ' FROM '.MAIN_DB_PREFIX.'expensereport_det d';
2722
		$sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'expensereport e ON (d.fk_expensereport = e.rowid)';
2723
		$sql .= ' WHERE e.fk_user_author = '.$fk_user;
2724
		if (!empty($this->id)) $sql .= ' AND d.rowid <> '.$this->id;
2725
		$sql .= ' AND d.fk_c_type_fees = '.$rule->fk_c_type_fees;
2726
		if ($mode == 'day' || $mode == 'EX_DAY') $sql .= ' AND d.date = \''.dol_print_date($this->date, '%Y-%m-%d').'\'';
2727
		elseif ($mode == 'mon' || $mode == 'EX_MON') $sql .= ' AND DATE_FORMAT(d.date, \'%Y-%m\') = \''.dol_print_date($this->date, '%Y-%m').'\''; // @todo DATE_FORMAT is forbidden
2728
		elseif ($mode == 'year' || $mode == 'EX_YEA') $sql .= ' AND DATE_FORMAT(d.date, \'%Y\') = \''.dol_print_date($this->date, '%Y').'\''; // @todo DATE_FORMAT is forbidden
2729
2730
		dol_syslog('ExpenseReportLine::getExpAmount');
2731
2732
		$resql = $this->db->query($sql);
2733
		if ($resql)
2734
		{
2735
			$num = $this->db->num_rows($resql);
2736
			if ($num > 0)
2737
			{
2738
				$obj = $this->db->fetch_object($resql);
2739
				$amount = (double) $obj->total_amount;
2740
			}
2741
		} else {
2742
			dol_print_error($this->db);
2743
		}
2744
2745
		return $amount + $this->total_ttc;
2746
	}
2747
2748
	/**
2749
	 * Update line
2750
	 *
2751
	 * @param   User    $user      User
2752
	 * @return  int                <0 if KO, >0 if OK
2753
	 */
2754
	public function update(User $user)
2755
	{
2756
		global $langs, $conf;
2757
2758
		$error = 0;
2759
2760
		// Clean parameters
2761
		$this->comments = trim($this->comments);
2762
		$this->vatrate = price2num($this->vatrate);
2763
		$this->value_unit = price2num($this->value_unit);
2764
		if (empty($this->fk_c_exp_tax_cat)) $this->fk_c_exp_tax_cat = 0;
2765
2766
		$this->db->begin();
2767
2768
		// Update line in database
2769
		$sql = "UPDATE ".MAIN_DB_PREFIX."expensereport_det SET";
2770
		$sql .= " comments='".$this->db->escape($this->comments)."'";
2771
		$sql .= ",value_unit=".$this->db->escape($this->value_unit);
2772
		$sql .= ",qty=".$this->db->escape($this->qty);
2773
		$sql .= ",date='".$this->db->idate($this->date)."'";
2774
		$sql .= ",total_ht=".$this->db->escape($this->total_ht)."";
2775
		$sql .= ",total_tva=".$this->db->escape($this->total_tva)."";
2776
		$sql .= ",total_ttc=".$this->db->escape($this->total_ttc)."";
2777
		$sql .= ",tva_tx=".$this->db->escape($this->vatrate);
2778
		$sql .= ",vat_src_code='".$this->db->escape($this->vat_src_code)."'";
2779
		$sql .= ",rule_warning_message='".$this->db->escape($this->rule_warning_message)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property rule_warning_message does not exist on ExpenseReportLine. Did you maybe forget to declare it?
Loading history...
2780
		$sql .= ",fk_c_exp_tax_cat=".$this->db->escape($this->fk_c_exp_tax_cat);
2781
		$sql .= ",fk_ecm_files=".($this->fk_ecm_files > 0 ? $this->fk_ecm_files : 'null');
2782
		if ($this->fk_c_type_fees) $sql .= ",fk_c_type_fees=".$this->db->escape($this->fk_c_type_fees);
2783
		else $sql .= ",fk_c_type_fees=null";
2784
		if ($this->fk_project > 0) $sql .= ",fk_projet=".$this->db->escape($this->fk_project);
2785
		else $sql .= ",fk_projet=null";
2786
		$sql .= " WHERE rowid = ".$this->db->escape($this->rowid ? $this->rowid : $this->id);
2787
2788
		dol_syslog("ExpenseReportLine::update sql=".$sql);
2789
2790
		$resql = $this->db->query($sql);
2791
		if ($resql)
2792
		{
2793
			$tmpparent = new ExpenseReport($this->db);
2794
			$result = $tmpparent->fetch($this->fk_expensereport);
2795
			if ($result > 0)
2796
			{
2797
				$result = $tmpparent->update_price();
2798
				if ($result < 0)
2799
				{
2800
					$error++;
2801
					$this->error = $tmpparent->error;
2802
					$this->errors = $tmpparent->errors;
2803
				}
2804
			} else {
2805
				$error++;
2806
				$this->error = $tmpparent->error;
2807
				$this->errors = $tmpparent->errors;
2808
			}
2809
		} else {
2810
			$error++;
2811
			dol_print_error($this->db);
2812
		}
2813
2814
		if (!$error)
2815
		{
2816
			$this->db->commit();
2817
			return 1;
2818
		} else {
2819
			$this->error = $this->db->lasterror();
2820
			dol_syslog("ExpenseReportLine::update Error ".$this->error, LOG_ERR);
2821
			$this->db->rollback();
2822
			return -2;
2823
		}
2824
	}
2825
}
2826