Passed
Push — master ( 65bdac...4e88da )
by Alxarafe
32:38
created

CommonObject   F

Complexity

Total Complexity 1521

Size/Duplication

Total Lines 7391
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 3371
dl 0
loc 7391
rs 0.8
c 0
b 0
f 0
wmc 1521

110 Methods

Rating   Name   Duplication   Size   Complexity  
F liste_contact() 0 60 16
A commonReplaceThirdparty() 0 15 4
F insertExtraFields() 0 236 49
D defineBuyPrice() 0 67 19
B update_note() 0 42 9
F createCommon() 0 85 29
F updateCommon() 0 76 22
A addThumbs() 0 16 2
F printObjectLine() 0 101 28
A getIdOfLine() 0 10 2
F setStatut() 0 77 29
F updateExtraField() 0 118 23
A initAsSpecimenCommon() 0 3 1
A updateLineDown() 0 22 5
A delete_contact() 0 28 4
A __clone() 0 9 4
F fetch_optionals() 0 96 22
C updateObjectLinked() 0 33 12
D showOptionals() 0 178 54
A fetch_product() 0 12 2
A isArray() 0 8 4
A line_max() 0 37 5
A updateLineUp() 0 22 5
A formAddObjectLine() 0 22 4
B fetchCommon() 0 32 9
A fetchComments() 0 13 2
C add_contact() 0 112 17
A fetch_user() 0 7 1
A fetchObjectFrom() 0 26 4
B getFullName() 0 17 10
F show_photos() 0 220 55
A copy_linked_contact() 0 13 3
A isText() 0 8 4
F getTotalWeightVolume() 0 86 30
A swapContactStatus() 0 26 3
A line_up() 0 10 1
A trimParameters() 0 6 4
A setMulticurrencyCode() 0 32 5
A isIndex() 0 8 4
A errorsToString() 0 3 3
D deleteCommon() 0 74 16
A getNbComments() 0 3 1
A isDate() 0 4 5
B getDefaultCreateValueFor() 0 21 7
A update_ref_ext() 0 23 4
F load_previous_next_ref() 0 114 99
F printOriginLine() 0 131 36
B setShippingMethod() 0 44 9
F getBannerAddress() 0 108 40
A setDeliveryAddress() 0 18 4
A delete_linked_contact() 0 26 4
A getListContactId() 0 13 3
B setPaymentTerms() 0 34 7
B fetch_thirdparty() 0 27 11
F setValueFrom() 0 67 27
D setVarsFromFetchObj() 0 42 19
A delete_resource() 0 28 4
F update_price() 0 225 54
A fetchOneLike() 0 17 3
B setBankAccount() 0 49 9
A setDocModel() 0 27 3
A isInt() 0 8 5
B getFullAddress() 0 21 11
A getValueFrom() 0 16 5
A isNull() 0 8 4
A updateRangOfLine() 0 12 3
C line_order() 0 77 14
A update_note_public() 0 4 1
F printObjectLines() 0 136 31
A call_trigger() 0 21 3
A isFloat() 0 8 4
A getRights() 0 8 2
B add_object_linked() 0 36 8
C getLastMainDocLink() 0 82 14
C hasProductsOrServices() 0 16 14
A setWarehouse() 0 20 5
A setProject() 0 32 6
B printOriginLinesList() 0 39 10
A getChildrenOfLine() 0 24 3
A getRangOfLine() 0 11 2
A fetch_projet() 0 14 4
F deleteObjectLinked() 0 49 17
A getIncotermsForPDF() 0 21 3
A fetch_origin() 0 12 4
A getSpecialCode() 0 9 2
D setSaveQuery() 0 54 18
A deleteExtraFields() 0 20 3
B isObjectUsed() 0 61 11
A getFieldList() 0 4 1
B isExistingObject() 0 27 8
A display_incoterms() 0 19 5
B fetch_barcode() 0 41 11
F commonGenerateDocument() 0 236 46
B setIncoterms() 0 31 7
F showOutputField() 0 357 82
A setExtraParameters() 0 22 4
A getTotalDiscount() 0 31 3
B setPaymentMethods() 0 33 7
C liste_type_contact() 0 40 11
F showInputField() 0 596 143
A fetch_contact() 0 12 3
A line_down() 0 13 1
F fetchObjectLinked() 0 191 58
A add_element_resource() 0 32 2
A line_ajaxorder() 0 7 2
C getIdContact() 0 51 12
A quote() 0 5 3
A update_contact() 0 18 4
B getCanvas() 0 31 8
D setMulticurrencyRate() 0 92 19

How to fix   Complexity   

Complex Class

Complex classes like CommonObject often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CommonObject, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* Copyright (C) 2018       Alxarafe            <[email protected]>
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
 */
17
namespace Alixar\Base;
18
19
use Alixar\Base\ExtraFields;
20
21
abstract class CommonObject
22
{
23
	/**
24
     * @var int The object identifier
25
     */
26
	public $id;
27
28
	/**
29
	 * @var string 		Error string
30
	 * @see             errors
31
	 */
32
	public $error;
33
34
	/**
35
	 * @var string[]	Array of error strings
36
	 */
37
	public $errors=array();
38
39
	/**
40
	 * @var string ID to identify managed object
41
	 */
42
	public $element;
43
44
	/**
45
	 * @var string Name of table without prefix where object is stored
46
	 */
47
	public $table_element;
48
49
	/**
50
	 * @var int    Name of subtable line
51
	 */
52
	public $table_element_line='';
53
54
	/**
55
	 * @var string		Key value used to track if data is coming from import wizard
56
	 */
57
	public $import_key;
58
59
	/**
60
	 * @var mixed		Contains data to manage extrafields
61
	 */
62
	public $array_options=array();
63
64
	/**
65
	 * @var int[][]		Array of linked objects ids. Loaded by ->fetchObjectLinked
66
	 */
67
	public $linkedObjectsIds;
68
69
	/**
70
	 * @var mixed		Array of linked objects. Loaded by ->fetchObjectLinked
71
	 */
72
	public $linkedObjects;
73
74
	/**
75
	 * @var Object      To store a cloned copy of object before to edit it and keep track of old properties
76
	 */
77
	public $oldcopy;
78
79
	/**
80
	 * @var string		Column name of the ref field.
81
	 */
82
	protected $table_ref_field = '';
83
84
85
86
	// Following vars are used by some objects only. We keep this property here in CommonObject to be able to provide common method using them.
87
88
	/**
89
	 * @var array<string,mixed>		Can be used to pass information when only object is provided to method
90
	 */
91
	public $context=array();
92
93
	/**
94
	 * @var string		Contains canvas name if record is an alternative canvas record
95
	 */
96
	public $canvas;
97
98
	/**
99
	 * @var Project The related project
0 ignored issues
show
Bug introduced by
The type Alixar\Base\Project was not found. Did you mean Project? If so, make sure to prefix the type with \.
Loading history...
100
	 * @see fetch_projet()
101
	 */
102
	public $project;
103
104
	/**
105
	 * @var int The related project ID
106
	 * @see setProject(), project
107
	 */
108
	public $fk_project;
109
110
	/**
111
	 * @deprecated
112
	 * @see project
113
	 */
114
	public $projet;
115
116
	/**
117
	 * @var Contact a related contact
0 ignored issues
show
Bug introduced by
The type Alixar\Base\Contact was not found. Did you mean Contact? If so, make sure to prefix the type with \.
Loading history...
118
	 * @see fetch_contact()
119
	 */
120
	public $contact;
121
122
	/**
123
	 * @var int The related contact ID
124
	 * @see fetch_contact()
125
	 */
126
	public $contact_id;
127
128
	/**
129
	 * @var Societe A related thirdparty
0 ignored issues
show
Bug introduced by
The type Alixar\Base\Societe was not found. Did you mean Societe? If so, make sure to prefix the type with \.
Loading history...
130
	 * @see fetch_thirdparty()
131
	 */
132
	public $thirdparty;
133
134
	/**
135
	 * @var User A related user
136
	 * @see fetch_user()
137
	 */
138
	public $user;
139
140
	/**
141
	 * @var string 	The type of originating object ('commande', 'facture', ...)
142
	 * @see fetch_origin()
143
	 */
144
	public $origin;
145
146
	/**
147
	 * @var int 	The id of originating object
148
	 * @see fetch_origin()
149
	 */
150
	public $origin_id;
151
152
	/**
153
	 * @var string The object's reference
154
	 */
155
	public $ref;
156
157
	/**
158
	 * @var string The object's previous reference
159
	 */
160
	public $ref_previous;
161
162
	/**
163
	 * @var string The object's next reference
164
	 */
165
	public $ref_next;
166
167
	/**
168
	 * @var string An external reference for the object
169
	 */
170
	public $ref_ext;
171
172
	/**
173
	 * @var int The object's status
174
	 * @see setStatut()
175
	 */
176
	public $statut;
177
178
	/**
179
	 * @var string
180
	 * @see getFullAddress()
181
	 */
182
	public $country;
183
184
	/**
185
	 * @var int
186
	 * @see getFullAddress(), country
187
	 */
188
	public $country_id;
189
190
	/**
191
	 * @var string
192
	 * @see getFullAddress(), isInEEC(), country
193
	 */
194
    public $country_code;
195
196
    /**
197
	 * @var string
198
	 * @see getFullAddress()
199
	 */
200
	public $state;
201
202
	/**
203
	 * @var int
204
	 * @see getFullAddress(), state
205
	 */
206
	public $state_id;
207
208
	/**
209
	 * @var string
210
	 * @see getFullAddress(), state
211
	 */
212
    public $state_code;
213
214
    /**
215
	 * @var string
216
	 * @see getFullAddress(), region
217
	 */
218
	public $region;
219
220
	/**
221
	 * @var string
222
	 * @see getFullAddress(), region
223
	 */
224
    public $region_code;
225
226
	/**
227
	 * @var int
228
	 * @see fetch_barcode()
229
	 */
230
	public $barcode_type;
231
232
	/**
233
	 * @var string
234
	 * @see fetch_barcode(), barcode_type
235
	 */
236
	public $barcode_type_code;
237
238
	/**
239
	 * @var string
240
	 * @see fetch_barcode(), barcode_type
241
	 */
242
	public $barcode_type_label;
243
244
	/**
245
	 * @var string
246
	 * @see fetch_barcode(), barcode_type
247
	 */
248
	public $barcode_type_coder;
249
250
	/**
251
	 * @var int Payment method ID (cheque, cash, ...)
252
	 * @see setPaymentMethods()
253
	 */
254
	public $mode_reglement_id;
255
256
	/**
257
	 * @var int Payment terms ID
258
	 * @see setPaymentTerms()
259
	 */
260
	public $cond_reglement_id;
261
262
	/**
263
	 * @var int Payment terms ID
264
	 * @deprecated Kept for compatibility
265
	 * @see cond_reglement_id;
266
	 */
267
	public $cond_reglement;
268
269
	/**
270
	 * @var int Delivery address ID
271
	 * @deprecated
272
	 * @see setDeliveryAddress()
273
	 */
274
	public $fk_delivery_address;
275
276
	/**
277
	 * @var int Shipping method ID
278
	 * @see setShippingMethod()
279
	 */
280
	public $shipping_method_id;
281
282
	/**
283
	 * @var string
284
	 * @see SetDocModel()
285
	 */
286
	public $modelpdf;
287
288
	/**
289
	 * @var int Bank account ID
290
	 * @see SetBankAccount()
291
	 */
292
	public $fk_account;
293
294
	/**
295
	 * @var string Public note
296
	 * @see update_note()
297
	 */
298
	public $note_public;
299
300
	/**
301
	 * @var string Private note
302
	 * @see update_note()
303
	 */
304
	public $note_private;
305
306
	/**
307
	 * @deprecated
308
	 * @see note_public
309
	 */
310
	public $note;
311
312
	/**
313
	 * @var float Total amount before taxes
314
	 * @see update_price()
315
	 */
316
	public $total_ht;
317
318
	/**
319
	 * @var float Total VAT amount
320
	 * @see update_price()
321
	 */
322
	public $total_tva;
323
324
	/**
325
	 * @var float Total local tax 1 amount
326
	 * @see update_price()
327
	 */
328
	public $total_localtax1;
329
330
	/**
331
	 * @var float Total local tax 2 amount
332
	 * @see update_price()
333
	 */
334
	public $total_localtax2;
335
336
	/**
337
	 * @var float Total amount with taxes
338
	 * @see update_price()
339
	 */
340
	public $total_ttc;
341
342
	/**
343
	 * @var CommonObjectLine[]
344
	 */
345
	public $lines;
346
347
	/**
348
	 * @var mixed		Contains comments
349
	 * @see fetchComments()
350
	 */
351
	public $comments=array();
352
353
	/**
354
	 * @var int
355
	 * @see setIncoterms()
356
	 */
357
	public $fk_incoterms;
358
359
	/**
360
	 * @var string
361
	 * @see SetIncoterms()
362
	 */
363
	public $libelle_incoterms;
364
365
	/**
366
	 * @var string
367
	 * @see display_incoterms()
368
	 */
369
	public $location_incoterms;
370
371
	public $name;
372
	public $lastname;
373
	public $firstname;
374
	public $civility_id;
375
376
	// Dates
377
	public $date_creation;			// Date creation
378
	public $date_validation;		// Date validation
379
	public $date_modification;		// Date last change (tms field)
380
381
382
383
	// No constructor as it is an abstract class
384
385
	/**
386
	 * Check an object id/ref exists
387
	 * If you don't need/want to instantiate object and just need to know if object exists, use this method instead of fetch
388
	 *
389
	 *  @param	string	$element   	String of element ('product', 'facture', ...)
390
	 *  @param	int		$id      	Id of object
391
	 *  @param  string	$ref     	Ref of object to check
392
	 *  @param	string	$ref_ext	Ref ext of object to check
393
	 *  @return int     			<0 if KO, 0 if OK but not found, >0 if OK and exists
394
	 */
395
	static function isExistingObject($element, $id, $ref='', $ref_ext='')
396
	{
397
		global $db,$conf;
398
399
		$sql = "SELECT rowid, ref, ref_ext";
400
		$sql.= " FROM ".MAIN_DB_PREFIX.$element;
401
		$sql.= " WHERE entity IN (".getEntity($element).")" ;
402
403
		if ($id > 0) $sql.= " AND rowid = ".$db->escape($id);
404
		else if ($ref) $sql.= " AND ref = '".$db->escape($ref)."'";
405
		else if ($ref_ext) $sql.= " AND ref_ext = '".$db->escape($ref_ext)."'";
406
		else {
407
			$error='ErrorWrongParameters';
408
			dol_print_error(get_class()."::isExistingObject ".$error, LOG_ERR);
409
			return -1;
410
		}
411
		if ($ref || $ref_ext) $sql.= " AND entity = ".$conf->entity;
412
413
		dol_syslog(get_class()."::isExistingObject", LOG_DEBUG);
414
		$resql = $db->query($sql);
415
		if ($resql)
416
		{
417
			$num=$db->num_rows($resql);
418
			if ($num > 0) return 1;
419
			else return 0;
420
		}
421
		return -1;
422
	}
423
424
	/**
425
	 * Method to output saved errors
426
	 *
427
	 * @return	string		String with errors
428
	 */
429
	function errorsToString()
430
	{
431
		return $this->error.(is_array($this->errors)?(($this->error!=''?', ':'').join(', ',$this->errors)):'');
432
	}
433
434
	/**
435
	 *	Return full name (civility+' '+name+' '+lastname)
436
	 *
437
	 *	@param	Translate	$langs			Language object for translation of civility (used only if option is 1)
0 ignored issues
show
Bug introduced by
The type Alixar\Base\Translate was not found. Did you mean Translate? If so, make sure to prefix the type with \.
Loading history...
438
	 *	@param	int			$option			0=No option, 1=Add civility
439
	 * 	@param	int			$nameorder		-1=Auto, 0=Lastname+Firstname, 1=Firstname+Lastname, 2=Firstname
440
	 * 	@param	int			$maxlen			Maximum length
441
	 * 	@return	string						String with full name
442
	 */
443
	function getFullName($langs,$option=0,$nameorder=-1,$maxlen=0)
444
	{
445
		//print "lastname=".$this->lastname." name=".$this->name." nom=".$this->nom."<br>\n";
446
		$lastname=$this->lastname;
447
		$firstname=$this->firstname;
448
		if (empty($lastname))  $lastname=(isset($this->lastname)?$this->lastname:(isset($this->name)?$this->name:(isset($this->nom)?$this->nom:(isset($this->societe)?$this->societe:(isset($this->company)?$this->company:'')))));
449
450
		$ret='';
451
		if ($option && $this->civility_id)
452
		{
453
			if ($langs->transnoentitiesnoconv("Civility".$this->civility_id)!="Civility".$this->civility_id) $ret.=$langs->transnoentitiesnoconv("Civility".$this->civility_id).' ';
454
			else $ret.=$this->civility_id.' ';
455
		}
456
457
		$ret.=dolGetFirstLastname($firstname, $lastname, $nameorder);
458
459
		return dol_trunc($ret,$maxlen);
460
	}
461
462
	/**
463
	 * 	Return full address of contact
464
	 *
465
	 * 	@param		int			$withcountry		1=Add country into address string
466
	 *  @param		string		$sep				Separator to use to build string
467
	 *  @param		int		    $withregion			1=Add region into address string
468
	 *	@return		string							Full address string
469
	 */
470
	function getFullAddress($withcountry=0, $sep="\n", $withregion=0)
471
	{
472
		if ($withcountry && $this->country_id && (empty($this->country_code) || empty($this->country)))
473
		{
474
			require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php';
475
			$tmparray=getCountry($this->country_id,'all');
476
			$this->country_code=$tmparray['code'];
477
			$this->country     =$tmparray['label'];
478
		}
479
480
        if ($withregion && $this->state_id && (empty($this->state_code) || empty($this->state) || empty($this->region) || empty($this->region_cpde)))
0 ignored issues
show
Bug introduced by
The property region_cpde does not exist on Alixar\Base\CommonObject. Did you mean region?
Loading history...
481
    	{
482
    		require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php';
483
    		$tmparray=getState($this->state_id,'all',0,1);
484
			$this->state_code   =$tmparray['code'];
485
			$this->state        =$tmparray['label'];
486
			$this->region_code  =$tmparray['region_code'];
487
			$this->region       =$tmparray['region'];
488
        }
489
490
		return dol_format_address($this, $withcountry, $sep);
491
	}
492
493
494
	/**
495
	 * 	Return full address for banner
496
	 *
497
	 * 	@param		string		$htmlkey            HTML id to make banner content unique
498
	 *  @param      Object      $object				Object (thirdparty, thirdparty of contact for contact, null for a member)
499
	 *	@return		string							Full address string
500
	 */
501
	function getBannerAddress($htmlkey, $object)
502
	{
503
		global $conf, $langs;
504
505
		$countriesusingstate=array('AU','US','IN','GB','ES','UK','TR');    // See also option MAIN_FORCE_STATE_INTO_ADDRESS
506
507
		$contactid=0;
508
		$thirdpartyid=0;
509
		if ($this->element == 'societe')
510
		{
511
			$thirdpartyid=$this->id;
512
		}
513
		if ($this->element == 'contact')
514
		{
515
			$contactid=$this->id;
516
			$thirdpartyid=$object->fk_soc;
517
		}
518
		if ($this->element == 'user')
519
		{
520
			$contactid=$this->contact_id;
521
			$thirdpartyid=$object->fk_soc;
522
		}
523
524
		$out='<!-- BEGIN part to show address block -->';
525
526
		$outdone=0;
527
		$coords = $this->getFullAddress(1,', ',$conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT);
528
		if ($coords)
529
		{
530
			if (! empty($conf->use_javascript_ajax))
531
			{
532
				$namecoords = $this->getFullName($langs,1).'<br>'.$coords;
533
				// hideonsmatphone because copyToClipboard call jquery dialog that does not work with jmobile
534
				$out.='<a href="#" class="hideonsmartphone" onclick="return copyToClipboard(\''.dol_escape_js($namecoords).'\',\''.dol_escape_js($langs->trans("HelpCopyToClipboard")).'\');">';
535
				$out.=img_picto($langs->trans("Address"), 'object_address.png');
536
				$out.='</a> ';
537
			}
538
			$out.=dol_print_address($coords, 'address_'.$htmlkey.'_'.$this->id, $this->element, $this->id, 1, ', '); $outdone++;
539
			$outdone++;
540
		}
541
542
		if (! in_array($this->country_code,$countriesusingstate) && empty($conf->global->MAIN_FORCE_STATE_INTO_ADDRESS)   // If MAIN_FORCE_STATE_INTO_ADDRESS is on, state is already returned previously with getFullAddress
543
				&& empty($conf->global->SOCIETE_DISABLE_STATE) && $this->state)
544
		{
545
            if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 && $this->region) {
546
                $out.=($outdone?' - ':'').$this->region.' - '.$this->state;
547
            }
548
            else {
549
                $out.=($outdone?' - ':'').$this->state;
550
            }
551
			$outdone++;
552
		}
553
554
		if (! empty($this->phone) || ! empty($this->phone_pro) || ! empty($this->phone_mobile) || ! empty($this->phone_perso) || ! empty($this->fax) || ! empty($this->office_phone) || ! empty($this->user_mobile) || ! empty($this->office_fax)) $out.=($outdone?'<br>':'');
555
		if (! empty($this->phone) && empty($this->phone_pro)) {		// For objects that store pro phone into ->phone
556
			$out.=dol_print_phone($this->phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
557
		}
558
		if (! empty($this->phone_pro)) {
559
			$out.=dol_print_phone($this->phone_pro,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
560
		}
561
		if (! empty($this->phone_mobile)) {
562
			$out.=dol_print_phone($this->phone_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','mobile',$langs->trans("PhoneMobile")); $outdone++;
563
		}
564
		if (! empty($this->phone_perso)) {
565
			$out.=dol_print_phone($this->phone_perso,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePerso")); $outdone++;
0 ignored issues
show
Bug Best Practice introduced by
The property phone_perso does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
566
		}
567
		if (! empty($this->office_phone)) {
568
			$out.=dol_print_phone($this->office_phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
569
		}
570
		if (! empty($this->user_mobile)) {
571
			$out.=dol_print_phone($this->user_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','mobile',$langs->trans("PhoneMobile")); $outdone++;
572
		}
573
		if (! empty($this->fax)) {
574
			$out.=dol_print_phone($this->fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX','&nbsp;','fax',$langs->trans("Fax")); $outdone++;
575
		}
576
		if (! empty($this->office_fax)) {
577
			$out.=dol_print_phone($this->office_fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX','&nbsp;','fax',$langs->trans("Fax")); $outdone++;
578
		}
579
580
		$out.='<div style="clear: both;"></div>';
581
		$outdone=0;
582
		if (! empty($this->email))
583
		{
584
			$out.=dol_print_email($this->email,$this->id,$object->id,'AC_EMAIL',0,0,1);
585
			$outdone++;
586
		}
587
		if (! empty($this->url))
588
		{
589
			$out.=dol_print_url($this->url,'_goout',0,1);
0 ignored issues
show
Bug Best Practice introduced by
The property url does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
590
			$outdone++;
591
		}
592
		$out.='<div style="clear: both;">';
593
		if (! empty($conf->socialnetworks->enabled))
594
		{
595
			if ($this->skype) $out.=dol_print_socialnetworks($this->skype,$this->id,$object->id,'skype');
596
			$outdone++;
597
			if ($this->jabberid) $out.=dol_print_socialnetworks($this->jabberid,$this->id,$object->id,'jabber');
0 ignored issues
show
Bug Best Practice introduced by
The property jabberid does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
598
			$outdone++;
599
			if ($this->twitter) $out.=dol_print_socialnetworks($this->twitter,$this->id,$object->id,'twitter');
600
			$outdone++;
601
			if ($this->facebook) $out.=dol_print_socialnetworks($this->facebook,$this->id,$object->id,'facebook');
602
			$outdone++;
603
		}
604
		$out.='</div>';
605
606
		$out.='<!-- END Part to show address block -->';
607
608
		return $out;
609
	}
610
611
	/**
612
	 * Return the link of last main doc file for direct public download.
613
	 *
614
	 * @param	string	$modulepart			Module related to document
615
	 * @param	int		$initsharekey		Init the share key if it was not yet defined
616
	 * @param	int		$relativelink		0=Return full external link, 1=Return link relative to root of file
617
	 * @return	string						Link or empty string if there is no download link
618
	 */
619
	function getLastMainDocLink($modulepart, $initsharekey=0, $relativelink=0)
620
	{
621
		global $user, $dolibarr_main_url_root;
622
623
		if (empty($this->last_main_doc))
624
		{
625
			return '';		// No way to known which document name to use
626
		}
627
628
		include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
629
		$ecmfile=new EcmFiles($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
Bug introduced by
The type Alixar\Base\EcmFiles was not found. Did you mean EcmFiles? If so, make sure to prefix the type with \.
Loading history...
630
		$result = $ecmfile->fetch(0, '', $this->last_main_doc);
0 ignored issues
show
Bug Best Practice introduced by
The property last_main_doc does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
631
		if ($result < 0)
632
		{
633
			$this->error = $ecmfile->error;
634
			$this->errors = $ecmfile->errors;
635
			return -1;
636
		}
637
638
		if (empty($ecmfile->id))
639
		{
640
			// Add entry into index
641
			if ($initsharekey)
642
			{
643
				require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
644
				// TODO We can't, we dont' have full path of file, only last_main_doc adn ->element, so we must rebuild full path first
645
				/*
646
				$ecmfile->filepath = $rel_dir;
647
				$ecmfile->filename = $filename;
648
				$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
649
				$ecmfile->fullpath_orig = '';
650
				$ecmfile->gen_or_uploaded = 'generated';
651
				$ecmfile->description = '';    // indexed content
652
				$ecmfile->keyword = '';        // keyword content
653
				$ecmfile->share = getRandomPassword(true);
654
				$result = $ecmfile->create($user);
655
				if ($result < 0)
656
				{
657
					$this->error = $ecmfile->error;
658
					$this->errors = $ecmfile->errors;
659
				}
660
				*/
661
			}
662
			else return '';
663
		}
664
		elseif (empty($ecmfile->share))
665
		{
666
			// Add entry into index
667
			if ($initsharekey)
668
			{
669
				require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
670
				$ecmfile->share = getRandomPassword(true);
671
				$ecmfile->update($user);
672
			}
673
			else return '';
674
		}
675
676
		// Define $urlwithroot
677
		$urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
678
		$urlwithroot=$urlwithouturlroot.DOL_URL_ROOT;		// This is to use external domain name found into config file
679
		//$urlwithroot=DOL_MAIN_URL_ROOT;					// This is to use same domain name than current
680
681
		$forcedownload=0;
682
683
		$paramlink='';
684
		//if (! empty($modulepart)) $paramlink.=($paramlink?'&':'').'modulepart='.$modulepart;		// For sharing with hash (so public files), modulepart is not required.
685
		//if (! empty($ecmfile->entity)) $paramlink.='&entity='.$ecmfile->entity; 					// For sharing with hash (so public files), entity is not required.
686
		//$paramlink.=($paramlink?'&':'').'file='.urlencode($filepath);								// No need of name of file for public link, we will use the hash
687
		if (! empty($ecmfile->share)) $paramlink.=($paramlink?'&':'').'hashp='.$ecmfile->share;			// Hash for public share
688
		if ($forcedownload) $paramlink.=($paramlink?'&':'').'attachment=1';
689
690
		if ($relativelink)
691
		{
692
			$linktoreturn='document.php'.($paramlink?'?'.$paramlink:'');
693
		}
694
		else
695
		{
696
			$linktoreturn=$urlwithroot.'/document.php'.($paramlink?'?'.$paramlink:'');
697
		}
698
699
		// Here $ecmfile->share is defined
700
		return $linktoreturn;
701
	}
702
703
704
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
705
	/**
706
	 *  Add a link between element $this->element and a contact
707
	 *
708
	 *  @param	int		$fk_socpeople       Id of thirdparty contact (if source = 'external') or id of user (if souce = 'internal') to link
709
	 *  @param 	int		$type_contact 		Type of contact (code or id). Must be id or code found into table llx_c_type_contact. For example: SALESREPFOLL
710
	 *  @param  string	$source             external=Contact extern (llx_socpeople), internal=Contact intern (llx_user)
711
	 *  @param  int		$notrigger			Disable all triggers
712
	 *  @return int                 		<0 if KO, >0 if OK
713
	 */
714
	function add_contact($fk_socpeople, $type_contact, $source='external',$notrigger=0)
715
	{
716
        // phpcs:enable
717
		global $user,$langs;
718
719
720
		dol_syslog(get_class($this)."::add_contact $fk_socpeople, $type_contact, $source, $notrigger");
721
722
		// Check parameters
723
		if ($fk_socpeople <= 0)
724
		{
725
			$langs->load("errors");
726
			$this->error=$langs->trans("ErrorWrongValueForParameterX","1");
727
			dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
728
			return -1;
729
		}
730
		if (! $type_contact)
731
		{
732
			$langs->load("errors");
733
			$this->error=$langs->trans("ErrorWrongValueForParameterX","2");
734
			dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
735
			return -2;
736
		}
737
738
		$id_type_contact=0;
739
		if (is_numeric($type_contact))
740
		{
741
			$id_type_contact=$type_contact;
742
		}
743
		else
744
		{
745
			// We look for id type_contact
746
			$sql = "SELECT tc.rowid";
747
			$sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
748
			$sql.= " WHERE tc.element='".$this->db->escape($this->element)."'";
749
			$sql.= " AND tc.source='".$this->db->escape($source)."'";
750
			$sql.= " AND tc.code='".$this->db->escape($type_contact)."' AND tc.active=1";
751
			//print $sql;
752
			$resql=$this->db->query($sql);
753
			if ($resql)
754
			{
755
				$obj = $this->db->fetch_object($resql);
756
				if ($obj) $id_type_contact=$obj->rowid;
757
			}
758
		}
759
760
		if ($id_type_contact == 0)
761
		{
762
			$this->error='CODE_NOT_VALID_FOR_THIS_ELEMENT';
763
			dol_syslog("CODE_NOT_VALID_FOR_THIS_ELEMENT: Code type of contact '".$type_contact."' does not exists or is not active for element ".$this->element.", we can ignore it");
764
			return -3;
765
		}
766
767
		$datecreate = dol_now();
768
769
		// Socpeople must have already been added by some trigger, then we have to check it to avoid DB_ERROR_RECORD_ALREADY_EXISTS error
770
		$TListeContacts=$this->liste_contact(-1, $source);
771
		$already_added=false;
772
		if(!empty($TListeContacts)) {
773
			foreach($TListeContacts as $array_contact) {
774
				if($array_contact['status'] == 4 && $array_contact['id'] == $fk_socpeople && $array_contact['fk_c_type_contact'] == $id_type_contact) {
775
					$already_added=true;
776
					break;
777
				}
778
			}
779
		}
780
781
		if(!$already_added) {
782
783
			$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
784
785
			// Insert into database
786
			$sql = "INSERT INTO ".MAIN_DB_PREFIX."element_contact";
787
			$sql.= " (element_id, fk_socpeople, datecreate, statut, fk_c_type_contact) ";
788
			$sql.= " VALUES (".$this->id.", ".$fk_socpeople." , " ;
789
			$sql.= "'".$this->db->idate($datecreate)."'";
790
			$sql.= ", 4, ". $id_type_contact;
791
			$sql.= ")";
792
793
			$resql=$this->db->query($sql);
794
			if ($resql)
795
			{
796
				if (! $notrigger)
797
				{
798
					$result=$this->call_trigger(strtoupper($this->element).'_ADD_CONTACT', $user);
799
					if ($result < 0)
800
					{
801
						$this->db->rollback();
802
						return -1;
803
					}
804
				}
805
806
				$this->db->commit();
807
				return 1;
808
			}
809
			else
810
			{
811
				if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS')
812
				{
813
					$this->error=$this->db->errno();
814
					$this->db->rollback();
815
					echo 'err rollback';
816
					return -2;
817
				}
818
				else
819
				{
820
					$this->error=$this->db->error();
821
					$this->db->rollback();
822
					return -1;
823
				}
824
			}
825
		} else return 0;
826
	}
827
828
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
829
	/**
830
	 *    Copy contact from one element to current
831
	 *
832
	 *    @param    CommonObject    $objFrom    Source element
833
	 *    @param    string          $source     Nature of contact ('internal' or 'external')
834
	 *    @return   int                         >0 if OK, <0 if KO
835
	 */
836
	function copy_linked_contact($objFrom, $source='internal')
837
	{
838
        // phpcs:enable
839
		$contacts = $objFrom->liste_contact(-1, $source);
840
		foreach($contacts as $contact)
841
		{
842
			if ($this->add_contact($contact['id'], $contact['fk_c_type_contact'], $contact['source']) < 0)
843
			{
844
				$this->error=$this->db->lasterror();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
845
				return -1;
846
			}
847
		}
848
		return 1;
849
	}
850
851
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
852
	/**
853
	 *      Update a link to contact line
854
	 *
855
	 *      @param	int		$rowid              Id of line contact-element
856
	 * 		@param	int		$statut	            New status of link
857
	 *      @param  int		$type_contact_id    Id of contact type (not modified if 0)
858
	 *      @param  int		$fk_socpeople	    Id of soc_people to update (not modified if 0)
859
	 *      @return int                 		<0 if KO, >= 0 if OK
860
	 */
861
	function update_contact($rowid, $statut, $type_contact_id=0, $fk_socpeople=0)
862
	{
863
        // phpcs:enable
864
		// Insert into database
865
		$sql = "UPDATE ".MAIN_DB_PREFIX."element_contact set";
866
		$sql.= " statut = ".$statut;
867
		if ($type_contact_id) $sql.= ", fk_c_type_contact = '".$type_contact_id ."'";
868
		if ($fk_socpeople) $sql.= ", fk_socpeople = '".$fk_socpeople ."'";
869
		$sql.= " where rowid = ".$rowid;
870
		$resql=$this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
871
		if ($resql)
872
		{
873
			return 0;
874
		}
875
		else
876
		{
877
			$this->error=$this->db->lasterror();
878
			return -1;
879
		}
880
	}
881
882
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
883
	/**
884
	 *    Delete a link to contact line
885
	 *
886
	 *    @param	int		$rowid			Id of contact link line to delete
887
	 *    @param	int		$notrigger		Disable all triggers
888
	 *    @return   int						>0 if OK, <0 if KO
889
	 */
890
	function delete_contact($rowid, $notrigger=0)
891
	{
892
        // phpcs:enable
893
		global $user;
894
895
896
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
897
898
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
899
		$sql.= " WHERE rowid =".$rowid;
900
901
		dol_syslog(get_class($this)."::delete_contact", LOG_DEBUG);
902
		if ($this->db->query($sql))
903
		{
904
			if (! $notrigger)
905
			{
906
				$result=$this->call_trigger(strtoupper($this->element).'_DELETE_CONTACT', $user);
907
				if ($result < 0) { $this->db->rollback(); return -1; }
908
			}
909
910
			$this->db->commit();
911
			return 1;
912
		}
913
		else
914
		{
915
			$this->error=$this->db->lasterror();
916
			$this->db->rollback();
917
			return -1;
918
		}
919
	}
920
921
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
922
	/**
923
	 *    Delete all links between an object $this and all its contacts
924
	 *
925
	 *	  @param	string	$source		'' or 'internal' or 'external'
926
	 *	  @param	string	$code		Type of contact (code or id)
927
	 *    @return   int					>0 if OK, <0 if KO
928
	 */
929
	function delete_linked_contact($source='',$code='')
930
	{
931
        // phpcs:enable
932
		$temp = array();
933
		$typeContact = $this->liste_type_contact($source,'',0,0,$code);
934
935
		foreach($typeContact as $key => $value)
936
		{
937
			array_push($temp,$key);
938
		}
939
		$listId = implode(",", $temp);
940
941
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
942
		$sql.= " WHERE element_id = ".$this->id;
943
		if ($listId)
944
			$sql.= " AND fk_c_type_contact IN (".$listId.")";
945
946
		dol_syslog(get_class($this)."::delete_linked_contact", LOG_DEBUG);
947
		if ($this->db->query($sql))
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
948
		{
949
			return 1;
950
		}
951
		else
952
		{
953
			$this->error=$this->db->lasterror();
954
			return -1;
955
		}
956
	}
957
958
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
959
	/**
960
	 *    Get array of all contacts for an object
961
	 *
962
	 *    @param	int			$statut		Status of links to get (-1=all)
963
	 *    @param	string		$source		Source of contact: external or thirdparty (llx_socpeople) or internal (llx_user)
964
	 *    @param	int         $list       0:Return array contains all properties, 1:Return array contains just id
965
	 *    @param    string      $code       Filter on this code of contact type ('SHIPPING', 'BILLING', ...)
966
	 *    @return	array|int		        Array of contacts, -1 if error
967
	 */
968
	function liste_contact($statut=-1,$source='external',$list=0,$code='')
969
	{
970
        // phpcs:enable
971
		global $langs;
972
973
		$tab=array();
974
975
		$sql = "SELECT ec.rowid, ec.statut as statuslink, ec.fk_socpeople as id, ec.fk_c_type_contact";    // This field contains id of llx_socpeople or id of llx_user
976
		if ($source == 'internal') $sql.=", '-1' as socid, t.statut as statuscontact, t.login, t.photo";
977
		if ($source == 'external' || $source == 'thirdparty') $sql.=", t.fk_soc as socid, t.statut as statuscontact";
978
		$sql.= ", t.civility as civility, t.lastname as lastname, t.firstname, t.email";
979
		$sql.= ", tc.source, tc.element, tc.code, tc.libelle";
980
		$sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact tc";
981
		$sql.= ", ".MAIN_DB_PREFIX."element_contact ec";
982
		if ($source == 'internal') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid";
983
		if ($source == 'external'|| $source == 'thirdparty') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid";
984
		$sql.= " WHERE ec.element_id =".$this->id;
985
		$sql.= " AND ec.fk_c_type_contact=tc.rowid";
986
		$sql.= " AND tc.element='".$this->db->escape($this->element)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
987
		if ($code) $sql.= " AND tc.code = '".$this->db->escape($code)."'";
988
		if ($source == 'internal') $sql.= " AND tc.source = 'internal'";
989
		if ($source == 'external' || $source == 'thirdparty') $sql.= " AND tc.source = 'external'";
990
		$sql.= " AND tc.active=1";
991
		if ($statut >= 0) $sql.= " AND ec.statut = '".$statut."'";
992
		$sql.=" ORDER BY t.lastname ASC";
993
994
		dol_syslog(get_class($this)."::liste_contact", LOG_DEBUG);
995
		$resql=$this->db->query($sql);
996
		if ($resql)
997
		{
998
			$num=$this->db->num_rows($resql);
999
			$i=0;
1000
			while ($i < $num)
1001
			{
1002
				$obj = $this->db->fetch_object($resql);
1003
1004
				if (! $list)
1005
				{
1006
					$transkey="TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
1007
					$libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
1008
					$tab[$i]=array('source'=>$obj->source,'socid'=>$obj->socid,'id'=>$obj->id,
1009
								   'nom'=>$obj->lastname,      // For backward compatibility
1010
								   'civility'=>$obj->civility, 'lastname'=>$obj->lastname, 'firstname'=>$obj->firstname, 'email'=>$obj->email, 'login'=>$obj->login, 'photo'=>$obj->photo, 'statuscontact'=>$obj->statuscontact,
1011
								   'rowid'=>$obj->rowid, 'code'=>$obj->code, 'libelle'=>$libelle_type, 'status'=>$obj->statuslink, 'fk_c_type_contact'=>$obj->fk_c_type_contact);
1012
				}
1013
				else
1014
				{
1015
					$tab[$i]=$obj->id;
1016
				}
1017
1018
				$i++;
1019
			}
1020
1021
			return $tab;
1022
		}
1023
		else
1024
		{
1025
			$this->error=$this->db->lasterror();
1026
			dol_print_error($this->db);
1027
			return -1;
1028
		}
1029
	}
1030
1031
1032
	/**
1033
	 * 		Update status of a contact linked to object
1034
	 *
1035
	 * 		@param	int		$rowid		Id of link between object and contact
1036
	 * 		@return	int					<0 if KO, >=0 if OK
1037
	 */
1038
	function swapContactStatus($rowid)
1039
	{
1040
		$sql = "SELECT ec.datecreate, ec.statut, ec.fk_socpeople, ec.fk_c_type_contact,";
1041
		$sql.= " tc.code, tc.libelle";
1042
		//$sql.= ", s.fk_soc";
1043
		$sql.= " FROM (".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as tc)";
1044
		//$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as s ON ec.fk_socpeople=s.rowid";	// Si contact de type external, alors il est lie a une societe
1045
		$sql.= " WHERE ec.rowid =".$rowid;
1046
		$sql.= " AND ec.fk_c_type_contact=tc.rowid";
1047
		$sql.= " AND tc.element = '".$this->db->escape($this->element)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1048
1049
		dol_syslog(get_class($this)."::swapContactStatus", LOG_DEBUG);
1050
		$resql=$this->db->query($sql);
1051
		if ($resql)
1052
		{
1053
			$obj = $this->db->fetch_object($resql);
1054
			$newstatut = ($obj->statut == 4) ? 5 : 4;
1055
			$result = $this->update_contact($rowid, $newstatut);
1056
			$this->db->free($resql);
1057
			return $result;
1058
		}
1059
		else
1060
		{
1061
			$this->error=$this->db->error();
1062
			dol_print_error($this->db);
1063
			return -1;
1064
		}
1065
	}
1066
1067
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1068
	/**
1069
	 *      Return array with list of possible values for type of contacts
1070
	 *
1071
	 *      @param	string	$source     'internal', 'external' or 'all'
1072
	 *      @param	string	$order		Sort order by : 'position', 'code', 'rowid'...
1073
	 *      @param  int		$option     0=Return array id->label, 1=Return array code->label
1074
	 *      @param  int		$activeonly 0=all status of contact, 1=only the active
1075
	 *		@param	string	$code		Type of contact (Example: 'CUSTOMER', 'SERVICE')
1076
	 *      @return array       		Array list of type of contacts (id->label if option=0, code->label if option=1)
1077
	 */
1078
	function liste_type_contact($source='internal', $order='position', $option=0, $activeonly=0, $code='')
1079
	{
1080
        // phpcs:enable
1081
		global $langs;
1082
1083
		if (empty($order)) $order='position';
1084
		if ($order == 'position') $order.=',code';
1085
1086
		$tab = array();
1087
		$sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position";
1088
		$sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
1089
		$sql.= " WHERE tc.element='".$this->db->escape($this->element)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1090
		if ($activeonly == 1) $sql.= " AND tc.active=1"; // only the active types
1091
		if (! empty($source) && $source != 'all') $sql.= " AND tc.source='".$this->db->escape($source)."'";
1092
		if (! empty($code)) $sql.= " AND tc.code='".$this->db->escape($code)."'";
1093
		$sql.= $this->db->order($order,'ASC');
1094
1095
		//print "sql=".$sql;
1096
		$resql=$this->db->query($sql);
1097
		if ($resql)
1098
		{
1099
			$num=$this->db->num_rows($resql);
1100
			$i=0;
1101
			while ($i < $num)
1102
			{
1103
				$obj = $this->db->fetch_object($resql);
1104
1105
				$transkey="TypeContact_".$this->element."_".$source."_".$obj->code;
1106
				$libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
1107
				if (empty($option)) $tab[$obj->rowid]=$libelle_type;
1108
				else $tab[$obj->code]=$libelle_type;
1109
				$i++;
1110
			}
1111
			return $tab;
1112
		}
1113
		else
1114
		{
1115
			$this->error=$this->db->lasterror();
1116
			//dol_print_error($this->db);
1117
			return null;
1118
		}
1119
	}
1120
1121
	/**
1122
	 *      Return id of contacts for a source and a contact code.
1123
	 *      Example: contact client de facturation ('external', 'BILLING')
1124
	 *      Example: contact client de livraison ('external', 'SHIPPING')
1125
	 *      Example: contact interne suivi paiement ('internal', 'SALESREPFOLL')
1126
	 *
1127
	 *		@param	string	$source		'external' or 'internal'
1128
	 *		@param	string	$code		'BILLING', 'SHIPPING', 'SALESREPFOLL', ...
1129
	 *		@param	int		$status		limited to a certain status
1130
	 *      @return array       		List of id for such contacts
1131
	 */
1132
	function getIdContact($source,$code,$status=0)
1133
	{
1134
		global $conf;
1135
1136
		$result=array();
1137
		$i=0;
1138
		//cas particulier pour les expeditions
1139
		if($this->element=='shipping' && $this->origin_id != 0) {
1140
			$id=$this->origin_id;
1141
			$element='commande';
1142
        } else if($this->element=='reception' && $this->origin_id != 0) {
1143
            $id=$this->origin_id;
1144
            $element='order_supplier';
1145
		} else {
1146
			$id=$this->id;
1147
			$element=$this->element;
1148
		}
1149
1150
		$sql = "SELECT ec.fk_socpeople";
1151
		$sql.= " FROM ".MAIN_DB_PREFIX."element_contact as ec,";
1152
		if ($source == 'internal') $sql.= " ".MAIN_DB_PREFIX."user as c,";
1153
		if ($source == 'external') $sql.= " ".MAIN_DB_PREFIX."socpeople as c,";
1154
		$sql.= " ".MAIN_DB_PREFIX."c_type_contact as tc";
1155
		$sql.= " WHERE ec.element_id = ".$id;
1156
		$sql.= " AND ec.fk_socpeople = c.rowid";
1157
		if ($source == 'internal') $sql.= " AND c.entity IN (".getEntity('user').")";
1158
		if ($source == 'external') $sql.= " AND c.entity IN (".getEntity('societe').")";
1159
		$sql.= " AND ec.fk_c_type_contact = tc.rowid";
1160
		$sql.= " AND tc.element = '".$element."'";
1161
		$sql.= " AND tc.source = '".$source."'";
1162
		$sql.= " AND tc.code = '".$code."'";
1163
		$sql.= " AND tc.active = 1";
1164
		if ($status) $sql.= " AND ec.statut = ".$status;
1165
1166
		dol_syslog(get_class($this)."::getIdContact", LOG_DEBUG);
1167
		$resql=$this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1168
		if ($resql)
1169
		{
1170
			while ($obj = $this->db->fetch_object($resql))
1171
			{
1172
				$result[$i]=$obj->fk_socpeople;
1173
				$i++;
1174
			}
1175
		}
1176
		else
1177
		{
1178
			$this->error=$this->db->error();
1179
			return null;
1180
		}
1181
1182
		return $result;
1183
	}
1184
1185
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1186
	/**
1187
	 *		Load object contact with id=$this->contactid into $this->contact
1188
	 *
1189
	 *		@param	int		$contactid      Id du contact. Use this->contactid if empty.
1190
	 *		@return	int						<0 if KO, >0 if OK
1191
	 */
1192
	function fetch_contact($contactid=null)
1193
	{
1194
        // phpcs:enable
1195
		if (empty($contactid)) $contactid=$this->contactid;
1196
1197
		if (empty($contactid)) return 0;
1198
1199
		require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1200
		$contact = new Contact($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1201
		$result=$contact->fetch($contactid);
1202
		$this->contact = $contact;
1203
		return $result;
1204
	}
1205
1206
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1207
	/**
1208
	 *    	Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty
1209
	 *
1210
	 *		@param		int		$force_thirdparty_id	Force thirdparty id
1211
	 *		@return		int								<0 if KO, >0 if OK
1212
	 */
1213
	function fetch_thirdparty($force_thirdparty_id=0)
1214
	{
1215
        // phpcs:enable
1216
		global $conf;
1217
1218
		if (empty($this->socid) && empty($this->fk_soc) && empty($this->fk_thirdparty) && empty($force_thirdparty_id))
0 ignored issues
show
Bug introduced by
The property fk_thirdparty does not exist on Alixar\Base\CommonObject. Did you mean thirdparty?
Loading history...
1219
			return 0;
1220
1221
		require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1222
1223
		$idtofetch = isset($this->socid) ? $this->socid : (isset($this->fk_soc) ? $this->fk_soc : $this->fk_thirdparty);
1224
		if ($force_thirdparty_id)
1225
			$idtofetch = $force_thirdparty_id;
1226
1227
		if ($idtofetch) {
1228
			$thirdparty = new Societe($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1229
			$result = $thirdparty->fetch($idtofetch);
1230
			$this->thirdparty = $thirdparty;
1231
1232
			// Use first price level if level not defined for third party
1233
			if (!empty($conf->global->PRODUIT_MULTIPRICES) && empty($this->thirdparty->price_level)) {
1234
				$this->thirdparty->price_level = 1;
1235
			}
1236
1237
			return $result;
1238
		} else
1239
			return -1;
1240
	}
1241
1242
1243
	/**
1244
	 * Looks for an object with ref matching the wildcard provided
1245
	 * It does only work when $this->table_ref_field is set
1246
	 *
1247
	 * @param string $ref Wildcard
1248
	 * @return int >1 = OK, 0 = Not found or table_ref_field not defined, <0 = KO
1249
	 */
1250
	public function fetchOneLike($ref)
1251
	{
1252
		if (!$this->table_ref_field) {
1253
			return 0;
1254
		}
1255
1256
		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE '.$this->table_ref_field.' LIKE "'.$this->db->escape($ref).'" LIMIT 1';
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1257
1258
		$query = $this->db->query($sql);
1259
1260
		if (!$this->db->num_rows($query)) {
1261
			return 0;
1262
		}
1263
1264
		$result = $this->db->fetch_object($query);
1265
1266
		return $this->fetch($result->rowid);
0 ignored issues
show
Bug introduced by
The method fetch() does not exist on Alixar\Base\CommonObject. Did you maybe mean fetch_user()? ( Ignorable by Annotation )

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

1266
		return $this->/** @scrutinizer ignore-call */ fetch($result->rowid);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1267
	}
1268
1269
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1270
	/**
1271
	 *	Load data for barcode into properties ->barcode_type*
1272
	 *	Properties ->barcode_type that is id of barcode. Type is used to find other properties, but
1273
	 *  if it is not defined, ->element must be defined to know default barcode type.
1274
	 *
1275
	 *	@return		int			<0 if KO, 0 if can't guess type of barcode (ISBN, EAN13...), >0 if OK (all barcode properties loaded)
1276
	 */
1277
	function fetch_barcode()
1278
	{
1279
        // phpcs:enable
1280
		global $conf;
1281
1282
		dol_syslog(get_class($this).'::fetch_barcode this->element='.$this->element.' this->barcode_type='.$this->barcode_type);
1283
1284
		$idtype=$this->barcode_type;
1285
		if (empty($idtype) && $idtype != '0')	// If type of barcode no set, we try to guess. If set to '0' it means we forced to have type remain not defined
1286
		{
1287
			if ($this->element == 'product')      $idtype = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
1288
			else if ($this->element == 'societe') $idtype = $conf->global->GENBARCODE_BARCODETYPE_THIRDPARTY;
1289
			else dol_syslog('Call fetch_barcode with barcode_type not defined and cant be guessed', LOG_WARNING);
1290
		}
1291
1292
		if ($idtype > 0)
1293
		{
1294
			if (empty($this->barcode_type) || empty($this->barcode_type_code) || empty($this->barcode_type_label) || empty($this->barcode_type_coder))    // If data not already loaded
1295
			{
1296
				$sql = "SELECT rowid, code, libelle as label, coder";
1297
				$sql.= " FROM ".MAIN_DB_PREFIX."c_barcode_type";
1298
				$sql.= " WHERE rowid = ".$idtype;
1299
				dol_syslog(get_class($this).'::fetch_barcode', LOG_DEBUG);
1300
				$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1301
				if ($resql)
1302
				{
1303
					$obj = $this->db->fetch_object($resql);
1304
					$this->barcode_type       = $obj->rowid;
1305
					$this->barcode_type_code  = $obj->code;
1306
					$this->barcode_type_label = $obj->label;
1307
					$this->barcode_type_coder = $obj->coder;
1308
					return 1;
1309
				}
1310
				else
1311
				{
1312
					dol_print_error($this->db);
1313
					return -1;
1314
				}
1315
			}
1316
		}
1317
		return 0;
1318
	}
1319
1320
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1321
	/**
1322
	 *		Load the project with id $this->fk_project into this->project
1323
	 *
1324
	 *		@return		int			<0 if KO, >=0 if OK
1325
	 */
1326
	function fetch_projet()
1327
	{
1328
        // phpcs:enable
1329
		include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
1330
1331
		if (empty($this->fk_project) && ! empty($this->fk_projet)) $this->fk_project = $this->fk_projet;	// For backward compatibility
0 ignored issues
show
Bug introduced by
The property fk_projet does not exist on Alixar\Base\CommonObject. Did you mean projet?
Loading history...
1332
		if (empty($this->fk_project)) return 0;
1333
1334
		$project = new Project($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1335
		$result = $project->fetch($this->fk_project);
1336
1337
		$this->projet = $project;	// deprecated
1338
		$this->project = $project;
1339
		return $result;
1340
	}
1341
1342
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1343
	/**
1344
	 *		Load the product with id $this->fk_product into this->product
1345
	 *
1346
	 *		@return		int			<0 if KO, >=0 if OK
1347
	 */
1348
	function fetch_product()
1349
	{
1350
        // phpcs:enable
1351
		include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1352
1353
		if (empty($this->fk_product)) return 0;
0 ignored issues
show
Bug introduced by
The property fk_product does not exist on Alixar\Base\CommonObject. Did you mean product?
Loading history...
1354
1355
		$product = new Product($this->db);
0 ignored issues
show
Bug introduced by
The type Alixar\Base\Product was not found. Did you mean Product? If so, make sure to prefix the type with \.
Loading history...
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1356
		$result = $product->fetch($this->fk_product);
1357
1358
		$this->product = $product;
1359
		return $result;
1360
	}
1361
1362
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1363
	/**
1364
	 *		Load the user with id $userid into this->user
1365
	 *
1366
	 *		@param	int		$userid 		Id du contact
1367
	 *		@return	int						<0 if KO, >0 if OK
1368
	 */
1369
	function fetch_user($userid)
1370
	{
1371
        // phpcs:enable
1372
		$user = new User($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1373
		$result=$user->fetch($userid);
1374
		$this->user = $user;
1375
		return $result;
1376
	}
1377
1378
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1379
	/**
1380
	 *	Read linked origin object
1381
	 *
1382
	 *	@return		void
1383
	 */
1384
	function fetch_origin()
1385
	{
1386
        // phpcs:enable
1387
		if ($this->origin == 'shipping') $this->origin = 'expedition';
1388
		if ($this->origin == 'delivery') $this->origin = 'livraison';
1389
        if ($this->origin == 'order_supplier') $this->origin = 'commandeFournisseur';
1390
1391
		$origin = $this->origin;
1392
1393
		$classname = ucfirst($origin);
1394
		$this->$origin = new $classname($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1395
		$this->$origin->fetch($this->origin_id);
1396
	}
1397
1398
	/**
1399
     *  Load object from specific field
1400
     *
1401
     *  @param	string	$table		Table element or element line
1402
     *  @param	string	$field		Field selected
1403
     *  @param	string	$key		Import key
1404
     *  @param	string	$element	Element name
1405
     *	@return	int					<0 if KO, >0 if OK
1406
     */
1407
	function fetchObjectFrom($table, $field, $key, $element = null)
1408
	{
1409
		global $conf;
1410
1411
		$result=false;
1412
1413
		$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$table;
1414
		$sql.= " WHERE ".$field." = '".$key."'";
1415
		if (! empty($element)) {
1416
			$sql.= " AND entity IN (".getEntity($element).")";
1417
		} else {
1418
			$sql.= " AND entity = ".$conf->entity;
1419
		}
1420
1421
		dol_syslog(get_class($this).'::fetchObjectFrom', LOG_DEBUG);
1422
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1423
		if ($resql)
1424
		{
1425
			$row = $this->db->fetch_row($resql);
1426
			// Test for avoid error -1
1427
			if ($row[0] > 0) {
1428
				$result = $this->fetch($row[0]);
1429
			}
1430
		}
1431
1432
		return $result;
1433
	}
1434
1435
	/**
1436
	 *	Getter generic. Load value from a specific field
1437
	 *
1438
	 *	@param	string	$table		Table of element or element line
1439
	 *	@param	int		$id			Element id
1440
	 *	@param	string	$field		Field selected
1441
	 *	@return	int					<0 if KO, >0 if OK
1442
	 */
1443
	function getValueFrom($table, $id, $field)
1444
	{
1445
		$result=false;
1446
		if (!empty($id) && !empty($field) && !empty($table)) {
1447
			$sql = "SELECT ".$field." FROM ".MAIN_DB_PREFIX.$table;
1448
			$sql.= " WHERE rowid = ".$id;
1449
1450
			dol_syslog(get_class($this).'::getValueFrom', LOG_DEBUG);
1451
			$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1452
			if ($resql)
1453
			{
1454
				$row = $this->db->fetch_row($resql);
1455
				$result = $row[0];
1456
			}
1457
		}
1458
		return $result;
1459
	}
1460
1461
	/**
1462
	 *	Setter generic. Update a specific field into database.
1463
	 *  Warning: Trigger is run only if param trigkey is provided.
1464
	 *
1465
	 *	@param	string		$field			Field to update
1466
	 *	@param	mixed		$value			New value
1467
	 *	@param	string		$table			To force other table element or element line (should not be used)
1468
	 *	@param	int			$id				To force other object id (should not be used)
1469
	 *	@param	string		$format			Data format ('text', 'date'). 'text' is used if not defined
1470
	 *	@param	string		$id_field		To force rowid field name. 'rowid' is used if not defined
1471
	 *	@param	User|string	$fuser			Update the user of last update field with this user. If not provided, current user is used except if value is 'none'
1472
	 *  @param  string      $trigkey    	Trigger key to run (in most cases something like 'XXX_MODIFY')
1473
	 *  @param	string		$fk_user_field	Name of field to save user id making change
1474
	 *	@return	int							<0 if KO, >0 if OK
1475
	 *  @see updateExtraField
1476
	 */
1477
	function setValueFrom($field, $value, $table='', $id=null, $format='', $id_field='', $fuser=null, $trigkey='', $fk_user_field='fk_user_modif')
1478
	{
1479
		global $user,$langs,$conf;
1480
1481
		if (empty($table)) 	  $table=$this->table_element;
1482
		if (empty($id))    	  $id=$this->id;
1483
		if (empty($format))   $format='text';
1484
		if (empty($id_field)) $id_field='rowid';
1485
1486
		$error=0;
1487
1488
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1489
1490
		// Special case
1491
		if ($table == 'product' && $field == 'note_private') $field='note';
1492
		if (in_array($table, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))) $fk_user_field = 'fk_user_mod';
1493
1494
		$sql = "UPDATE ".MAIN_DB_PREFIX.$table." SET ";
1495
1496
		if ($format == 'text') $sql.= $field." = '".$this->db->escape($value)."'";
1497
		else if ($format == 'int') $sql.= $field." = ".$this->db->escape($value);
1498
		else if ($format == 'date') $sql.= $field." = ".($value ? "'".$this->db->idate($value)."'" : "null");
1499
1500
		if ($fk_user_field)
1501
		{
1502
			if (! empty($fuser) && is_object($fuser)) $sql.=", ".$fk_user_field." = ".$fuser->id;
1503
			elseif (empty($fuser) || $fuser != 'none') $sql.=", ".$fk_user_field." = ".$user->id;
1504
		}
1505
1506
		$sql.= " WHERE ".$id_field." = ".$id;
1507
1508
		dol_syslog(get_class($this)."::".__FUNCTION__."", LOG_DEBUG);
1509
		$resql = $this->db->query($sql);
1510
		if ($resql)
1511
		{
1512
			if ($trigkey)
1513
			{
1514
				// call trigger with updated object values
1515
				if (empty($this->fields) && method_exists($this, 'fetch'))
1516
				{
1517
					$result = $this->fetch($id);
1518
				}
1519
				else
1520
				{
1521
					$result = $this->fetchCommon($id);
1522
				}
1523
				if ($result >= 0) $result=$this->call_trigger($trigkey, (! empty($fuser) && is_object($fuser)) ? $fuser : $user);   // This may set this->errors
1524
				if ($result < 0) $error++;
1525
			}
1526
1527
			if (! $error)
1528
			{
1529
				if (property_exists($this, $field)) $this->$field = $value;
1530
				$this->db->commit();
1531
				return 1;
1532
			}
1533
			else
1534
			{
1535
				$this->db->rollback();
1536
				return -2;
1537
			}
1538
		}
1539
		else
1540
		{
1541
			$this->error=$this->db->lasterror();
1542
			$this->db->rollback();
1543
			return -1;
1544
		}
1545
	}
1546
1547
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1548
	/**
1549
	 *      Load properties id_previous and id_next by comparing $fieldid with $this->ref
1550
	 *
1551
	 *      @param	string	$filter		Optional filter. Example: " AND (t.field1 = 'aa' OR t.field2 = 'bb')"
1552
	 *	 	@param  string	$fieldid   	Name of field to use for the select MAX and MIN
1553
	 *		@param	int		$nodbprefix	Do not include DB prefix to forge table name
1554
	 *      @return int         		<0 if KO, >0 if OK
1555
	 */
1556
	function load_previous_next_ref($filter, $fieldid, $nodbprefix=0)
1557
	{
1558
        // phpcs:enable
1559
		global $conf, $user;
1560
1561
		if (! $this->table_element)
1562
		{
1563
			dol_print_error('',get_class($this)."::load_previous_next_ref was called on objet with property table_element not defined");
1564
			return -1;
1565
		}
1566
		if ($fieldid == 'none') return 1;
1567
1568
		// Security on socid
1569
		$socid = 0;
1570
		if ($user->societe_id > 0) $socid = $user->societe_id;
1571
1572
		// this->ismultientitymanaged contains
1573
		// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
1574
		$alias = 's';
1575
		if ($this->element == 'societe') $alias = 'te';
1576
1577
		$sql = "SELECT MAX(te.".$fieldid.")";
1578
		$sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1579
		if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1580
			$sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
1581
		}
1582
		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ", ".MAIN_DB_PREFIX."societe as s";	// If we need to link to societe to limit select to entity
1583
		else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe as s";	// If we need to link to societe to limit select to socid
0 ignored issues
show
Bug Best Practice introduced by
The property restrictiononfksoc does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1584
		else if ($this->restrictiononfksoc == 2 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON te.fk_soc = s.rowid";	// If we need to link to societe to limit select to socid
1585
		if ($this->restrictiononfksoc && !$user->rights->societe->client->voir && !$socid)  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ".$alias.".rowid = sc.fk_soc";
1586
		$sql.= " WHERE te.".$fieldid." < '".$this->db->escape($this->ref)."'";  // ->ref must always be defined (set to id if field does not exists)
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1587
		if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1588
		if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1589
		if (! empty($filter))
1590
		{
1591
			if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND ";   // For backward compatibility
1592
			$sql.=$filter;
1593
		}
1594
		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ' AND te.fk_soc = s.rowid';			// If we need to link to societe to limit select to entity
1595
		else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ' AND te.fk_soc = s.rowid';			// If we need to link to societe to limit select to socid
1596
		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1597
			if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1598
				if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1599
					$sql.= " AND te.entity IS NOT NULL"; // Show all users
1600
				} else {
1601
					$sql.= " AND ug.fk_user = te.rowid";
1602
					$sql.= " AND ug.entity IN (".getEntity($this->element).")";
1603
				}
1604
			} else {
1605
				$sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1606
			}
1607
		}
1608
		if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1609
		if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1610
		if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1611
		//print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1612
1613
		$result = $this->db->query($sql);
1614
		if (! $result)
1615
		{
1616
			$this->error=$this->db->lasterror();
1617
			return -1;
1618
		}
1619
		$row = $this->db->fetch_row($result);
1620
		$this->ref_previous = $row[0];
1621
1622
1623
		$sql = "SELECT MIN(te.".$fieldid.")";
1624
		$sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1625
		if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1626
			$sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
1627
		}
1628
		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ", ".MAIN_DB_PREFIX."societe as s";	// If we need to link to societe to limit select to entity
1629
		else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe as s";	// If we need to link to societe to limit select to socid
1630
		else if ($this->restrictiononfksoc == 2 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON te.fk_soc = s.rowid";	// If we need to link to societe to limit select to socid
1631
		if ($this->restrictiononfksoc && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ".$alias.".rowid = sc.fk_soc";
1632
		$sql.= " WHERE te.".$fieldid." > '".$this->db->escape($this->ref)."'";  // ->ref must always be defined (set to id if field does not exists)
1633
		if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1634
		if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1635
		if (! empty($filter))
1636
		{
1637
			if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND ";   // For backward compatibility
1638
			$sql.=$filter;
1639
		}
1640
		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ' AND te.fk_soc = s.rowid';			// If we need to link to societe to limit select to entity
1641
		else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ' AND te.fk_soc = s.rowid';			// If we need to link to societe to limit select to socid
1642
		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1643
			if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1644
				if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1645
					$sql.= " AND te.entity IS NOT NULL"; // Show all users
1646
				} else {
1647
					$sql.= " AND ug.fk_user = te.rowid";
1648
					$sql.= " AND ug.entity IN (".getEntity($this->element).")";
1649
				}
1650
			} else {
1651
				$sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1652
			}
1653
		}
1654
		if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1655
		if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1656
		if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1657
		//print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1658
		// Rem: Bug in some mysql version: SELECT MIN(rowid) FROM llx_socpeople WHERE rowid > 1 when one row in database with rowid=1, returns 1 instead of null
1659
1660
		$result = $this->db->query($sql);
1661
		if (! $result)
1662
		{
1663
			$this->error=$this->db->lasterror();
1664
			return -2;
1665
		}
1666
		$row = $this->db->fetch_row($result);
1667
		$this->ref_next = $row[0];
1668
1669
		return 1;
1670
	}
1671
1672
1673
	/**
1674
	 *      Return list of id of contacts of object
1675
	 *
1676
	 *      @param	string	$source     Source of contact: external (llx_socpeople) or internal (llx_user) or thirdparty (llx_societe)
1677
	 *      @return array				Array of id of contacts (if source=external or internal)
1678
	 * 									Array of id of third parties with at least one contact on object (if source=thirdparty)
1679
	 */
1680
	function getListContactId($source='external')
1681
	{
1682
		$contactAlreadySelected = array();
1683
		$tab = $this->liste_contact(-1,$source);
1684
		$num=count($tab);
1685
		$i = 0;
1686
		while ($i < $num)
1687
		{
1688
			if ($source == 'thirdparty') $contactAlreadySelected[$i] = $tab[$i]['socid'];
1689
			else  $contactAlreadySelected[$i] = $tab[$i]['id'];
1690
			$i++;
1691
		}
1692
		return $contactAlreadySelected;
1693
	}
1694
1695
1696
	/**
1697
	 *	Link element with a project
1698
	 *
1699
	 *	@param     	int		$projectid		Project id to link element to
1700
	 *	@return		int						<0 if KO, >0 if OK
1701
	 */
1702
	function setProject($projectid)
1703
	{
1704
		if (! $this->table_element)
1705
		{
1706
			dol_syslog(get_class($this)."::setProject was called on objet with property table_element not defined",LOG_ERR);
1707
			return -1;
1708
		}
1709
1710
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1711
		if ($this->table_element == 'actioncomm')
1712
		{
1713
			if ($projectid) $sql.= ' SET fk_project = '.$projectid;
1714
			else $sql.= ' SET fk_project = NULL';
1715
			$sql.= ' WHERE id = '.$this->id;
1716
		}
1717
		else
1718
		{
1719
			if ($projectid) $sql.= ' SET fk_projet = '.$projectid;
1720
			else $sql.= ' SET fk_projet = NULL';
1721
			$sql.= ' WHERE rowid = '.$this->id;
1722
		}
1723
1724
		dol_syslog(get_class($this)."::setProject", LOG_DEBUG);
1725
		if ($this->db->query($sql))
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1726
		{
1727
			$this->fk_project = $projectid;
1728
			return 1;
1729
		}
1730
		else
1731
		{
1732
			dol_print_error($this->db);
1733
			return -1;
1734
		}
1735
	}
1736
1737
	/**
1738
	 *  Change the payments methods
1739
	 *
1740
	 *  @param		int		$id		Id of new payment method
1741
	 *  @return		int				>0 if OK, <0 if KO
1742
	 */
1743
	function setPaymentMethods($id)
1744
	{
1745
		dol_syslog(get_class($this).'::setPaymentMethods('.$id.')');
1746
		if ($this->statut >= 0 || $this->element == 'societe')
1747
		{
1748
			// TODO uniformize field name
1749
			$fieldname = 'fk_mode_reglement';
1750
			if ($this->element == 'societe') $fieldname = 'mode_reglement';
1751
			if (get_class($this) == 'Fournisseur') $fieldname = 'mode_reglement_supplier';
1752
1753
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1754
			$sql .= ' SET '.$fieldname.' = '.$id;
1755
			$sql .= ' WHERE rowid='.$this->id;
1756
1757
			if ($this->db->query($sql))
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1758
			{
1759
				$this->mode_reglement_id = $id;
1760
				// for supplier
1761
				if (get_class($this) == 'Fournisseur') $this->mode_reglement_supplier_id = $id;
1762
				return 1;
1763
			}
1764
			else
1765
			{
1766
				dol_syslog(get_class($this).'::setPaymentMethods Erreur '.$sql.' - '.$this->db->error());
1767
				$this->error=$this->db->error();
1768
				return -1;
1769
			}
1770
		}
1771
		else
1772
		{
1773
			dol_syslog(get_class($this).'::setPaymentMethods, status of the object is incompatible');
1774
			$this->error='Status of the object is incompatible '.$this->statut;
1775
			return -2;
1776
		}
1777
	}
1778
1779
	/**
1780
	 *  Change the multicurrency code
1781
	 *
1782
	 *  @param		string	$code	multicurrency code
1783
	 *  @return		int				>0 if OK, <0 if KO
1784
	 */
1785
	function setMulticurrencyCode($code)
1786
	{
1787
		dol_syslog(get_class($this).'::setMulticurrencyCode('.$id.')');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id seems to be never defined.
Loading history...
1788
		if ($this->statut >= 0 || $this->element == 'societe')
1789
		{
1790
			$fieldname = 'multicurrency_code';
1791
1792
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1793
			$sql .= ' SET '.$fieldname." = '".$this->db->escape($code)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1794
			$sql .= ' WHERE rowid='.$this->id;
1795
1796
			if ($this->db->query($sql))
1797
			{
1798
				$this->multicurrency_code = $code;
1799
1800
				list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code);
0 ignored issues
show
Bug introduced by
The type Alixar\Base\MultiCurrency was not found. Did you mean MultiCurrency? If so, make sure to prefix the type with \.
Loading history...
1801
				if ($rate) $this->setMulticurrencyRate($rate,2);
1802
1803
				return 1;
1804
			}
1805
			else
1806
			{
1807
				dol_syslog(get_class($this).'::setMulticurrencyCode Erreur '.$sql.' - '.$this->db->error());
1808
				$this->error=$this->db->error();
1809
				return -1;
1810
			}
1811
		}
1812
		else
1813
		{
1814
			dol_syslog(get_class($this).'::setMulticurrencyCode, status of the object is incompatible');
1815
			$this->error='Status of the object is incompatible '.$this->statut;
1816
			return -2;
1817
		}
1818
	}
1819
1820
	/**
1821
	 *  Change the multicurrency rate
1822
	 *
1823
	 *  @param		double	$rate	multicurrency rate
1824
	 *  @param		int		$mode	mode 1 : amounts in company currency will be recalculated, mode 2 : amounts in foreign currency
1825
	 *  @return		int				>0 if OK, <0 if KO
1826
	 */
1827
	function setMulticurrencyRate($rate, $mode=1)
1828
	{
1829
		dol_syslog(get_class($this).'::setMulticurrencyRate('.$id.')');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id seems to be never defined.
Loading history...
1830
		if ($this->statut >= 0 || $this->element == 'societe')
1831
		{
1832
			$fieldname = 'multicurrency_tx';
1833
1834
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1835
			$sql .= ' SET '.$fieldname.' = '.$rate;
1836
			$sql .= ' WHERE rowid='.$this->id;
1837
1838
			if ($this->db->query($sql))
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1839
			{
1840
				$this->multicurrency_tx = $rate;
1841
1842
				// Update line price
1843
				if (!empty($this->lines))
1844
				{
1845
					foreach ($this->lines as &$line)
1846
					{
1847
						if($mode == 1) {
1848
							$line->subprice = 0;
1849
						}
1850
1851
						switch ($this->element) {
1852
							case 'propal':
1853
								$this->updateline(
0 ignored issues
show
Bug introduced by
The method updateline() does not exist on Alixar\Base\CommonObject. Did you maybe mean updateLineUp()? ( Ignorable by Annotation )

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

1853
								$this->/** @scrutinizer ignore-call */ updateline(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1854
									$line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1855
									($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1856
									$line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start,
1857
									$line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1858
								);
1859
								break;
1860
							case 'commande':
1861
								$this->updateline(
1862
									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1863
									$line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->date_start, $line->date_end,
1864
									$line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1865
									$line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1866
								);
1867
								break;
1868
							case 'facture':
1869
								$this->updateline(
1870
									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1871
									$line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits,
1872
									$line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1873
									$line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice
1874
								);
1875
								break;
1876
							case 'supplier_proposal':
1877
								$this->updateline(
1878
									$line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1879
									($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1880
									$line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->array_options,
1881
									$line->ref_fourn, $line->multicurrency_subprice
1882
								);
1883
								break;
1884
							case 'order_supplier':
1885
								$this->updateline(
1886
									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1887
									$line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, false,
1888
									$line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1889
								);
1890
								break;
1891
							case 'invoice_supplier':
1892
								$this->updateline(
1893
									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->tva_tx, $line->localtax1_tx,
1894
									$line->localtax2_tx, $line->qty, 0, 'HT', $line->info_bits, $line->product_type, $line->remise_percent, false,
1895
									$line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1896
								);
1897
								break;
1898
							default:
1899
								dol_syslog(get_class($this).'::setMulticurrencyRate no updateline defined', LOG_DEBUG);
1900
								break;
1901
						}
1902
					}
1903
				}
1904
1905
				return 1;
1906
			}
1907
			else
1908
			{
1909
				dol_syslog(get_class($this).'::setMulticurrencyRate Erreur '.$sql.' - '.$this->db->error());
1910
				$this->error=$this->db->error();
1911
				return -1;
1912
			}
1913
		}
1914
		else
1915
		{
1916
			dol_syslog(get_class($this).'::setMulticurrencyRate, status of the object is incompatible');
1917
			$this->error='Status of the object is incompatible '.$this->statut;
1918
			return -2;
1919
		}
1920
	}
1921
1922
	/**
1923
	 *  Change the payments terms
1924
	 *
1925
	 *  @param		int		$id		Id of new payment terms
1926
	 *  @return		int				>0 if OK, <0 if KO
1927
	 */
1928
	function setPaymentTerms($id)
1929
	{
1930
		dol_syslog(get_class($this).'::setPaymentTerms('.$id.')');
1931
		if ($this->statut >= 0 || $this->element == 'societe')
1932
		{
1933
			// TODO uniformize field name
1934
			$fieldname = 'fk_cond_reglement';
1935
			if ($this->element == 'societe') $fieldname = 'cond_reglement';
1936
			if (get_class($this) == 'Fournisseur') $fieldname = 'cond_reglement_supplier';
1937
1938
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1939
			$sql .= ' SET '.$fieldname.' = '.$id;
1940
			$sql .= ' WHERE rowid='.$this->id;
1941
1942
			if ($this->db->query($sql))
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1943
			{
1944
				$this->cond_reglement_id = $id;
1945
				// for supplier
1946
				if (get_class($this) == 'Fournisseur') $this->cond_reglement_supplier_id = $id;
1947
				$this->cond_reglement = $id;	// for compatibility
0 ignored issues
show
Deprecated Code introduced by
The property Alixar\Base\CommonObject::$cond_reglement has been deprecated: Kept for compatibility ( Ignorable by Annotation )

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

1947
				/** @scrutinizer ignore-deprecated */ $this->cond_reglement = $id;	// for compatibility

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1948
				return 1;
1949
			}
1950
			else
1951
			{
1952
				dol_syslog(get_class($this).'::setPaymentTerms Erreur '.$sql.' - '.$this->db->error());
1953
				$this->error=$this->db->error();
1954
				return -1;
1955
			}
1956
		}
1957
		else
1958
		{
1959
			dol_syslog(get_class($this).'::setPaymentTerms, status of the object is incompatible');
1960
			$this->error='Status of the object is incompatible '.$this->statut;
1961
			return -2;
1962
		}
1963
	}
1964
1965
	/**
1966
	 *	Define delivery address
1967
	 *  @deprecated
1968
	 *
1969
	 *	@param      int		$id		Address id
1970
	 *	@return     int				<0 si ko, >0 si ok
1971
	 */
1972
	function setDeliveryAddress($id)
1973
	{
1974
		$fieldname = 'fk_delivery_address';
1975
		if ($this->element == 'delivery' || $this->element == 'shipping') $fieldname = 'fk_address';
1976
1977
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET ".$fieldname." = ".$id;
1978
		$sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
1979
1980
		if ($this->db->query($sql))
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
1981
		{
1982
			$this->fk_delivery_address = $id;
1983
			return 1;
1984
		}
1985
		else
1986
		{
1987
			$this->error=$this->db->error();
1988
			dol_syslog(get_class($this).'::setDeliveryAddress Erreur '.$sql.' - '.$this->error);
1989
			return -1;
1990
		}
1991
	}
1992
1993
1994
	/**
1995
	 *  Change the shipping method
1996
	 *
1997
	 *  @param      int     $shipping_method_id     Id of shipping method
1998
     *  @param      bool    $notrigger              false=launch triggers after, true=disable triggers
1999
     *  @param      User	$userused               Object user
2000
	 *
2001
	 *  @return     int              1 if OK, 0 if KO
2002
	 */
2003
	function setShippingMethod($shipping_method_id, $notrigger=false, $userused=null)
2004
	{
2005
        global $user;
2006
2007
        if (empty($userused)) $userused=$user;
2008
2009
        $error = 0;
2010
2011
		if (! $this->table_element) {
2012
			dol_syslog(get_class($this)."::setShippingMethod was called on objet with property table_element not defined",LOG_ERR);
2013
			return -1;
2014
		}
2015
2016
        $this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2017
2018
		if ($shipping_method_id<0) $shipping_method_id='NULL';
2019
		dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')');
2020
2021
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2022
		$sql.= " SET fk_shipping_method = ".$shipping_method_id;
2023
		$sql.= " WHERE rowid=".$this->id;
2024
        $resql = $this->db->query($sql);
2025
		if (! $resql) {
2026
			dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG);
2027
			$this->error = $this->db->lasterror();
2028
			$error++;
2029
        } else {
2030
            if (!$notrigger)
2031
            {
2032
                // Call trigger
2033
                $this->context=array('shippingmethodupdate'=>1);
2034
                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2035
                if ($result < 0) $error++;
2036
                // End call trigger
2037
            }
2038
        }
2039
        if ($error)
2040
        {
2041
            $this->db->rollback();
2042
            return -1;
2043
        } else {
2044
            $this->shipping_method_id = ($shipping_method_id=='NULL')?null:$shipping_method_id;
0 ignored issues
show
Documentation Bug introduced by
It seems like $shipping_method_id == '...l : $shipping_method_id can also be of type string. However, the property $shipping_method_id is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
2045
            $this->db->commit();
2046
            return 1;
2047
        }
2048
	}
2049
2050
2051
	/**
2052
	 *  Change the warehouse
2053
	 *
2054
	 *  @param      int     $warehouse_id     Id of warehouse
2055
	 *  @return     int              1 if OK, 0 if KO
2056
	 */
2057
	function setWarehouse($warehouse_id)
2058
	{
2059
		if (! $this->table_element) {
2060
			dol_syslog(get_class($this)."::setWarehouse was called on objet with property table_element not defined",LOG_ERR);
2061
			return -1;
2062
		}
2063
		if ($warehouse_id<0) $warehouse_id='NULL';
2064
		dol_syslog(get_class($this).'::setWarehouse('.$warehouse_id.')');
2065
2066
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2067
		$sql.= " SET fk_warehouse = ".$warehouse_id;
2068
		$sql.= " WHERE rowid=".$this->id;
2069
2070
		if ($this->db->query($sql)) {
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2071
			$this->warehouse_id = ($warehouse_id=='NULL')?null:$warehouse_id;
2072
			return 1;
2073
		} else {
2074
			dol_syslog(get_class($this).'::setWarehouse Error ', LOG_DEBUG);
2075
			$this->error=$this->db->error();
2076
			return 0;
2077
		}
2078
	}
2079
2080
2081
	/**
2082
	 *		Set last model used by doc generator
2083
	 *
2084
	 *		@param		User	$user		User object that make change
2085
	 *		@param		string	$modelpdf	Modele name
2086
	 *		@return		int					<0 if KO, >0 if OK
2087
	 */
2088
	function setDocModel($user, $modelpdf)
2089
	{
2090
		if (! $this->table_element)
2091
		{
2092
			dol_syslog(get_class($this)."::setDocModel was called on objet with property table_element not defined",LOG_ERR);
2093
			return -1;
2094
		}
2095
2096
		$newmodelpdf=dol_trunc($modelpdf,255);
2097
2098
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2099
		$sql.= " SET model_pdf = '".$this->db->escape($newmodelpdf)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2100
		$sql.= " WHERE rowid = ".$this->id;
2101
		// if ($this->element == 'facture') $sql.= " AND fk_statut < 2";
2102
		// if ($this->element == 'propal')  $sql.= " AND fk_statut = 0";
2103
2104
		dol_syslog(get_class($this)."::setDocModel", LOG_DEBUG);
2105
		$resql=$this->db->query($sql);
2106
		if ($resql)
2107
		{
2108
			$this->modelpdf=$modelpdf;
2109
			return 1;
2110
		}
2111
		else
2112
		{
2113
			dol_print_error($this->db);
2114
			return 0;
2115
		}
2116
	}
2117
2118
2119
	/**
2120
	 *  Change the bank account
2121
	 *
2122
	 *  @param		int		$fk_account		Id of bank account
2123
	 *  @param      bool    $notrigger      false=launch triggers after, true=disable triggers
2124
	 *  @param      User	$userused		Object user
2125
	 *  @return		int				1 if OK, 0 if KO
2126
	 */
2127
	function setBankAccount($fk_account, $notrigger=false, $userused=null)
2128
	{
2129
        global $user;
2130
2131
        if (empty($userused)) $userused=$user;
2132
2133
        $error = 0;
2134
2135
		if (! $this->table_element) {
2136
			dol_syslog(get_class($this)."::setBankAccount was called on objet with property table_element not defined",LOG_ERR);
2137
			return -1;
2138
		}
2139
        $this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2140
2141
		if ($fk_account<0) $fk_account='NULL';
2142
		dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')');
2143
2144
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2145
		$sql.= " SET fk_account = ".$fk_account;
2146
		$sql.= " WHERE rowid=".$this->id;
2147
2148
        $resql = $this->db->query($sql);
2149
        if (! $resql)
2150
        {
2151
            dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error());
2152
            $this->error = $this->db->lasterror();
2153
            $error++;
2154
        }
2155
        else
2156
        {
2157
            if (!$notrigger)
2158
            {
2159
                // Call trigger
2160
                $this->context=array('bankaccountupdate'=>1);
2161
                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2162
                if ($result < 0) $error++;
2163
                // End call trigger
2164
            }
2165
        }
2166
        if ($error)
2167
        {
2168
            $this->db->rollback();
2169
            return -1;
2170
        }
2171
        else
2172
        {
2173
            $this->fk_account = ($fk_account=='NULL')?null:$fk_account;
0 ignored issues
show
Documentation Bug introduced by
It seems like $fk_account == 'NULL' ? null : $fk_account can also be of type string. However, the property $fk_account is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
2174
            $this->db->commit();
2175
            return 1;
2176
        }
2177
    }
2178
2179
2180
	// TODO: Move line related operations to CommonObjectLine?
2181
2182
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2183
	/**
2184
	 *  Save a new position (field rang) for details lines.
2185
	 *  You can choose to set position for lines with already a position or lines without any position defined.
2186
	 *
2187
	 * 	@param		boolean		$renum			   True to renum all already ordered lines, false to renum only not already ordered lines.
2188
	 * 	@param		string		$rowidorder		   ASC or DESC
2189
	 * 	@param		boolean		$fk_parent_line    Table with fk_parent_line field or not
2190
	 * 	@return		int                            <0 if KO, >0 if OK
2191
	 */
2192
	function line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
2193
	{
2194
        // phpcs:enable
2195
		if (! $this->table_element_line)
2196
		{
2197
			dol_syslog(get_class($this)."::line_order was called on objet with property table_element_line not defined",LOG_ERR);
2198
			return -1;
2199
		}
2200
		if (! $this->fk_element)
2201
		{
2202
			dol_syslog(get_class($this)."::line_order was called on objet with property fk_element not defined",LOG_ERR);
2203
			return -1;
2204
		}
2205
2206
		// Count number of lines to reorder (according to choice $renum)
2207
		$nl=0;
2208
		$sql = 'SELECT count(rowid) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2209
		$sql.= ' WHERE '.$this->fk_element.'='.$this->id;
2210
		if (! $renum) $sql.= ' AND rang = 0';
2211
		if ($renum) $sql.= ' AND rang <> 0';
2212
2213
		dol_syslog(get_class($this)."::line_order", LOG_DEBUG);
2214
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2215
		if ($resql)
2216
		{
2217
			$row = $this->db->fetch_row($resql);
2218
			$nl = $row[0];
2219
		}
2220
		else dol_print_error($this->db);
2221
		if ($nl > 0)
2222
		{
2223
			// The goal of this part is to reorder all lines, with all children lines sharing the same
2224
			// counter that parents.
2225
			$rows=array();
2226
2227
			// We first search all lines that are parent lines (for multilevel details lines)
2228
			$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2229
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2230
			if ($fk_parent_line) $sql.= ' AND fk_parent_line IS NULL';
2231
			$sql.= ' ORDER BY rang ASC, rowid '.$rowidorder;
2232
2233
			dol_syslog(get_class($this)."::line_order search all parent lines", LOG_DEBUG);
2234
			$resql = $this->db->query($sql);
2235
			if ($resql)
2236
			{
2237
				$i=0;
2238
				$num = $this->db->num_rows($resql);
2239
				while ($i < $num)
2240
				{
2241
					$row = $this->db->fetch_row($resql);
2242
					$rows[] = $row[0];	// Add parent line into array rows
2243
					$childrens = $this->getChildrenOfLine($row[0]);
2244
					if (! empty($childrens))
2245
					{
2246
						foreach($childrens as $child)
2247
						{
2248
							array_push($rows, $child);
2249
						}
2250
					}
2251
					$i++;
2252
				}
2253
2254
				// Now we set a new number for each lines (parent and children with children included into parent tree)
2255
				if (! empty($rows))
2256
				{
2257
					foreach($rows as $key => $row)
2258
					{
2259
						$this->updateRangOfLine($row, ($key+1));
2260
					}
2261
				}
2262
			}
2263
			else
2264
			{
2265
				dol_print_error($this->db);
2266
			}
2267
		}
2268
		return 1;
2269
	}
2270
2271
	/**
2272
	 * 	Get children of line
2273
	 *
2274
	 * 	@param	int		$id		Id of parent line
2275
	 * 	@return	array			Array with list of children lines id
2276
	 */
2277
	function getChildrenOfLine($id)
2278
	{
2279
		$rows=array();
2280
2281
		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2282
		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2283
		$sql.= ' AND fk_parent_line = '.$id;
2284
		$sql.= ' ORDER BY rang ASC';
2285
2286
		dol_syslog(get_class($this)."::getChildrenOfLine search children lines for line ".$id."", LOG_DEBUG);
2287
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2288
		if ($resql)
2289
		{
2290
			$i=0;
2291
			$num = $this->db->num_rows($resql);
2292
			while ($i < $num)
2293
			{
2294
				$row = $this->db->fetch_row($resql);
2295
				$rows[$i] = $row[0];
2296
				$i++;
2297
			}
2298
		}
2299
2300
		return $rows;
2301
	}
2302
2303
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2304
	/**
2305
	 * 	Update a line to have a lower rank
2306
	 *
2307
	 * 	@param 	int			$rowid				Id of line
2308
	 * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2309
	 * 	@return	void
2310
	 */
2311
	function line_up($rowid, $fk_parent_line=true)
2312
	{
2313
        // phpcs:enable
2314
		$this->line_order(false, 'ASC', $fk_parent_line);
2315
2316
		// Get rang of line
2317
		$rang = $this->getRangOfLine($rowid);
2318
2319
		// Update position of line
2320
		$this->updateLineUp($rowid, $rang);
2321
	}
2322
2323
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2324
	/**
2325
	 * 	Update a line to have a higher rank
2326
	 *
2327
	 * 	@param	int			$rowid				Id of line
2328
	 * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2329
	 * 	@return	void
2330
	 */
2331
	function line_down($rowid, $fk_parent_line=true)
2332
	{
2333
        // phpcs:enable
2334
		$this->line_order(false, 'ASC', $fk_parent_line);
2335
2336
		// Get rang of line
2337
		$rang = $this->getRangOfLine($rowid);
2338
2339
		// Get max value for rang
2340
		$max = $this->line_max();
2341
2342
		// Update position of line
2343
		$this->updateLineDown($rowid, $rang, $max);
2344
	}
2345
2346
	/**
2347
	 * 	Update position of line (rang)
2348
	 *
2349
	 * 	@param	int		$rowid		Id of line
2350
	 * 	@param	int		$rang		Position
2351
	 * 	@return	void
2352
	 */
2353
	function updateRangOfLine($rowid,$rang)
2354
	{
2355
		$fieldposition = 'rang';
2356
		if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2357
2358
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2359
		$sql.= ' WHERE rowid = '.$rowid;
2360
2361
		dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
2362
		if (! $this->db->query($sql))
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2363
		{
2364
			dol_print_error($this->db);
2365
		}
2366
	}
2367
2368
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2369
	/**
2370
	 * 	Update position of line with ajax (rang)
2371
	 *
2372
	 * 	@param	array	$rows	Array of rows
2373
	 * 	@return	void
2374
	 */
2375
	function line_ajaxorder($rows)
2376
	{
2377
        // phpcs:enable
2378
		$num = count($rows);
2379
		for ($i = 0 ; $i < $num ; $i++)
2380
		{
2381
			$this->updateRangOfLine($rows[$i], ($i+1));
2382
		}
2383
	}
2384
2385
	/**
2386
	 * 	Update position of line up (rang)
2387
	 *
2388
	 * 	@param	int		$rowid		Id of line
2389
	 * 	@param	int		$rang		Position
2390
	 * 	@return	void
2391
	 */
2392
	function updateLineUp($rowid,$rang)
2393
	{
2394
		if ($rang > 1)
2395
		{
2396
			$fieldposition = 'rang';
2397
			if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2398
2399
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang ;
2400
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2401
			$sql.= ' AND rang = '.($rang - 1);
2402
			if ($this->db->query($sql) )
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2403
			{
2404
				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang - 1);
2405
				$sql.= ' WHERE rowid = '.$rowid;
2406
				if (! $this->db->query($sql) )
2407
				{
2408
					dol_print_error($this->db);
2409
				}
2410
			}
2411
			else
2412
			{
2413
				dol_print_error($this->db);
2414
			}
2415
		}
2416
	}
2417
2418
	/**
2419
	 * 	Update position of line down (rang)
2420
	 *
2421
	 * 	@param	int		$rowid		Id of line
2422
	 * 	@param	int		$rang		Position
2423
	 * 	@param	int		$max		Max
2424
	 * 	@return	void
2425
	 */
2426
	function updateLineDown($rowid,$rang,$max)
2427
	{
2428
		if ($rang < $max)
2429
		{
2430
			$fieldposition = 'rang';
2431
			if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2432
2433
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2434
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2435
			$sql.= ' AND rang = '.($rang+1);
2436
			if ($this->db->query($sql) )
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2437
			{
2438
				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang+1);
2439
				$sql.= ' WHERE rowid = '.$rowid;
2440
				if (! $this->db->query($sql) )
2441
				{
2442
					dol_print_error($this->db);
2443
				}
2444
			}
2445
			else
2446
			{
2447
				dol_print_error($this->db);
2448
			}
2449
		}
2450
	}
2451
2452
	/**
2453
	 * 	Get position of line (rang)
2454
	 *
2455
	 * 	@param		int		$rowid		Id of line
2456
	 *  @return		int     			Value of rang in table of lines
2457
	 */
2458
	function getRangOfLine($rowid)
2459
	{
2460
		$sql = 'SELECT rang FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2461
		$sql.= ' WHERE rowid ='.$rowid;
2462
2463
		dol_syslog(get_class($this)."::getRangOfLine", LOG_DEBUG);
2464
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2465
		if ($resql)
2466
		{
2467
			$row = $this->db->fetch_row($resql);
2468
			return $row[0];
2469
		}
2470
	}
2471
2472
	/**
2473
	 * 	Get rowid of the line relative to its position
2474
	 *
2475
	 * 	@param		int		$rang		Rang value
2476
	 *  @return     int     			Rowid of the line
2477
	 */
2478
	function getIdOfLine($rang)
2479
	{
2480
		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2481
		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2482
		$sql.= ' AND rang = '.$rang;
2483
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2484
		if ($resql)
2485
		{
2486
			$row = $this->db->fetch_row($resql);
2487
			return $row[0];
2488
		}
2489
	}
2490
2491
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2492
	/**
2493
	 * 	Get max value used for position of line (rang)
2494
	 *
2495
	 * 	@param		int		$fk_parent_line		Parent line id
2496
	 *  @return     int  			   			Max value of rang in table of lines
2497
	 */
2498
	function line_max($fk_parent_line=0)
2499
	{
2500
        // phpcs:enable
2501
		// Search the last rang with fk_parent_line
2502
		if ($fk_parent_line)
2503
		{
2504
			$sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2505
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2506
			$sql.= ' AND fk_parent_line = '.$fk_parent_line;
2507
2508
			dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2509
			$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2510
			if ($resql)
2511
			{
2512
				$row = $this->db->fetch_row($resql);
2513
				if (! empty($row[0]))
2514
				{
2515
					return $row[0];
2516
				}
2517
				else
2518
				{
2519
					return $this->getRangOfLine($fk_parent_line);
2520
				}
2521
			}
2522
		}
2523
		// If not, search the last rang of element
2524
		else
2525
		{
2526
			$sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2527
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2528
2529
			dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2530
			$resql = $this->db->query($sql);
2531
			if ($resql)
2532
			{
2533
				$row = $this->db->fetch_row($resql);
2534
				return $row[0];
2535
			}
2536
		}
2537
	}
2538
2539
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2540
	/**
2541
	 *  Update external ref of element
2542
	 *
2543
	 *  @param      string		$ref_ext	Update field ref_ext
2544
	 *  @return     int      		   		<0 if KO, >0 if OK
2545
	 */
2546
	function update_ref_ext($ref_ext)
2547
	{
2548
        // phpcs:enable
2549
		if (! $this->table_element)
2550
		{
2551
			dol_syslog(get_class($this)."::update_ref_ext was called on objet with property table_element not defined", LOG_ERR);
2552
			return -1;
2553
		}
2554
2555
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2556
		$sql.= " SET ref_ext = '".$this->db->escape($ref_ext)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2557
		$sql.= " WHERE ".(isset($this->table_rowid)?$this->table_rowid:'rowid')." = ". $this->id;
2558
2559
		dol_syslog(get_class($this)."::update_ref_ext", LOG_DEBUG);
2560
		if ($this->db->query($sql))
2561
		{
2562
			$this->ref_ext = $ref_ext;
2563
			return 1;
2564
		}
2565
		else
2566
		{
2567
			$this->error=$this->db->error();
2568
			return -1;
2569
		}
2570
	}
2571
2572
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2573
	/**
2574
	 *  Update note of element
2575
	 *
2576
	 *  @param      string		$note		New value for note
2577
	 *  @param		string		$suffix		'', '_public' or '_private'
2578
	 *  @return     int      		   		<0 if KO, >0 if OK
2579
	 */
2580
	function update_note($note, $suffix='')
2581
	{
2582
        // phpcs:enable
2583
		global $user;
2584
2585
		if (! $this->table_element)
2586
		{
2587
			$this->error='update_note was called on objet with property table_element not defined';
2588
			dol_syslog(get_class($this)."::update_note was called on objet with property table_element not defined", LOG_ERR);
2589
			return -1;
2590
		}
2591
		if (! in_array($suffix,array('','_public','_private')))
2592
		{
2593
			$this->error='update_note Parameter suffix must be empty, \'_private\' or \'_public\'';
2594
			dol_syslog(get_class($this)."::update_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR);
2595
			return -2;
2596
		}
2597
		// Special cas
2598
		//var_dump($this->table_element);exit;
2599
		if ($this->table_element == 'product') $suffix='';
2600
2601
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2602
		$sql.= " SET note".$suffix." = ".(!empty($note)?("'".$this->db->escape($note)."'"):"NULL");
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2603
		$sql.= " ,".(in_array($this->table_element, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))?"fk_user_mod":"fk_user_modif")." = ".$user->id;
2604
		$sql.= " WHERE rowid =". $this->id;
2605
2606
		dol_syslog(get_class($this)."::update_note", LOG_DEBUG);
2607
		if ($this->db->query($sql))
2608
		{
2609
			if ($suffix == '_public') $this->note_public = $note;
2610
			else if ($suffix == '_private') $this->note_private = $note;
2611
			else
2612
			{
2613
				$this->note = $note;      // deprecated
2614
				$this->note_private = $note;
2615
			}
2616
			return 1;
2617
		}
2618
		else
2619
		{
2620
			$this->error=$this->db->lasterror();
2621
			return -1;
2622
		}
2623
	}
2624
2625
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2626
	/**
2627
	 * 	Update public note (kept for backward compatibility)
2628
	 *
2629
	 * @param      string		$note		New value for note
2630
	 * @return     int      		   		<0 if KO, >0 if OK
2631
	 * @deprecated
2632
	 * @see update_note()
2633
	 */
2634
	function update_note_public($note)
2635
	{
2636
        // phpcs:enable
2637
		return $this->update_note($note,'_public');
2638
	}
2639
2640
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2641
	/**
2642
	 *	Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
2643
	 *  Must be called at end of methods addline or updateline.
2644
	 *
2645
	 *	@param	int		$exclspec          	>0 = Exclude special product (product_type=9)
2646
	 *  @param  string	$roundingadjust    	'none'=Do nothing, 'auto'=Use default method (MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND if defined, or '0'), '0'=Force mode total of rounding, '1'=Force mode rounding of total
2647
	 *  @param	int		$nodatabaseupdate	1=Do not update database. Update only properties of object.
2648
	 *  @param	Societe	$seller				If roundingadjust is '0' or '1' or maybe 'auto', it means we recalculate total for lines before calculating total for object and for this, we need seller object.
2649
	 *	@return	int    			           	<0 if KO, >0 if OK
2650
	 */
2651
	function update_price($exclspec=0,$roundingadjust='none',$nodatabaseupdate=0,$seller=null)
2652
	{
2653
        // phpcs:enable
2654
		global $conf, $hookmanager, $action;
2655
2656
		// Some external module want no update price after a trigger because they have another method to calculate the total (ex: with an extrafield)
2657
		$MODULE = "";
2658
		if ($this->element == 'propal')
2659
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_PROPOSAL";
2660
		elseif ($this->element == 'order')
2661
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER";
2662
		elseif ($this->element == 'facture')
2663
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE";
2664
		elseif ($this->element == 'facture_fourn')
2665
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE";
2666
		elseif ($this->element == 'order_supplier')
2667
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER";
2668
		elseif ($this->element == 'supplier_proposal')
2669
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_PROPOSAL";
2670
2671
		if (! empty($MODULE)) {
2672
			if (! empty($conf->global->$MODULE)) {
2673
				$modsactivated = explode(',', $conf->global->$MODULE);
2674
				foreach ($modsactivated as $mod) {
2675
					if ($conf->$mod->enabled)
2676
						return 1; // update was disabled by specific setup
2677
				}
2678
			}
2679
		}
2680
2681
		include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2682
2683
		if ($roundingadjust == '-1') $roundingadjust='auto';	// For backward compatibility
2684
2685
		$forcedroundingmode=$roundingadjust;
2686
		if ($forcedroundingmode == 'auto' && isset($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)) $forcedroundingmode=$conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND;
2687
		elseif ($forcedroundingmode == 'auto') $forcedroundingmode='0';
2688
2689
		$error=0;
2690
2691
		$multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1;
2692
2693
		// Define constants to find lines to sum
2694
		$fieldtva='total_tva';
2695
		$fieldlocaltax1='total_localtax1';
2696
		$fieldlocaltax2='total_localtax2';
2697
		$fieldup='subprice';
2698
		if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier')
2699
		{
2700
			$fieldtva='tva';
2701
			$fieldup='pu_ht';
2702
		}
2703
		if ($this->element == 'expensereport')
2704
		{
2705
			$fieldup='value_unit';
2706
		}
2707
2708
		$sql = 'SELECT rowid, qty, '.$fieldup.' as up, remise_percent, total_ht, '.$fieldtva.' as total_tva, total_ttc, '.$fieldlocaltax1.' as total_localtax1, '.$fieldlocaltax2.' as total_localtax2,';
2709
		$sql.= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type';
2710
			if ($this->table_element_line == 'facturedet') $sql.= ', situation_percent';
2711
			$sql.= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
2712
		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2713
		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2714
		if ($exclspec)
2715
		{
2716
			$product_field='product_type';
2717
			if ($this->table_element_line == 'contratdet') $product_field='';    // contratdet table has no product_type field
2718
			if ($product_field) $sql.= ' AND '.$product_field.' <> 9';
2719
		}
2720
		$sql.= ' ORDER by rowid';	// We want to be sure to always use same order of line to not change lines differently when option MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND is used
2721
2722
		dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2723
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2724
		if ($resql)
2725
		{
2726
			$this->total_ht  = 0;
2727
			$this->total_tva = 0;
2728
			$this->total_localtax1 = 0;
2729
			$this->total_localtax2 = 0;
2730
			$this->total_ttc = 0;
2731
			$total_ht_by_vats  = array();
2732
			$total_tva_by_vats = array();
2733
			$total_ttc_by_vats = array();
2734
			$this->multicurrency_total_ht	= 0;
2735
			$this->multicurrency_total_tva	= 0;
2736
			$this->multicurrency_total_ttc	= 0;
2737
2738
			$num = $this->db->num_rows($resql);
2739
			$i = 0;
2740
			while ($i < $num)
2741
			{
2742
				$obj = $this->db->fetch_object($resql);
2743
2744
				// Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none'
2745
				$parameters=array('fk_element' => $obj->rowid);
2746
				$reshook = $hookmanager->executeHooks('changeRoundingMode', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2747
2748
				if (empty($reshook) && $forcedroundingmode == '0')	// Check if data on line are consistent. This may solve lines that were not consistent because set with $forcedroundingmode='auto'
2749
				{
2750
					$localtax_array=array($obj->localtax1_type,$obj->localtax1_tx,$obj->localtax2_type,$obj->localtax2_tx);
2751
					$tmpcal=calcul_price_total($obj->qty, $obj->up, $obj->remise_percent, $obj->vatrate, $obj->localtax1_tx, $obj->localtax2_tx, 0, 'HT', $obj->info_bits, $obj->product_type, $seller, $localtax_array, (isset($obj->situation_percent) ? $obj->situation_percent : 100), $multicurrency_tx);
2752
					$diff=price2num($tmpcal[1] - $obj->total_tva, 'MT', 1);
2753
					if ($diff)
2754
					{
2755
						$sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".$tmpcal[1].", total_ttc = ".$tmpcal[2]." WHERE rowid = ".$obj->rowid;
2756
						dol_syslog('We found unconsistent data into detailed line (difference of '.$diff.') for line rowid = '.$obj->rowid." (total vat of line calculated=".$tmpcal[1].", database=".$obj->total_tva."). We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix);
2757
								$resqlfix=$this->db->query($sqlfix);
2758
								if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2759
								$obj->total_tva = $tmpcal[1];
2760
								$obj->total_ttc = $tmpcal[2];
2761
						//
2762
					}
2763
				}
2764
2765
				$this->total_ht        += $obj->total_ht;		// The field visible at end of line detail
2766
				$this->total_tva       += $obj->total_tva;
2767
				$this->total_localtax1 += $obj->total_localtax1;
2768
				$this->total_localtax2 += $obj->total_localtax2;
2769
				$this->total_ttc       += $obj->total_ttc;
2770
				$this->multicurrency_total_ht        += $obj->multicurrency_total_ht;		// The field visible at end of line detail
2771
				$this->multicurrency_total_tva       += $obj->multicurrency_total_tva;
2772
				$this->multicurrency_total_ttc       += $obj->multicurrency_total_ttc;
2773
2774
				if (! isset($total_ht_by_vats[$obj->vatrate]))  $total_ht_by_vats[$obj->vatrate]=0;
2775
				if (! isset($total_tva_by_vats[$obj->vatrate])) $total_tva_by_vats[$obj->vatrate]=0;
2776
				if (! isset($total_ttc_by_vats[$obj->vatrate])) $total_ttc_by_vats[$obj->vatrate]=0;
2777
				$total_ht_by_vats[$obj->vatrate]  += $obj->total_ht;
2778
				$total_tva_by_vats[$obj->vatrate] += $obj->total_tva;
2779
				$total_ttc_by_vats[$obj->vatrate] += $obj->total_ttc;
2780
2781
				if ($forcedroundingmode == '1')	// Check if we need adjustement onto line for vat. TODO This works on the company currency but not on multicurrency
2782
				{
2783
					$tmpvat=price2num($total_ht_by_vats[$obj->vatrate] * $obj->vatrate / 100, 'MT', 1);
2784
					$diff=price2num($total_tva_by_vats[$obj->vatrate]-$tmpvat, 'MT', 1);
2785
					//print 'Line '.$i.' rowid='.$obj->rowid.' vat_rate='.$obj->vatrate.' total_ht='.$obj->total_ht.' total_tva='.$obj->total_tva.' total_ttc='.$obj->total_ttc.' total_ht_by_vats='.$total_ht_by_vats[$obj->vatrate].' total_tva_by_vats='.$total_tva_by_vats[$obj->vatrate].' (new calculation = '.$tmpvat.') total_ttc_by_vats='.$total_ttc_by_vats[$obj->vatrate].($diff?" => DIFF":"")."<br>\n";
2786
					if ($diff)
2787
					{
2788
						if (abs($diff) > 0.1) { dol_syslog('A rounding difference was detected into TOTAL but is too high to be corrected', LOG_WARNING); exit; }
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
2789
						$sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".($obj->total_tva - $diff).", total_ttc = ".($obj->total_ttc - $diff)." WHERE rowid = ".$obj->rowid;
2790
						dol_syslog('We found a difference of '.$diff.' for line rowid = '.$obj->rowid.". We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix);
2791
								$resqlfix=$this->db->query($sqlfix);
2792
								if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2793
								$this->total_tva -= $diff;
2794
								$this->total_ttc -= $diff;
2795
								$total_tva_by_vats[$obj->vatrate] -= $diff;
2796
								$total_ttc_by_vats[$obj->vatrate] -= $diff;
2797
					}
2798
				}
2799
2800
				$i++;
2801
			}
2802
2803
			// Add revenue stamp to total
2804
			$this->total_ttc       			+= isset($this->revenuestamp)?$this->revenuestamp:0;
2805
			$this->multicurrency_total_ttc  += isset($this->revenuestamp)?($this->revenuestamp * $multicurrency_tx):0;
2806
2807
			// Situations totals
2808
			if ($this->situation_cycle_ref && $this->situation_counter > 1 && method_exists($this, 'get_prev_sits') && $this->type != $this::TYPE_CREDIT_NOTE )
0 ignored issues
show
Bug Best Practice introduced by
The property situation_counter does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
Bug Best Practice introduced by
The property situation_cycle_ref does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2809
			{
2810
				$prev_sits = $this->get_prev_sits();
2811
2812
				foreach ($prev_sits as $sit) {				// $sit is an object Facture loaded with a fetch.
2813
					$this->total_ht -= $sit->total_ht;
2814
					$this->total_tva -= $sit->total_tva;
2815
					$this->total_localtax1 -= $sit->total_localtax1;
2816
					$this->total_localtax2 -= $sit->total_localtax2;
2817
					$this->total_ttc -= $sit->total_ttc;
2818
					$this->multicurrency_total_ht -= $sit->multicurrency_total_ht;
2819
					$this->multicurrency_total_tva -= $sit->multicurrency_total_tva;
2820
					$this->multicurrency_total_ttc -= $sit->multicurrency_total_ttc;
2821
				}
2822
			}
2823
2824
			$this->db->free($resql);
2825
2826
			// Now update global field total_ht, total_ttc and tva
2827
			$fieldht='total_ht';
2828
			$fieldtva='tva';
2829
			$fieldlocaltax1='localtax1';
2830
			$fieldlocaltax2='localtax2';
2831
			$fieldttc='total_ttc';
2832
			// Specific code for backward compatibility with old field names
2833
			if ($this->element == 'facture' || $this->element == 'facturerec')             $fieldht='total';
2834
			if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva='total_tva';
2835
			if ($this->element == 'propal')                                                $fieldttc='total';
2836
			if ($this->element == 'expensereport')                                         $fieldtva='total_tva';
2837
			if ($this->element == 'supplier_proposal')                                     $fieldttc='total';
2838
2839
			if (empty($nodatabaseupdate))
2840
			{
2841
				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET';
2842
				$sql .= " ".$fieldht."='".price2num($this->total_ht)."',";
2843
				$sql .= " ".$fieldtva."='".price2num($this->total_tva)."',";
2844
				$sql .= " ".$fieldlocaltax1."='".price2num($this->total_localtax1)."',";
2845
				$sql .= " ".$fieldlocaltax2."='".price2num($this->total_localtax2)."',";
2846
				$sql .= " ".$fieldttc."='".price2num($this->total_ttc)."'";
2847
						$sql .= ", multicurrency_total_ht='".price2num($this->multicurrency_total_ht, 'MT', 1)."'";
2848
						$sql .= ", multicurrency_total_tva='".price2num($this->multicurrency_total_tva, 'MT', 1)."'";
2849
						$sql .= ", multicurrency_total_ttc='".price2num($this->multicurrency_total_ttc, 'MT', 1)."'";
2850
				$sql .= ' WHERE rowid = '.$this->id;
2851
2852
2853
				dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2854
				$resql=$this->db->query($sql);
2855
				if (! $resql)
2856
				{
2857
					$error++;
2858
					$this->error=$this->db->lasterror();
2859
					$this->errors[]=$this->db->lasterror();
2860
				}
2861
			}
2862
2863
			if (! $error)
2864
			{
2865
				return 1;
2866
			}
2867
			else
2868
			{
2869
				return -1;
2870
			}
2871
		}
2872
		else
2873
		{
2874
			dol_print_error($this->db,'Bad request in update_price');
2875
			return -1;
2876
		}
2877
	}
2878
2879
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2880
	/**
2881
	 *	Add objects linked in llx_element_element.
2882
	 *
2883
	 *	@param		string	$origin		Linked element type
2884
	 *	@param		int		$origin_id	Linked element id
2885
	 *	@return		int					<=0 if KO, >0 if OK
2886
	 *	@see		fetchObjectLinked, updateObjectLinked, deleteObjectLinked
2887
	 */
2888
	function add_object_linked($origin=null, $origin_id=null)
2889
	{
2890
        // phpcs:enable
2891
		$origin = (! empty($origin) ? $origin : $this->origin);
2892
		$origin_id = (! empty($origin_id) ? $origin_id : $this->origin_id);
2893
2894
		// Special case
2895
		if ($origin == 'order') $origin='commande';
2896
		if ($origin == 'invoice') $origin='facture';
2897
		if ($origin == 'invoice_template') $origin='facturerec';
2898
    	if ($origin == 'supplierorder') $origin='order_supplier';
2899
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
2900
2901
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."element_element (";
2902
		$sql.= "fk_source";
2903
		$sql.= ", sourcetype";
2904
		$sql.= ", fk_target";
2905
		$sql.= ", targettype";
2906
		$sql.= ") VALUES (";
2907
		$sql.= $origin_id;
2908
		$sql.= ", '".$this->db->escape($origin)."'";
2909
		$sql.= ", ".$this->id;
2910
		$sql.= ", '".$this->db->escape($this->element)."'";
2911
		$sql.= ")";
2912
2913
		dol_syslog(get_class($this)."::add_object_linked", LOG_DEBUG);
2914
		if ($this->db->query($sql))
2915
	  	{
2916
	  		$this->db->commit();
2917
	  		return 1;
2918
	  	}
2919
	  	else
2920
	  	{
2921
	  		$this->error=$this->db->lasterror();
2922
	  		$this->db->rollback();
2923
	  		return 0;
2924
	  	}
2925
	}
2926
2927
	/**
2928
	 *	Fetch array of objects linked to current object (object of enabled modules only). Links are loaded into
2929
	 *		this->linkedObjectsIds array and
2930
	 *		this->linkedObjects array if $loadalsoobjects = 1
2931
	 *  Possible usage for parameters:
2932
	 *  - all parameters empty -> we look all link to current object (current object can be source or target)
2933
	 *  - source id+type -> will get target list linked to source
2934
	 *  - target id+type -> will get source list linked to target
2935
	 *  - source id+type + target type -> will get target list of the type
2936
	 *  - target id+type + target source -> will get source list of the type
2937
	 *
2938
	 *	@param	int		$sourceid			Object source id (if not defined, id of object)
2939
	 *	@param  string	$sourcetype			Object source type (if not defined, element name of object)
2940
	 *	@param  int		$targetid			Object target id (if not defined, id of object)
2941
	 *	@param  string	$targettype			Object target type (if not defined, elemennt name of object)
2942
	 *	@param  string	$clause				'OR' or 'AND' clause used when both source id and target id are provided
2943
	 *  @param  int		$alsosametype		0=Return only links to object that differs from source type. 1=Include also link to objects of same type.
2944
	 *  @param  string	$orderby			SQL 'ORDER BY' clause
2945
	 *  @param	int		$loadalsoobjects	Load also array this->linkedObjects (Use 0 to increase performances)
2946
	 *	@return int							<0 if KO, >0 if OK
2947
	 *  @see	add_object_linked, updateObjectLinked, deleteObjectLinked
2948
	 */
2949
	function fetchObjectLinked($sourceid=null,$sourcetype='',$targetid=null,$targettype='',$clause='OR',$alsosametype=1,$orderby='sourcetype',$loadalsoobjects=1)
2950
	{
2951
		global $conf;
2952
2953
		$this->linkedObjectsIds=array();
2954
		$this->linkedObjects=array();
2955
2956
		$justsource=false;
2957
		$justtarget=false;
2958
		$withtargettype=false;
2959
		$withsourcetype=false;
2960
2961
		if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid))
2962
		{
2963
			$justsource=true;  // the source (id and type) is a search criteria
2964
			if (! empty($targettype)) $withtargettype=true;
2965
		}
2966
		if (! empty($targetid) && ! empty($targettype) && empty($sourceid))
2967
		{
2968
			$justtarget=true;  // the target (id and type) is a search criteria
2969
			if (! empty($sourcetype)) $withsourcetype=true;
2970
		}
2971
2972
		$sourceid = (! empty($sourceid) ? $sourceid : $this->id);
2973
		$targetid = (! empty($targetid) ? $targetid : $this->id);
2974
		$sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
2975
		$targettype = (! empty($targettype) ? $targettype : $this->element);
2976
2977
		/*if (empty($sourceid) && empty($targetid))
2978
		 {
2979
		 dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR);
2980
		 return -1;
2981
		 }*/
2982
2983
		// Links between objects are stored in table element_element
2984
		$sql = 'SELECT rowid, fk_source, sourcetype, fk_target, targettype';
2985
		$sql.= ' FROM '.MAIN_DB_PREFIX.'element_element';
2986
		$sql.= " WHERE ";
2987
		if ($justsource || $justtarget)
2988
		{
2989
			if ($justsource)
2990
			{
2991
				$sql.= "fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."'";
2992
				if ($withtargettype) $sql.= " AND targettype = '".$targettype."'";
2993
			}
2994
			else if ($justtarget)
2995
			{
2996
				$sql.= "fk_target = ".$targetid." AND targettype = '".$targettype."'";
2997
				if ($withsourcetype) $sql.= " AND sourcetype = '".$sourcetype."'";
2998
			}
2999
		}
3000
		else
3001
		{
3002
			$sql.= "(fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."')";
3003
			$sql.= " ".$clause." (fk_target = ".$targetid." AND targettype = '".$targettype."')";
3004
		}
3005
		$sql .= ' ORDER BY '.$orderby;
3006
3007
		dol_syslog(get_class($this)."::fetchObjectLink", LOG_DEBUG);
3008
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3009
		if ($resql)
3010
		{
3011
			$num = $this->db->num_rows($resql);
3012
			$i = 0;
3013
			while ($i < $num)
3014
			{
3015
				$obj = $this->db->fetch_object($resql);
3016
				if ($justsource || $justtarget)
3017
				{
3018
					if ($justsource)
3019
					{
3020
						$this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
3021
					}
3022
					else if ($justtarget)
3023
					{
3024
						$this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
3025
					}
3026
				}
3027
				else
3028
				{
3029
					if ($obj->fk_source == $sourceid && $obj->sourcetype == $sourcetype)
3030
					{
3031
						$this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
3032
					}
3033
					if ($obj->fk_target == $targetid && $obj->targettype == $targettype)
3034
					{
3035
						$this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
3036
					}
3037
				}
3038
				$i++;
3039
			}
3040
3041
			if (! empty($this->linkedObjectsIds))
3042
			{
3043
				$tmparray = $this->linkedObjectsIds;
3044
				foreach($tmparray as $objecttype => $objectids)       // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...)
3045
				{
3046
					// Parse element/subelement (ex: project_task, cabinetmed_consultation, ...)
3047
					$module = $element = $subelement = $objecttype;
3048
					if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier'
3049
						&& preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
3050
					{
3051
						$module = $element = $regs[1];
3052
						$subelement = $regs[2];
3053
					}
3054
3055
					$classpath = $element.'/class';
3056
					// To work with non standard classpath or module name
3057
					if ($objecttype == 'facture')			{
3058
						$classpath = 'compta/facture/class';
3059
					}
3060
					else if ($objecttype == 'facturerec')			{
3061
						$classpath = 'compta/facture/class'; $module = 'facture';
3062
					}
3063
					else if ($objecttype == 'propal')			{
3064
						$classpath = 'comm/propal/class';
3065
					}
3066
					else if ($objecttype == 'supplier_proposal')			{
3067
						$classpath = 'supplier_proposal/class';
3068
					}
3069
					else if ($objecttype == 'shipping')			{
3070
						$classpath = 'expedition/class'; $subelement = 'expedition'; $module = 'expedition_bon';
3071
					}
3072
					else if ($objecttype == 'delivery')			{
3073
						$classpath = 'livraison/class'; $subelement = 'livraison'; $module = 'livraison_bon';
3074
					}
3075
					else if ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier')	{
3076
						$classpath = 'fourn/class'; $module = 'fournisseur';
3077
					}
3078
					else if ($objecttype == 'fichinter')			{
3079
						$classpath = 'fichinter/class'; $subelement = 'fichinter'; $module = 'ficheinter';
3080
					}
3081
					else if ($objecttype == 'subscription')			{
3082
						$classpath = 'adherents/class'; $module = 'adherent';
3083
					}
3084
3085
					// Set classfile
3086
					$classfile = strtolower($subelement); $classname = ucfirst($subelement);
3087
3088
					if ($objecttype == 'order') {
3089
						$classfile = 'commande'; $classname = 'Commande';
3090
					}
3091
					else if ($objecttype == 'invoice_supplier') {
3092
						$classfile = 'fournisseur.facture'; $classname = 'FactureFournisseur';
3093
					}
3094
					else if ($objecttype == 'order_supplier')   {
3095
						$classfile = 'fournisseur.commande'; $classname = 'CommandeFournisseur';
3096
					}
3097
					else if ($objecttype == 'supplier_proposal')   {
3098
						$classfile = 'supplier_proposal'; $classname = 'SupplierProposal';
3099
					}
3100
					else if ($objecttype == 'facturerec')   {
3101
						$classfile = 'facture-rec'; $classname = 'FactureRec';
3102
					}
3103
					else if ($objecttype == 'subscription')   {
3104
						$classfile = 'subscription'; $classname = 'Subscription';
3105
					}
3106
3107
					// Here $module, $classfile and $classname are set
3108
					if ($conf->$module->enabled && (($element != $this->element) || $alsosametype))
3109
					{
3110
						if ($loadalsoobjects)
3111
						{
3112
							dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
3113
							//print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname);
3114
							if (class_exists($classname))
3115
							{
3116
								foreach($objectids as $i => $objectid)	// $i is rowid into llx_element_element
3117
								{
3118
									$object = new $classname($this->db);
3119
									$ret = $object->fetch($objectid);
3120
									if ($ret >= 0)
3121
									{
3122
										$this->linkedObjects[$objecttype][$i] = $object;
3123
									}
3124
								}
3125
							}
3126
						}
3127
					}
3128
					else
3129
					{
3130
						unset($this->linkedObjectsIds[$objecttype]);
3131
					}
3132
				}
3133
			}
3134
			return 1;
3135
		}
3136
		else
3137
		{
3138
			dol_print_error($this->db);
3139
			return -1;
3140
		}
3141
	}
3142
3143
	/**
3144
	 *	Update object linked of a current object
3145
	 *
3146
	 *	@param	int		$sourceid		Object source id
3147
	 *	@param  string	$sourcetype		Object source type
3148
	 *	@param  int		$targetid		Object target id
3149
	 *	@param  string	$targettype		Object target type
3150
	 *	@return							int	>0 if OK, <0 if KO
3151
	 *	@see	add_object_linked, fetObjectLinked, deleteObjectLinked
3152
	 */
3153
	function updateObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='')
3154
	{
3155
		$updatesource=false;
3156
		$updatetarget=false;
3157
3158
		if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $updatesource=true;
3159
		else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $updatetarget=true;
3160
3161
		$sql = "UPDATE ".MAIN_DB_PREFIX."element_element SET ";
3162
		if ($updatesource)
3163
		{
3164
			$sql.= "fk_source = ".$sourceid;
3165
			$sql.= ", sourcetype = '".$this->db->escape($sourcetype)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3166
			$sql.= " WHERE fk_target = ".$this->id;
3167
			$sql.= " AND targettype = '".$this->db->escape($this->element)."'";
3168
		}
3169
		else if ($updatetarget)
3170
		{
3171
			$sql.= "fk_target = ".$targetid;
3172
			$sql.= ", targettype = '".$this->db->escape($targettype)."'";
3173
			$sql.= " WHERE fk_source = ".$this->id;
3174
			$sql.= " AND sourcetype = '".$this->db->escape($this->element)."'";
3175
		}
3176
3177
		dol_syslog(get_class($this)."::updateObjectLinked", LOG_DEBUG);
3178
		if ($this->db->query($sql))
3179
		{
3180
			return 1;
3181
		}
3182
		else
3183
		{
3184
			$this->error=$this->db->lasterror();
3185
			return -1;
3186
		}
3187
	}
3188
3189
	/**
3190
	 *	Delete all links between an object $this
3191
	 *
3192
	 *	@param	int		$sourceid		Object source id
3193
	 *	@param  string	$sourcetype		Object source type
3194
	 *	@param  int		$targetid		Object target id
3195
	 *	@param  string	$targettype		Object target type
3196
	 *  @param	int		$rowid			Row id of line to delete. If defined, other parameters are not used.
3197
	 *	@return     					int	>0 if OK, <0 if KO
3198
	 *	@see	add_object_linked, updateObjectLinked, fetchObjectLinked
3199
	 */
3200
	function deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
3201
	{
3202
		$deletesource=false;
3203
		$deletetarget=false;
3204
3205
		if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $deletesource=true;
3206
		else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $deletetarget=true;
3207
3208
		$sourceid = (! empty($sourceid) ? $sourceid : $this->id);
3209
		$sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
3210
		$targetid = (! empty($targetid) ? $targetid : $this->id);
3211
		$targettype = (! empty($targettype) ? $targettype : $this->element);
3212
3213
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_element";
3214
		$sql.= " WHERE";
3215
		if ($rowid > 0)
3216
		{
3217
			$sql.=" rowid = ".$rowid;
3218
		}
3219
		else
3220
		{
3221
			if ($deletesource)
3222
			{
3223
				$sql.= " fk_source = ".$sourceid." AND sourcetype = '".$this->db->escape($sourcetype)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3224
				$sql.= " AND fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."'";
3225
			}
3226
			else if ($deletetarget)
3227
			{
3228
				$sql.= " fk_target = ".$targetid." AND targettype = '".$this->db->escape($targettype)."'";
3229
				$sql.= " AND fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."'";
3230
			}
3231
			else
3232
			{
3233
				$sql.= " (fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."')";
3234
				$sql.= " OR";
3235
				$sql.= " (fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."')";
3236
			}
3237
		}
3238
3239
		dol_syslog(get_class($this)."::deleteObjectLinked", LOG_DEBUG);
3240
		if ($this->db->query($sql))
3241
		{
3242
			return 1;
3243
		}
3244
		else
3245
		{
3246
			$this->error=$this->db->lasterror();
3247
			$this->errors[]=$this->error;
3248
			return -1;
3249
		}
3250
	}
3251
3252
	/**
3253
	 *      Set status of an object
3254
	 *
3255
	 *      @param	int		$status			Status to set
3256
	 *      @param	int		$elementId		Id of element to force (use this->id by default)
3257
	 *      @param	string	$elementType	Type of element to force (use this->table_element by default)
3258
	 *      @param	string	$trigkey		Trigger key to use for trigger
3259
	 *      @return int						<0 if KO, >0 if OK
3260
	 */
3261
	function setStatut($status, $elementId=null, $elementType='', $trigkey='')
3262
	{
3263
		global $user,$langs,$conf;
3264
3265
		$savElementId=$elementId;  // To be used later to know if we were using the method using the id of this or not.
3266
3267
		$elementId = (!empty($elementId)?$elementId:$this->id);
3268
		$elementTable = (!empty($elementType)?$elementType:$this->table_element);
3269
3270
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3271
3272
		$fieldstatus="fk_statut";
3273
		if ($elementTable == 'facture_rec') $fieldstatus="suspended";
3274
		if ($elementTable == 'mailing') $fieldstatus="statut";
3275
		if ($elementTable == 'cronjob') $fieldstatus="status";
3276
		if ($elementTable == 'user') $fieldstatus="statut";
3277
		if ($elementTable == 'expensereport') $fieldstatus="fk_statut";
3278
		if ($elementTable == 'commande_fournisseur_dispatch') $fieldstatus="status";
3279
3280
		$sql = "UPDATE ".MAIN_DB_PREFIX.$elementTable;
3281
		$sql.= " SET ".$fieldstatus." = ".$status;
3282
		// If status = 1 = validated, update also fk_user_valid
3283
		if ($status == 1 && $elementTable == 'expensereport') $sql.=", fk_user_valid = ".$user->id;
3284
		$sql.= " WHERE rowid=".$elementId;
3285
3286
		dol_syslog(get_class($this)."::setStatut", LOG_DEBUG);
3287
		if ($this->db->query($sql))
3288
		{
3289
			$error = 0;
3290
3291
			// Try autoset of trigkey
3292
			if (empty($trigkey))
3293
			{
3294
				if ($this->element == 'supplier_proposal' && $status == 2) $trigkey='SUPPLIER_PROPOSAL_SIGN';   // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class
3295
				if ($this->element == 'supplier_proposal' && $status == 3) $trigkey='SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class
3296
				if ($this->element == 'supplier_proposal' && $status == 4) $trigkey='SUPPLIER_PROPOSAL_CLOSE';  // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class
3297
				if ($this->element == 'fichinter' && $status == 3) $trigkey='FICHINTER_CLASSIFY_DONE';
3298
				if ($this->element == 'fichinter' && $status == 2) $trigkey='FICHINTER_CLASSIFY_BILLED';
3299
				if ($this->element == 'fichinter' && $status == 1) $trigkey='FICHINTER_CLASSIFY_UNBILLED';
3300
			}
3301
3302
			if ($trigkey)
3303
			{
3304
				// Appel des triggers
3305
				include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
3306
				$interface=new Interfaces($this->db);
3307
				$result=$interface->run_triggers($trigkey,$this,$user,$langs,$conf);
3308
				if ($result < 0) {
3309
					$error++; $this->errors=$interface->errors;
3310
				}
3311
				// Fin appel triggers
3312
			}
3313
3314
			if (! $error)
3315
			{
3316
				$this->db->commit();
3317
3318
				if (empty($savElementId))    // If the element we update was $this (so $elementId is null)
3319
				{
3320
					$this->statut = $status;
3321
					$this->status = $status;
3322
				}
3323
3324
				return 1;
3325
			}
3326
			else
3327
			{
3328
				$this->db->rollback();
3329
				dol_syslog(get_class($this)."::setStatus ".$this->error,LOG_ERR);
3330
				return -1;
3331
			}
3332
		}
3333
		else
3334
		{
3335
			$this->error=$this->db->lasterror();
3336
			$this->db->rollback();
3337
			return -1;
3338
		}
3339
	}
3340
3341
3342
	/**
3343
	 *  Load type of canvas of an object if it exists
3344
	 *
3345
	 *  @param      int		$id     Record id
3346
	 *  @param      string	$ref    Record ref
3347
	 *  @return		int				<0 if KO, 0 if nothing done, >0 if OK
3348
	 */
3349
	function getCanvas($id=0,$ref='')
3350
	{
3351
		global $conf;
3352
3353
		if (empty($id) && empty($ref)) return 0;
3354
		if (! empty($conf->global->MAIN_DISABLE_CANVAS)) return 0;    // To increase speed. Not enabled by default.
3355
3356
		// Clean parameters
3357
		$ref = trim($ref);
3358
3359
		$sql = "SELECT rowid, canvas";
3360
		$sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element;
3361
		$sql.= " WHERE entity IN (".getEntity($this->element).")";
3362
		if (! empty($id))  $sql.= " AND rowid = ".$id;
3363
		if (! empty($ref)) $sql.= " AND ref = '".$this->db->escape($ref)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3364
3365
		$resql = $this->db->query($sql);
3366
		if ($resql)
3367
		{
3368
			$obj = $this->db->fetch_object($resql);
3369
			if ($obj)
3370
			{
3371
				$this->canvas   = $obj->canvas;
3372
				return 1;
3373
			}
3374
			else return 0;
3375
		}
3376
		else
3377
		{
3378
			dol_print_error($this->db);
3379
			return -1;
3380
		}
3381
	}
3382
3383
3384
	/**
3385
	 * 	Get special code of a line
3386
	 *
3387
	 * 	@param	int		$lineid		Id of line
3388
	 * 	@return	int					Special code
3389
	 */
3390
	function getSpecialCode($lineid)
3391
	{
3392
		$sql = 'SELECT special_code FROM '.MAIN_DB_PREFIX.$this->table_element_line;
3393
		$sql.= ' WHERE rowid = '.$lineid;
3394
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3395
		if ($resql)
3396
		{
3397
			$row = $this->db->fetch_row($resql);
3398
			return $row[0];
3399
		}
3400
	}
3401
3402
	/**
3403
	 *  Function to check if an object is used by others.
3404
	 *  Check is done into this->childtables. There is no check into llx_element_element.
3405
	 *
3406
	 *  @param	int		$id			Force id of object
3407
	 *  @return	int					<0 if KO, 0 if not used, >0 if already used
3408
	 */
3409
	function isObjectUsed($id=0)
3410
	{
3411
		global $langs;
3412
3413
		if (empty($id)) $id=$this->id;
3414
3415
		// Check parameters
3416
		if (! isset($this->childtables) || ! is_array($this->childtables) || count($this->childtables) == 0)
3417
		{
3418
			dol_print_error('Called isObjectUsed on a class with property this->childtables not defined');
3419
			return -1;
3420
		}
3421
3422
		$arraytoscan = $this->childtables;
3423
		// For backward compatibility, we check if array is old format array('table1', 'table2', ...)
3424
		$tmparray=array_keys($this->childtables);
3425
		if (is_numeric($tmparray[0]))
3426
		{
3427
			$arraytoscan = array_flip($this->childtables);
3428
		}
3429
3430
		// Test if child exists
3431
		$haschild=0;
3432
		foreach($arraytoscan as $table => $elementname)
3433
		{
3434
			//print $id.'-'.$table.'-'.$elementname.'<br>';
3435
			// Check if third party can be deleted
3436
			$sql = "SELECT COUNT(*) as nb from ".MAIN_DB_PREFIX.$table;
3437
			$sql.= " WHERE ".$this->fk_element." = ".$id;
3438
			$resql=$this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3439
			if ($resql)
3440
			{
3441
				$obj=$this->db->fetch_object($resql);
3442
				if ($obj->nb > 0)
3443
				{
3444
					$langs->load("errors");
3445
					//print 'Found into table '.$table.', type '.$langs->transnoentitiesnoconv($elementname).', haschild='.$haschild;
3446
					$haschild += $obj->nb;
3447
					if (is_numeric($elementname))	// old usage
3448
					{
3449
						$this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $table);
3450
					}
3451
					else	// new usage: $elementname=Translation key
3452
					{
3453
						$this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $langs->transnoentitiesnoconv($elementname));
3454
					}
3455
					break;    // We found at least one, we stop here
3456
				}
3457
			}
3458
			else
3459
			{
3460
				$this->errors[]=$this->db->lasterror();
3461
				return -1;
3462
			}
3463
		}
3464
		if ($haschild > 0)
3465
		{
3466
			$this->errors[]="ErrorRecordHasChildren";
3467
			return $haschild;
3468
		}
3469
		else return 0;
3470
	}
3471
3472
	/**
3473
	 *  Function to say how many lines object contains
3474
	 *
3475
	 *	@param	int		$predefined		-1=All, 0=Count free product/service only, 1=Count predefined product/service only, 2=Count predefined product, 3=Count predefined service
3476
	 *  @return	int						<0 if KO, 0 if no predefined products, nb of lines with predefined products if found
3477
	 */
3478
	function hasProductsOrServices($predefined=-1)
3479
	{
3480
		$nb=0;
3481
3482
		foreach($this->lines as $key => $val)
3483
		{
3484
			$qualified=0;
3485
			if ($predefined == -1) $qualified=1;
3486
			if ($predefined == 1 && $val->fk_product > 0) $qualified=1;
3487
			if ($predefined == 0 && $val->fk_product <= 0) $qualified=1;
3488
			if ($predefined == 2 && $val->fk_product > 0 && $val->product_type==0) $qualified=1;
3489
			if ($predefined == 3 && $val->fk_product > 0 && $val->product_type==1) $qualified=1;
3490
			if ($qualified) $nb++;
3491
		}
3492
		dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies');
3493
		return $nb;
3494
	}
3495
3496
	/**
3497
	 * Function that returns the total amount HT of discounts applied for all lines.
3498
	 *
3499
	 * @return 	float
3500
	 */
3501
	function getTotalDiscount()
3502
	{
3503
		$total_discount=0.00;
3504
3505
		$sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht";
3506
		$sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element."det";
3507
		$sql.= " WHERE ".$this->fk_element." = ".$this->id;
3508
3509
		dol_syslog(get_class($this).'::getTotalDiscount', LOG_DEBUG);
3510
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3511
		if ($resql)
3512
		{
3513
			$num=$this->db->num_rows($resql);
3514
			$i=0;
3515
			while ($i < $num)
3516
			{
3517
				$obj = $this->db->fetch_object($resql);
3518
3519
				$pu_ht = $obj->pu_ht;
3520
				$qty= $obj->qty;
3521
				$total_ht = $obj->total_ht;
3522
3523
				$total_discount_line = floatval(price2num(($pu_ht * $qty) - $total_ht, 'MT'));
3524
				$total_discount += $total_discount_line;
3525
3526
				$i++;
3527
			}
3528
		}
3529
3530
		//print $total_discount; exit;
3531
		return price2num($total_discount);
3532
	}
3533
3534
3535
	/**
3536
	 * Return into unit=0, the calculated total of weight and volume of all lines * qty
3537
	 * Calculate by adding weight and volume of each product line, so properties ->volume/volume_units/weight/weight_units must be loaded on line.
3538
	 *
3539
	 * @return  array                           array('weight'=>...,'volume'=>...)
3540
	 */
3541
	function getTotalWeightVolume()
3542
	{
3543
		$totalWeight = 0;
3544
		$totalVolume = 0;
3545
		// defined for shipment only
3546
		$totalOrdered = '';
3547
		// defined for shipment only
3548
		$totalToShip = '';
3549
3550
		foreach ($this->lines as $line)
3551
		{
3552
			if (isset($line->qty_asked))
3553
			{
3554
				if (empty($totalOrdered)) $totalOrdered=0;  // Avoid warning because $totalOrdered is ''
3555
				$totalOrdered+=$line->qty_asked;    // defined for shipment only
3556
			}
3557
			if (isset($line->qty_shipped))
3558
			{
3559
				if (empty($totalToShip)) $totalToShip=0;    // Avoid warning because $totalToShip is ''
3560
				$totalToShip+=$line->qty_shipped;   // defined for shipment only
3561
            }else if ($line->element == 'commandefournisseurdispatch' && isset($line->qty))
3562
            {
3563
                if (empty($totalToShip)) $totalToShip=0;
3564
                $totalToShip+=$line->qty;   // defined for reception only
3565
			}
3566
3567
			// Define qty, weight, volume, weight_units, volume_units
3568
			if ($this->element == 'shipping') {
3569
				// for shipments
3570
				$qty = $line->qty_shipped ? $line->qty_shipped : 0;
3571
			}
3572
			else {
3573
				$qty = $line->qty ? $line->qty : 0;
3574
			}
3575
3576
			$weight = $line->weight ? $line->weight : 0;
3577
            ($weight==0 && !empty($line->product->weight))? $weight=$line->product->weight: 0;
3578
			$volume = $line->volume ? $line->volume : 0;
3579
			($volume==0 && !empty($line->product->volume))? $volume=$line->product->volume: 0;
3580
3581
			$weight_units=$line->weight_units;
3582
			($weight_units==0 && !empty($line->product->weight_units))? $weight_units=$line->product->weight_units: 0;
3583
			$volume_units=$line->volume_units;
3584
			($volume_units==0 && !empty($line->product->volume_units))? $volume_units=$line->product->volume_units: 0;
3585
3586
			$weightUnit=0;
3587
			$volumeUnit=0;
3588
			if (! empty($weight_units)) $weightUnit = $weight_units;
3589
			if (! empty($volume_units)) $volumeUnit = $volume_units;
3590
3591
			if (empty($totalWeight)) $totalWeight=0;  // Avoid warning because $totalWeight is ''
3592
			if (empty($totalVolume)) $totalVolume=0;  // Avoid warning because $totalVolume is ''
3593
3594
			//var_dump($line->volume_units);
3595
			if ($weight_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3596
			{
3597
				$trueWeightUnit=pow(10, $weightUnit);
3598
				$totalWeight += $weight * $qty * $trueWeightUnit;
3599
			}
3600
			else {
3601
		if ($weight_units == 99) {
3602
			// conversion 1 Pound = 0.45359237 KG
3603
			$trueWeightUnit = 0.45359237;
3604
			$totalWeight += $weight * $qty * $trueWeightUnit;
3605
		} elseif ($weight_units == 98) {
3606
			// conversion 1 Ounce = 0.0283495 KG
3607
			$trueWeightUnit = 0.0283495;
3608
			$totalWeight += $weight * $qty * $trueWeightUnit;
3609
		}
3610
		else
3611
					$totalWeight += $weight * $qty;   // This may be wrong if we mix different units
3612
			}
3613
			if ($volume_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3614
			{
3615
				//print $line->volume."x".$line->volume_units."x".($line->volume_units < 50)."x".$volumeUnit;
3616
				$trueVolumeUnit=pow(10, $volumeUnit);
3617
				//print $line->volume;
3618
				$totalVolume += $volume * $qty * $trueVolumeUnit;
3619
			}
3620
			else
3621
			{
3622
				$totalVolume += $volume * $qty;   // This may be wrong if we mix different units
3623
			}
3624
		}
3625
3626
		return array('weight'=>$totalWeight, 'volume'=>$totalVolume, 'ordered'=>$totalOrdered, 'toship'=>$totalToShip);
3627
	}
3628
3629
3630
	/**
3631
	 *	Set extra parameters
3632
	 *
3633
	 *	@return	int      <0 if KO, >0 if OK
3634
	 */
3635
	function setExtraParameters()
3636
	{
3637
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3638
3639
		$extraparams = (! empty($this->extraparams) ? json_encode($this->extraparams) : null);
0 ignored issues
show
Bug Best Practice introduced by
The property extraparams does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3640
3641
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3642
		$sql.= " SET extraparams = ".(! empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null");
3643
		$sql.= " WHERE rowid = ".$this->id;
3644
3645
		dol_syslog(get_class($this)."::setExtraParameters", LOG_DEBUG);
3646
		$resql = $this->db->query($sql);
3647
		if (! $resql)
3648
		{
3649
			$this->error=$this->db->lasterror();
3650
			$this->db->rollback();
3651
			return -1;
3652
		}
3653
		else
3654
		{
3655
			$this->db->commit();
3656
			return 1;
3657
		}
3658
	}
3659
3660
3661
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3662
	/**
3663
	 *    Return incoterms informations
3664
	 *    TODO Use a cache for label get
3665
	 *
3666
	 *    @return	string	incoterms info
3667
	 */
3668
	function display_incoterms()
3669
	{
3670
        // phpcs:enable
3671
		$out = '';
3672
		$this->libelle_incoterms = '';
3673
		if (!empty($this->fk_incoterms))
3674
		{
3675
			$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3676
			$result = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3677
			if ($result)
3678
			{
3679
				$res = $this->db->fetch_object($result);
3680
				$out .= $res->code;
3681
			}
3682
		}
3683
3684
		$out .= (($res->code && $this->location_incoterms)?' - ':'').$this->location_incoterms;
3685
3686
		return $out;
3687
	}
3688
3689
	/**
3690
	 *    Return incoterms informations for pdf display
3691
	 *
3692
	 *    @return	string		incoterms info
3693
	 */
3694
	function getIncotermsForPDF()
3695
	{
3696
		$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3697
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3698
		if ($resql)
3699
		{
3700
			$num = $this->db->num_rows($resql);
3701
			if ($num > 0)
3702
			{
3703
				$res = $this->db->fetch_object($resql);
3704
				return 'Incoterm : '.$res->code.' - '.$this->location_incoterms;
3705
			}
3706
			else
3707
			{
3708
				return '';
3709
			}
3710
		}
3711
		else
3712
		{
3713
			$this->errors[] = $this->db->lasterror();
3714
			return false;
3715
		}
3716
	}
3717
3718
	/**
3719
	 *    Define incoterms values of current object
3720
	 *
3721
	 *    @param	int		$id_incoterm     Id of incoterm to set or '' to remove
3722
	 * 	  @param 	string  $location		 location of incoterm
3723
	 *    @return	int     		<0 if KO, >0 if OK
3724
	 */
3725
	function setIncoterms($id_incoterm, $location)
3726
	{
3727
		if ($this->id && $this->table_element)
3728
		{
3729
			$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3730
			$sql.= " SET fk_incoterms = ".($id_incoterm > 0 ? $id_incoterm : "null");
3731
			$sql.= ", location_incoterms = ".($id_incoterm > 0 ? "'".$this->db->escape($location)."'" : "null");
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3732
			$sql.= " WHERE rowid = " . $this->id;
3733
			dol_syslog(get_class($this).'::setIncoterms', LOG_DEBUG);
3734
			$resql=$this->db->query($sql);
3735
			if ($resql)
3736
			{
3737
				$this->fk_incoterms = $id_incoterm;
3738
				$this->location_incoterms = $location;
3739
3740
				$sql = 'SELECT libelle FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3741
				$res = $this->db->query($sql);
3742
				if ($res)
3743
				{
3744
					$obj = $this->db->fetch_object($res);
3745
					$this->libelle_incoterms = $obj->libelle;
3746
				}
3747
				return 1;
3748
			}
3749
			else
3750
			{
3751
				$this->errors[] = $this->db->lasterror();
3752
				return -1;
3753
			}
3754
		}
3755
		else return -1;
3756
	}
3757
3758
3759
	// --------------------
3760
	// TODO: All functions here must be redesigned and moved as they are not business functions but output functions
3761
	// --------------------
3762
3763
	/* This is to show add lines */
3764
3765
	/**
3766
	 *	Show add free and predefined products/services form
3767
	 *
3768
	 *  @param	int		        $dateSelector       1=Show also date range input fields
3769
	 *  @param	Societe			$seller				Object thirdparty who sell
3770
	 *  @param	Societe			$buyer				Object thirdparty who buy
3771
	 *	@return	void
3772
	 */
3773
	function formAddObjectLine($dateSelector, $seller, $buyer)
3774
	{
3775
		global $conf,$user,$langs,$object,$hookmanager;
3776
		global $form,$bcnd,$var;
3777
3778
		// Line extrafield
3779
		require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3780
		$extrafieldsline = new ExtraFields($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3781
		$extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3782
3783
		// Output template part (modules that overwrite templates must declare this into descriptor)
3784
		// Use global variables + $dateSelector + $seller and $buyer
3785
		$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
3786
		foreach($dirtpls as $reldir)
3787
		{
3788
			$tpl = dol_buildpath($reldir.'/objectline_create.tpl.php');
3789
			if (empty($conf->file->strict_mode)) {
3790
				$res=@include $tpl;
3791
			} else {
3792
				$res=include $tpl; // for debug
3793
			}
3794
			if ($res) break;
3795
		}
3796
	}
3797
3798
3799
3800
	/* This is to show array of line of details */
3801
3802
3803
	/**
3804
	 *	Return HTML table for object lines
3805
	 *	TODO Move this into an output class file (htmlline.class.php)
3806
	 *	If lines are into a template, title must also be into a template
3807
	 *	But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
3808
	 *
3809
	 *	@param	string		$action				Action code
3810
	 *	@param  string		$seller            	Object of seller third party
3811
	 *	@param  string  	$buyer             	Object of buyer third party
3812
	 *	@param	int			$selected		   	Object line selected
3813
	 *	@param  int	    	$dateSelector      	1=Show also date range input fields
3814
	 *	@return	void
3815
	 */
3816
	function printObjectLines($action, $seller, $buyer, $selected=0, $dateSelector=0)
3817
	{
3818
		global $conf, $hookmanager, $langs, $user;
3819
		// TODO We should not use global var for this !
3820
		global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax;
3821
3822
		// Define usemargins
3823
		$usemargins=0;
3824
		if (! empty($conf->margin->enabled) && ! empty($this->element) && in_array($this->element,array('facture','propal','commande'))) $usemargins=1;
3825
3826
		$num = count($this->lines);
3827
3828
		// Line extrafield
3829
		require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3830
		$extrafieldsline = new ExtraFields($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3831
		$extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3832
3833
		$parameters = array('num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $i seems to be never defined.
Loading history...
3834
		$reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3835
		if (empty($reshook))
3836
		{
3837
			// Title line
3838
		    print "<thead>\n";
3839
3840
			print '<tr class="liste_titre nodrag nodrop">';
3841
3842
			// Adds a line numbering column
3843
			if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) print '<td class="linecolnum" align="center" width="5">&nbsp;</td>';
3844
3845
			// Description
3846
			print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
3847
3848
			if ($this->element == 'supplier_proposal' || $this->element == 'order_supplier' || $this->element == 'invoice_supplier')
3849
			{
3850
				print '<td class="linerefsupplier"><span id="title_fourn_ref">'.$langs->trans("SupplierRef").'</span></td>';
3851
			}
3852
3853
			// VAT
3854
			print '<td class="linecolvat" align="right" width="80">'.$langs->trans('VAT').'</td>';
3855
3856
			// Price HT
3857
			print '<td class="linecoluht" align="right" width="80">'.$langs->trans('PriceUHT').'</td>';
3858
3859
			// Multicurrency
3860
			if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) print '<td class="linecoluht_currency" align="right" width="80">'.$langs->trans('PriceUHTCurrency', $this->multicurrency_code).'</td>';
3861
3862
			if ($inputalsopricewithtax) print '<td align="right" width="80">'.$langs->trans('PriceUTTC').'</td>';
3863
3864
			// Qty
3865
			print '<td class="linecolqty" align="right">'.$langs->trans('Qty').'</td>';
3866
3867
			if($conf->global->PRODUCT_USE_UNITS)
3868
			{
3869
				print '<td class="linecoluseunit" align="left">'.$langs->trans('Unit').'</td>';
3870
			}
3871
3872
			// Reduction short
3873
			print '<td class="linecoldiscount" align="right">'.$langs->trans('ReductionShort').'</td>';
3874
3875
			if ($this->situation_cycle_ref) {
0 ignored issues
show
Bug Best Practice introduced by
The property situation_cycle_ref does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3876
				print '<td class="linecolcycleref" align="right">' . $langs->trans('Progress') . '</td>';
3877
			}
3878
3879
			if ($usemargins && ! empty($conf->margin->enabled) && empty($user->societe_id))
3880
			{
3881
				if (!empty($user->rights->margins->creer))
3882
				{
3883
					if ($conf->global->MARGIN_TYPE == "1")
3884
						print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('BuyingPrice').'</td>';
3885
					else
3886
						print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('CostPrice').'</td>';
3887
				}
3888
3889
				if (! empty($conf->global->DISPLAY_MARGIN_RATES) && $user->rights->margins->liretous)
3890
					print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarginRate').'</td>';
3891
				if (! empty($conf->global->DISPLAY_MARK_RATES) && $user->rights->margins->liretous)
3892
					print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarkRate').'</td>';
3893
			}
3894
3895
			// Total HT
3896
			print '<td class="linecolht" align="right">'.$langs->trans('TotalHTShort').'</td>';
3897
3898
			// Multicurrency
3899
			if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) print '<td class="linecoltotalht_currency" align="right">'.$langs->trans('TotalHTShortCurrency', $this->multicurrency_code).'</td>';
3900
3901
			if ($outputalsopricetotalwithtax) print '<td align="right" width="80">'.$langs->trans('TotalTTCShort').'</td>';
3902
3903
			print '<td class="linecoledit"></td>';  // No width to allow autodim
3904
3905
			print '<td class="linecoldelete" width="10"></td>';
3906
3907
			print '<td class="linecolmove" width="10"></td>';
3908
3909
			if($action == 'selectlines')
3910
			{
3911
			    print '<td class="linecolcheckall" align="center">';
3912
			    print '<input type="checkbox" class="linecheckboxtoggle" />';
3913
			    print '<script type="text/javascript">$(document).ready(function() {$(".linecheckboxtoggle").click(function() {var checkBoxes = $(".linecheckbox");checkBoxes.prop("checked", this.checked);})});</script>';
3914
			    print '</td>';
3915
			}
3916
3917
			print "</tr>\n";
3918
			print "</thead>\n";
3919
		}
3920
3921
		$var = true;
3922
		$i	 = 0;
3923
3924
		print "<tbody>\n";
3925
		foreach ($this->lines as $line)
3926
		{
3927
			//Line extrafield
3928
			$line->fetch_optionals();
3929
3930
			//if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
3931
			if (is_object($hookmanager))   // Old code is commented on preceding line.
3932
			{
3933
				if (empty($line->fk_parent_line))
3934
				{
3935
					$parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3936
					$reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3937
				}
3938
				else
3939
				{
3940
					$parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline, 'fk_parent_line'=>$line->fk_parent_line);
3941
					$reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3942
				}
3943
			}
3944
			if (empty($reshook))
3945
			{
3946
				$this->printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected,$extrafieldsline);
3947
			}
3948
3949
			$i++;
3950
		}
3951
		print "</tbody>\n";
3952
	}
3953
3954
	/**
3955
	 *	Return HTML content of a detail line
3956
	 *	TODO Move this into an output class file (htmlline.class.php)
3957
	 *
3958
	 *	@param	string		$action				GET/POST action
3959
	 *	@param CommonObjectLine $line		       	Selected object line to output
0 ignored issues
show
Bug introduced by
The type Alixar\Base\CommonObjectLine was not found. Did you mean CommonObjectLine? If so, make sure to prefix the type with \.
Loading history...
3960
	 *	@param  string	    $var               	Is it a an odd line (true)
3961
	 *	@param  int		    $num               	Number of line (0)
3962
	 *	@param  int		    $i					I
3963
	 *	@param  int		    $dateSelector      	1=Show also date range input fields
3964
	 *	@param  string	    $seller            	Object of seller third party
3965
	 *	@param  string	    $buyer             	Object of buyer third party
3966
	 *	@param	int			$selected		   	Object line selected
3967
	 *  @param  int			$extrafieldsline	Object of extrafield line attribute
3968
	 *	@return	void
3969
	 */
3970
	function printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected=0,$extrafieldsline=0)
3971
	{
3972
		global $conf,$langs,$user,$object,$hookmanager;
3973
		global $form,$bc,$bcdd;
3974
		global $object_rights, $disableedit, $disablemove, $disableremove;   // TODO We should not use global var for this !
3975
3976
		$object_rights = $this->getRights();
3977
3978
		$element=$this->element;
3979
3980
		$text=''; $description=''; $type=0;
3981
3982
		// Show product and description
3983
		$type=(! empty($line->product_type)?$line->product_type:$line->fk_product_type);
3984
		// Try to enhance type detection using date_start and date_end for free lines where type was not saved.
3985
		if (! empty($line->date_start)) $type=1; // deprecated
3986
		if (! empty($line->date_end)) $type=1; // deprecated
3987
3988
		// Ligne en mode visu
3989
		if ($action != 'editline' || $selected != $line->id)
3990
		{
3991
			// Product
3992
			if ($line->fk_product > 0)
3993
			{
3994
				$product_static = new Product($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
3995
				$product_static->fetch($line->fk_product);
3996
3997
				$product_static->ref = $line->ref; //can change ref in hook
3998
				$product_static->label = $line->label; //can change label in hook
3999
				$text=$product_static->getNomUrl(1);
4000
4001
				// Define output language and label
4002
				if (! empty($conf->global->MAIN_MULTILANGS))
4003
				{
4004
					if (! is_object($this->thirdparty))
4005
					{
4006
						dol_print_error('','Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before');
4007
						return;
4008
					}
4009
4010
					$prod = new Product($this->db);
4011
					$prod->fetch($line->fk_product);
4012
4013
					$outputlangs = $langs;
4014
					$newlang='';
4015
					if (empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09');
4016
					if (! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && empty($newlang)) $newlang=$this->thirdparty->default_lang;		// For language to language of customer
4017
					if (! empty($newlang))
4018
					{
4019
						$outputlangs = new Translate("",$conf);
4020
						$outputlangs->setDefaultLang($newlang);
4021
					}
4022
4023
					$label = (! empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $line->product_label;
4024
				}
4025
				else
4026
				{
4027
					$label = $line->product_label;
4028
				}
4029
4030
				$text.= ' - '.(! empty($line->label)?$line->label:$label);
4031
				$description.=(! empty($conf->global->PRODUIT_DESC_IN_FORM)?'':dol_htmlentitiesbr($line->description));	// Description is what to show on popup. We shown nothing if already into desc.
4032
			}
4033
4034
			$line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
4035
4036
			// Output template part (modules that overwrite templates must declare this into descriptor)
4037
			// Use global variables + $dateSelector + $seller and $buyer
4038
			$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4039
			foreach($dirtpls as $reldir)
4040
			{
4041
				$tpl = dol_buildpath($reldir.'/objectline_view.tpl.php');
4042
				if (empty($conf->file->strict_mode)) {
4043
					$res=@include $tpl;
4044
				} else {
4045
					$res=include $tpl; // for debug
4046
				}
4047
				if ($res) break;
4048
			}
4049
		}
4050
4051
		// Ligne en mode update
4052
		if ($this->statut == 0 && $action == 'editline' && $selected == $line->id)
4053
		{
4054
			$label = (! empty($line->label) ? $line->label : (($line->fk_product > 0) ? $line->product_label : ''));
4055
			$placeholder=' placeholder="'.$langs->trans("Label").'"';
4056
4057
			$line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
4058
4059
			// Output template part (modules that overwrite templates must declare this into descriptor)
4060
			// Use global variables + $dateSelector + $seller and $buyer
4061
			$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4062
			foreach($dirtpls as $reldir)
4063
			{
4064
				$tpl = dol_buildpath($reldir.'/objectline_edit.tpl.php');
4065
				if (empty($conf->file->strict_mode)) {
4066
					$res=@include $tpl;
4067
				} else {
4068
					$res=include $tpl; // for debug
4069
				}
4070
				if ($res) break;
4071
			}
4072
		}
4073
	}
4074
4075
4076
	/* This is to show array of line of details of source object */
4077
4078
4079
	/**
4080
	 * 	Return HTML table table of source object lines
4081
	 *  TODO Move this and previous function into output html class file (htmlline.class.php).
4082
	 *  If lines are into a template, title must also be into a template
4083
	 *  But for the moment we don't know if it's possible, so we keep the method available on overloaded objects.
4084
	 *
4085
	 *	@param	string		$restrictlist		''=All lines, 'services'=Restrict to services only
4086
	 *  @return	void
4087
	 */
4088
	function printOriginLinesList($restrictlist='')
4089
	{
4090
		global $langs, $hookmanager, $conf;
4091
4092
		print '<tr class="liste_titre">';
4093
		print '<td>'.$langs->trans('Ref').'</td>';
4094
		print '<td>'.$langs->trans('Description').'</td>';
4095
		print '<td align="right">'.$langs->trans('VATRate').'</td>';
4096
		print '<td align="right">'.$langs->trans('PriceUHT').'</td>';
4097
		if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$langs->trans('PriceUHTCurrency').'</td>';
4098
		print '<td align="right">'.$langs->trans('Qty').'</td>';
4099
		if($conf->global->PRODUCT_USE_UNITS)
4100
		{
4101
			print '<td align="left">'.$langs->trans('Unit').'</td>';
4102
		}
4103
		print '<td align="right">'.$langs->trans('ReductionShort').'</td></tr>';
4104
4105
		$var = true;
4106
		$i	 = 0;
4107
4108
		if (! empty($this->lines))
4109
		{
4110
			foreach ($this->lines as $line)
4111
			{
4112
				if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
4113
				{
4114
					if (empty($line->fk_parent_line))
4115
					{
4116
						$parameters=array('line'=>$line,'var'=>$var,'i'=>$i);
4117
						$action='';
4118
						$hookmanager->executeHooks('printOriginObjectLine',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
4119
					}
4120
				}
4121
				else
4122
				{
4123
					$this->printOriginLine($line, $var, $restrictlist);
4124
				}
4125
4126
				$i++;
4127
			}
4128
		}
4129
	}
4130
4131
	/**
4132
	 * 	Return HTML with a line of table array of source object lines
4133
	 *  TODO Move this and previous function into output html class file (htmlline.class.php).
4134
	 *  If lines are into a template, title must also be into a template
4135
	 *  But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
4136
	 *
4137
	 * 	@param	CommonObjectLine	$line				Line
4138
	 * 	@param	string				$var				Var
4139
	 *	@param	string				$restrictlist		''=All lines, 'services'=Restrict to services only (strike line if not)
4140
	 * 	@return	void
4141
	 */
4142
	function printOriginLine($line, $var, $restrictlist='')
4143
	{
4144
		global $langs, $conf;
4145
4146
		//var_dump($line);
4147
		if (!empty($line->date_start))
4148
		{
4149
			$date_start=$line->date_start;
4150
		}
4151
		else
4152
		{
4153
			$date_start=$line->date_debut_prevue;
4154
			if ($line->date_debut_reel) $date_start=$line->date_debut_reel;
4155
		}
4156
		if (!empty($line->date_end))
4157
		{
4158
			$date_end=$line->date_end;
4159
		}
4160
		else
4161
		{
4162
			$date_end=$line->date_fin_prevue;
4163
			if ($line->date_fin_reel) $date_end=$line->date_fin_reel;
4164
		}
4165
4166
		$this->tpl['label'] = '';
4167
		if (! empty($line->fk_parent_line)) $this->tpl['label'].= img_picto('', 'rightarrow');
4168
4169
		if (($line->info_bits & 2) == 2)  // TODO Not sure this is used for source object
4170
		{
4171
			$discount=new DiscountAbsolute($this->db);
0 ignored issues
show
Bug introduced by
The type Alixar\Base\DiscountAbsolute was not found. Did you mean DiscountAbsolute? If so, make sure to prefix the type with \.
Loading history...
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
4172
			$discount->fk_soc = $this->socid;
4173
			$this->tpl['label'].= $discount->getNomUrl(0,'discount');
4174
		}
4175
		else if (! empty($line->fk_product))
4176
		{
4177
			$productstatic = new Product($this->db);
4178
			$productstatic->id = $line->fk_product;
4179
			$productstatic->ref = $line->ref;
4180
			$productstatic->type = $line->fk_product_type;
4181
            if(empty($productstatic->ref)){
4182
				$line->fetch_product();
4183
				$productstatic = $line->product;
4184
			}
4185
			
4186
			$this->tpl['label'].= $productstatic->getNomUrl(1);
4187
			$this->tpl['label'].= ' - '.(! empty($line->label)?$line->label:$line->product_label);
4188
			// Dates
4189
			if ($line->product_type == 1 && ($date_start || $date_end))
4190
			{
4191
				$this->tpl['label'].= get_date_range($date_start,$date_end);
4192
			}
4193
		}
4194
		else
4195
		{
4196
			$this->tpl['label'].= ($line->product_type == -1 ? '&nbsp;' : ($line->product_type == 1 ? img_object($langs->trans(''),'service') : img_object($langs->trans(''),'product')));
4197
			if (!empty($line->desc)) {
4198
				$this->tpl['label'].=$line->desc;
4199
			}else {
4200
				$this->tpl['label'].= ($line->label ? '&nbsp;'.$line->label : '');
4201
			}
4202
			
4203
			// Dates
4204
			if ($line->product_type == 1 && ($date_start || $date_end))
4205
			{
4206
				$this->tpl['label'].= get_date_range($date_start,$date_end);
4207
			}
4208
		}
4209
4210
		if (! empty($line->desc))
4211
		{
4212
			if ($line->desc == '(CREDIT_NOTE)')  // TODO Not sure this is used for source object
4213
			{
4214
				$discount=new DiscountAbsolute($this->db);
4215
				$discount->fetch($line->fk_remise_except);
4216
				$this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote",$discount->getNomUrl(0));
4217
			}
4218
			elseif ($line->desc == '(DEPOSIT)')  // TODO Not sure this is used for source object
4219
			{
4220
				$discount=new DiscountAbsolute($this->db);
4221
				$discount->fetch($line->fk_remise_except);
4222
				$this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit",$discount->getNomUrl(0));
4223
			}
4224
			elseif ($line->desc == '(EXCESS RECEIVED)')
4225
			{
4226
				$discount=new DiscountAbsolute($this->db);
4227
				$discount->fetch($line->fk_remise_except);
4228
				$this->tpl['description'] = $langs->transnoentities("DiscountFromExcessReceived",$discount->getNomUrl(0));
4229
			}
4230
			elseif ($line->desc == '(EXCESS PAID)')
4231
			{
4232
				$discount=new DiscountAbsolute($this->db);
4233
				$discount->fetch($line->fk_remise_except);
4234
				$this->tpl['description'] = $langs->transnoentities("DiscountFromExcessPaid",$discount->getNomUrl(0));
4235
			}
4236
			else
4237
			{
4238
				$this->tpl['description'] = dol_trunc($line->desc,60);
4239
			}
4240
		}
4241
		else
4242
		{
4243
			$this->tpl['description'] = '&nbsp;';
4244
		}
4245
4246
        // VAT Rate
4247
        $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
4248
        $this->tpl['vat_rate'] .= (($line->info_bits & 1) == 1) ? '*' : '';
4249
        if (! empty($line->vat_src_code) && ! preg_match('/\(/', $this->tpl['vat_rate'])) $this->tpl['vat_rate'].=' ('.$line->vat_src_code.')';
4250
4251
		$this->tpl['price'] = price($line->subprice);
4252
		$this->tpl['multicurrency_price'] = price($line->multicurrency_subprice);
4253
		$this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : '&nbsp;';
4254
		if ($conf->global->PRODUCT_USE_UNITS) $this->tpl['unit'] = $langs->transnoentities($line->getLabelOfUnit('long'));
4255
		$this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : '&nbsp;';
4256
4257
		// Is the line strike or not
4258
		$this->tpl['strike']=0;
4259
		if ($restrictlist == 'services' && $line->product_type != Product::TYPE_SERVICE) $this->tpl['strike']=1;
4260
4261
		// Output template part (modules that overwrite templates must declare this into descriptor)
4262
		// Use global variables + $dateSelector + $seller and $buyer
4263
		$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4264
		foreach($dirtpls as $reldir)
4265
		{
4266
			$tpl = dol_buildpath($reldir.'/originproductline.tpl.php');
4267
			if (empty($conf->file->strict_mode)) {
4268
				$res=@include $tpl;
4269
			} else {
4270
				$res=include $tpl; // for debug
4271
			}
4272
			if ($res) break;
4273
		}
4274
	}
4275
4276
4277
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4278
	/**
4279
	 *	Add resources to the current object : add entry into llx_element_resources
4280
	 *	Need $this->element & $this->id
4281
	 *
4282
	 *	@param		int		$resource_id		Resource id
4283
	 *	@param		string	$resource_type		'resource'
4284
	 *	@param		int		$busy				Busy or not
4285
	 *	@param		int		$mandatory			Mandatory or not
4286
	 *	@return		int							<=0 if KO, >0 if OK
4287
	 */
4288
	function add_element_resource($resource_id, $resource_type, $busy=0, $mandatory=0)
4289
	{
4290
        // phpcs:enable
4291
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
4292
4293
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."element_resources (";
4294
		$sql.= "resource_id";
4295
		$sql.= ", resource_type";
4296
		$sql.= ", element_id";
4297
		$sql.= ", element_type";
4298
		$sql.= ", busy";
4299
		$sql.= ", mandatory";
4300
		$sql.= ") VALUES (";
4301
		$sql.= $resource_id;
4302
		$sql.= ", '".$this->db->escape($resource_type)."'";
4303
		$sql.= ", '".$this->db->escape($this->id)."'";
4304
		$sql.= ", '".$this->db->escape($this->element)."'";
4305
		$sql.= ", '".$this->db->escape($busy)."'";
4306
		$sql.= ", '".$this->db->escape($mandatory)."'";
4307
		$sql.= ")";
4308
4309
		dol_syslog(get_class($this)."::add_element_resource", LOG_DEBUG);
4310
		if ($this->db->query($sql))
4311
		{
4312
			$this->db->commit();
4313
			return 1;
4314
		}
4315
		else
4316
		{
4317
			$this->error=$this->db->lasterror();
4318
			$this->db->rollback();
4319
			return  0;
4320
		}
4321
	}
4322
4323
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4324
	/**
4325
	 *    Delete a link to resource line
4326
	 *
4327
	 *    @param	int		$rowid			Id of resource line to delete
4328
	 *    @param	int		$element		element name (for trigger) TODO: use $this->element into commonobject class
4329
	 *    @param	int		$notrigger		Disable all triggers
4330
	 *    @return   int						>0 if OK, <0 if KO
4331
	 */
4332
	function delete_resource($rowid, $element, $notrigger=0)
4333
	{
4334
        // phpcs:enable
4335
		global $user;
4336
4337
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
4338
4339
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_resources";
4340
		$sql.= " WHERE rowid=".$rowid;
4341
4342
		dol_syslog(get_class($this)."::delete_resource", LOG_DEBUG);
4343
4344
		$resql=$this->db->query($sql);
4345
		if (! $resql)
4346
		{
4347
			$this->error=$this->db->lasterror();
4348
			$this->db->rollback();
4349
			return -1;
4350
		}
4351
		else
4352
		{
4353
			if (! $notrigger)
4354
			{
4355
				$result=$this->call_trigger(strtoupper($element).'_DELETE_RESOURCE', $user);
4356
				if ($result < 0) { $this->db->rollback(); return -1; }
4357
			}
4358
			$this->db->commit();
4359
			return 1;
4360
		}
4361
	}
4362
4363
4364
	/**
4365
	 * Overwrite magic function to solve problem of cloning object that are kept as references
4366
	 *
4367
	 * @return void
4368
	 */
4369
	function __clone()
4370
	{
4371
		// Force a copy of this->lines, otherwise it will point to same object.
4372
		if (isset($this->lines) && is_array($this->lines))
4373
		{
4374
			$nboflines=count($this->lines);
4375
			for($i=0; $i < $nboflines; $i++)
4376
			{
4377
				$this->lines[$i] = clone $this->lines[$i];
4378
			}
4379
		}
4380
	}
4381
4382
	/**
4383
	 * Common function for all objects extending CommonObject for generating documents
4384
	 *
4385
	 * @param 	string 		$modelspath 	Relative folder where generators are placed
4386
	 * @param 	string 		$modele 		Generator to use. Caller must set it to obj->modelpdf or GETPOST('modelpdf') for example.
4387
	 * @param 	Translate 	$outputlangs 	Output language to use
4388
	 * @param 	int 		$hidedetails 	1 to hide details. 0 by default
4389
	 * @param 	int 		$hidedesc 		1 to hide product description. 0 by default
4390
	 * @param 	int 		$hideref 		1 to hide product reference. 0 by default
4391
	 * @param   null|array  $moreparams     Array to provide more information
4392
	 * @return 	int 						>0 if OK, <0 if KO
4393
	 * @see	addFileIntoDatabaseIndex
4394
	 */
4395
	protected function commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
4396
	{
4397
		global $conf, $langs, $user;
4398
4399
		$srctemplatepath='';
4400
4401
		// Increase limit for PDF build
4402
		$err=error_reporting();
4403
		error_reporting(0);
4404
		@set_time_limit(120);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for set_time_limit(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

4404
		/** @scrutinizer ignore-unhandled */ @set_time_limit(120);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
4405
		error_reporting($err);
4406
4407
		// If selected model is a filename template (then $modele="modelname" or "modelname:filename")
4408
		$tmp=explode(':',$modele,2);
4409
		if (! empty($tmp[1]))
4410
		{
4411
			$modele=$tmp[0];
4412
			$srctemplatepath=$tmp[1];
4413
		}
4414
4415
		// Search template files
4416
		$file=''; $classname=''; $filefound=0;
4417
		$dirmodels=array('/');
4418
		if (is_array($conf->modules_parts['models'])) $dirmodels=array_merge($dirmodels,$conf->modules_parts['models']);
4419
		foreach($dirmodels as $reldir)
4420
		{
4421
			foreach(array('doc','pdf') as $prefix)
4422
			{
4423
				if (in_array(get_class($this), array('Adherent'))) $file = $prefix."_".$modele.".class.php";     // Member module use prefix_module.class.php
4424
				else $file = $prefix."_".$modele.".modules.php";
4425
4426
				// On verifie l'emplacement du modele
4427
				$file=dol_buildpath($reldir.$modelspath.$file,0);
4428
				if (file_exists($file))
4429
				{
4430
					$filefound=1;
4431
					$classname=$prefix.'_'.$modele;
4432
					break;
4433
				}
4434
			}
4435
			if ($filefound) break;
4436
		}
4437
4438
		// If generator was found
4439
		if ($filefound)
4440
		{
4441
			global $db;  // Required to solve a conception default in commonstickergenerator.class.php making an include of code using $db
4442
4443
			require_once $file;
4444
4445
			$obj = new $classname($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
4446
4447
			// If generator is ODT, we must have srctemplatepath defined, if not we set it.
4448
			if ($obj->type == 'odt' && empty($srctemplatepath))
4449
			{
4450
				$varfortemplatedir=$obj->scandir;
4451
				if ($varfortemplatedir && ! empty($conf->global->$varfortemplatedir))
4452
				{
4453
					$dirtoscan=$conf->global->$varfortemplatedir;
4454
4455
					$listoffiles=array();
4456
4457
					// Now we add first model found in directories scanned
4458
					$listofdir=explode(',',$dirtoscan);
4459
					foreach($listofdir as $key => $tmpdir)
4460
					{
4461
						$tmpdir=trim($tmpdir);
4462
						$tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir);
4463
						if (! $tmpdir) { unset($listofdir[$key]); continue; }
4464
						if (is_dir($tmpdir))
4465
						{
4466
							$tmpfiles=dol_dir_list($tmpdir,'files',0,'\.od(s|t)$','','name',SORT_ASC,0);
4467
							if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles);
4468
						}
4469
					}
4470
4471
					if (count($listoffiles))
4472
					{
4473
						foreach($listoffiles as $record)
4474
						{
4475
							$srctemplatepath=$record['fullname'];
4476
							break;
4477
						}
4478
					}
4479
				}
4480
4481
				if (empty($srctemplatepath))
4482
				{
4483
					$this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotDefined';
4484
					return -1;
4485
				}
4486
			}
4487
4488
			if ($obj->type == 'odt' && ! empty($srctemplatepath))
4489
			{
4490
				if (! dol_is_file($srctemplatepath))
4491
				{
4492
					$this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotFound';
4493
					return -1;
4494
				}
4495
			}
4496
4497
			// We save charset_output to restore it because write_file can change it if needed for
4498
			// output format that does not support UTF8.
4499
			$sav_charset_output=$outputlangs->charset_output;
4500
4501
			if (in_array(get_class($this), array('Adherent')))
4502
			{
4503
				$arrayofrecords = array();   // The write_file of templates of adherent class need this var
4504
				$resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, $moreparams);
4505
			}
4506
			else
4507
			{
4508
				$resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams);
4509
			}
4510
			// After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index.
4511
4512
			if ($resultwritefile > 0)
4513
			{
4514
				$outputlangs->charset_output=$sav_charset_output;
4515
4516
				// We delete old preview
4517
				require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
4518
				dol_delete_preview($this);
4519
4520
				// Index file in database
4521
				if (! empty($obj->result['fullpath']))
4522
				{
4523
					$destfull = $obj->result['fullpath'];
4524
					$upload_dir = dirname($destfull);
4525
					$destfile = basename($destfull);
4526
					$rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $upload_dir);
4527
4528
					if (! preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir))     // If not a tmp dir
4529
					{
4530
						$filename = basename($destfile);
4531
						$rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
4532
						$rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
4533
4534
						include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
4535
						$ecmfile=new EcmFiles($this->db);
4536
						$result = $ecmfile->fetch(0, '', ($rel_dir?$rel_dir.'/':'').$filename);
4537
4538
						// Set the public "share" key
4539
						$setsharekey = false;
4540
						if ($this->element == 'propal')
4541
						{
4542
							$useonlinesignature = $conf->global->MAIN_FEATURES_LEVEL;	// Replace this with 1 when feature to make online signature is ok
4543
							if ($useonlinesignature) $setsharekey=true;
4544
							if (! empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4545
						}
4546
						if ($this->element == 'commande'     && ! empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD))        $setsharekey=true;
4547
						if ($this->element == 'facture'      && ! empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD))      $setsharekey=true;
4548
						if ($this->element == 'bank_account' && ! empty($conf->global->BANK_ACCOUNT_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4549
4550
						if ($setsharekey)
4551
						{
4552
							if (empty($ecmfile->share))	// Because object not found or share not set yet
4553
							{
4554
								require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
4555
								$ecmfile->share = getRandomPassword(true);
4556
							}
4557
						}
4558
4559
						if ($result > 0)
4560
						{
4561
							$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
4562
							$ecmfile->fullpath_orig = '';
4563
							$ecmfile->gen_or_uploaded = 'generated';
4564
							$ecmfile->description = '';    // indexed content
4565
							$ecmfile->keyword = '';        // keyword content
4566
							$result = $ecmfile->update($user);
4567
							if ($result < 0)
4568
							{
4569
								setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4570
							}
4571
						}
4572
						else
4573
						{
4574
							$ecmfile->entity = $conf->entity;
4575
							$ecmfile->filepath = $rel_dir;
4576
							$ecmfile->filename = $filename;
4577
							$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
4578
							$ecmfile->fullpath_orig = '';
4579
							$ecmfile->gen_or_uploaded = 'generated';
4580
							$ecmfile->description = '';    // indexed content
4581
							$ecmfile->keyword = '';        // keyword content
4582
							$ecmfile->src_object_type = $this->table_element;
4583
							$ecmfile->src_object_id   = $this->id;
4584
4585
							$result = $ecmfile->create($user);
4586
							if ($result < 0)
4587
							{
4588
								setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4589
							}
4590
						}
4591
4592
						/*$this->result['fullname']=$destfull;
4593
						$this->result['filepath']=$ecmfile->filepath;
4594
						$this->result['filename']=$ecmfile->filename;*/
4595
						//var_dump($obj->update_main_doc_field);exit;
4596
4597
						// Update the last_main_doc field into main object (if documenent generator has property ->update_main_doc_field set)
4598
						$update_main_doc_field=0;
4599
						if (! empty($obj->update_main_doc_field)) $update_main_doc_field=1;
4600
						if ($update_main_doc_field && ! empty($this->table_element))
4601
						{
4602
							$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET last_main_doc = '".($ecmfile->filepath.'/'.$ecmfile->filename)."'";
4603
							$sql.= ' WHERE rowid = '.$this->id;
4604
							$resql = $this->db->query($sql);
4605
							if (! $resql) dol_print_error($this->db);
4606
						}
4607
					}
4608
				}
4609
				else
4610
				{
4611
					dol_syslog('Method ->write_file was called on object '.get_class($obj).' and return a success but the return array ->result["fullpath"] was not set.', LOG_WARNING);
4612
				}
4613
4614
				// Success in building document. We build meta file.
4615
				dol_meta_create($this);
4616
4617
				return 1;
4618
			}
4619
			else
4620
			{
4621
				$outputlangs->charset_output=$sav_charset_output;
4622
				dol_print_error($this->db, "Error generating document for ".__CLASS__.". Error: ".$obj->error, $obj->errors);
4623
				return -1;
4624
			}
4625
		}
4626
		else
4627
		{
4628
			$this->error=$langs->trans("Error")." ".$langs->trans("ErrorFileDoesNotExists",$file);
4629
			dol_print_error('',$this->error);
4630
			return -1;
4631
		}
4632
	}
4633
4634
	/**
4635
	 *  Build thumb
4636
	 *  @TODO Move this into files.lib.php
4637
	 *
4638
	 *  @param      string	$file           Path file in UTF8 to original file to create thumbs from.
4639
	 *	@return		void
4640
	 */
4641
	function addThumbs($file)
4642
	{
4643
		global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini, $quality;
4644
4645
		require_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';		// This define also $maxwidthsmall, $quality, ...
4646
4647
		$file_osencoded=dol_osencode($file);
4648
		if (file_exists($file_osencoded))
4649
		{
4650
			// Create small thumbs for company (Ratio is near 16/9)
4651
			// Used on logon for example
4652
			vignette($file_osencoded, $maxwidthsmall, $maxheightsmall, '_small', $quality);
4653
4654
			// Create mini thumbs for company (Ratio is near 16/9)
4655
			// Used on menu or for setup page for example
4656
			vignette($file_osencoded, $maxwidthmini, $maxheightmini, '_mini', $quality);
4657
		}
4658
	}
4659
4660
4661
	/* Functions common to commonobject and commonobjectline */
4662
4663
	/* For default values */
4664
4665
	/**
4666
	 * Return the default value to use for a field when showing the create form of object.
4667
	 * Return values in this order:
4668
	 * 1) If parameter is available into POST, we return it first.
4669
	 * 2) If not but an alternate value was provided as parameter of function, we return it.
4670
	 * 3) If not but a constant $conf->global->OBJECTELEMENT_FIELDNAME is set, we return it (It is better to use the dedicated table).
4671
	 * 4) Return value found into database (TODO No yet implemented)
4672
	 *
4673
	 * @param   string              $fieldname          Name of field
4674
	 * @param   string              $alternatevalue     Alternate value to use
4675
	 * @return  string|string[]                         Default value (can be an array if the GETPOST return an array)
4676
	 **/
4677
	function getDefaultCreateValueFor($fieldname, $alternatevalue=null)
4678
	{
4679
		global $conf, $_POST;
4680
4681
		// If param here has been posted, we use this value first.
4682
		if (isset($_POST[$fieldname])) return GETPOST($fieldname, 2);
4683
4684
		if (isset($alternatevalue)) return $alternatevalue;
4685
4686
		$newelement=$this->element;
4687
		if ($newelement == 'facture') $newelement='invoice';
4688
		if ($newelement == 'commande') $newelement='order';
4689
		if (empty($newelement))
4690
		{
4691
			dol_syslog("Ask a default value using common method getDefaultCreateValueForField on an object with no property ->element defined. Return empty string.", LOG_WARNING);
4692
			return '';
4693
		}
4694
4695
		$keyforfieldname=strtoupper($newelement.'_DEFAULT_'.$fieldname);
4696
		//var_dump($keyforfieldname);
4697
		if (isset($conf->global->$keyforfieldname)) return $conf->global->$keyforfieldname;
4698
4699
		// TODO Ad here a scan into table llx_overwrite_default with a filter on $this->element and $fieldname
4700
	}
4701
4702
4703
	/* For triggers */
4704
4705
4706
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4707
	/**
4708
	 * Call trigger based on this instance.
4709
	 * Some context information may also be provided into array property this->context.
4710
	 * NB:  Error from trigger are stacked in interface->errors
4711
	 * NB2: If return code of triggers are < 0, action calling trigger should cancel all transaction.
4712
	 *
4713
	 * @param   string    $trigger_name   trigger's name to execute
4714
	 * @param   User      $user           Object user
4715
	 * @return  int                       Result of run_triggers
4716
	 */
4717
	function call_trigger($trigger_name, $user)
4718
	{
4719
        // phpcs:enable
4720
		global $langs,$conf;
4721
4722
		include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
4723
		$interface=new Interfaces($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
4724
		$result=$interface->run_triggers($trigger_name,$this,$user,$langs,$conf);
4725
4726
		if ($result < 0)
4727
		{
4728
			if (!empty($this->errors))
4729
			{
4730
				$this->errors=array_unique(array_merge($this->errors,$interface->errors));   // We use array_unique because when a trigger call another trigger on same object, this->errors is added twice.
4731
			}
4732
			else
4733
			{
4734
				$this->errors=$interface->errors;
4735
			}
4736
		}
4737
		return $result;
4738
	}
4739
4740
4741
	/* Functions for extrafields */
4742
4743
4744
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4745
	/**
4746
	 *  Function to get extra fields of an object into $this->array_options
4747
	 *  This method is in most cases called by method fetch of objects but you can call it separately.
4748
	 *
4749
	 *  @param	int		$rowid			Id of line. Use the id of object if not defined. Deprecated. Function must be called without parameters.
4750
	 *  @param  array	$optionsArray   Array resulting of call of extrafields->fetch_name_optionals_label(). Deprecated. Function must be called without parameters.
4751
	 *  @return	int						<0 if error, 0 if no values of extrafield to find nor found, 1 if an attribute is found and value loaded
4752
	 */
4753
	function fetch_optionals($rowid=null, $optionsArray=null)
4754
	{
4755
        // phpcs:enable
4756
		if (empty($rowid)) $rowid=$this->id;
4757
4758
		// To avoid SQL errors. Probably not the better solution though
4759
		if (!$this->table_element) {
4760
			return 0;
4761
		}
4762
4763
		$this->array_options=array();
4764
4765
		if (! is_array($optionsArray))
4766
		{
4767
			// If $extrafields is not a known object, we initialize it. Best practice is to have $extrafields defined into card.php or list.php page.
4768
			// TODO Use of existing $extrafield is not yet ready (must mutualize code that use extrafields in form first)
4769
			// global $extrafields;
4770
			//if (! is_object($extrafields))
4771
			//{
4772
				// require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4773
            $extrafields = new ExtraFields();
4774
            //}
4775
4776
			// Load array of extrafields for elementype = $this->table_element
4777
			if (empty($extrafields->attributes[$this->table_element]['loaded']))
4778
			{
4779
				$extrafields->fetch_name_optionals_label($this->table_element);
4780
			}
4781
			$optionsArray = (! empty($extrafields->attributes[$this->table_element]['label'])?$extrafields->attributes[$this->table_element]['label']:null);
4782
		}
4783
		else
4784
		{
4785
			global $extrafields;
4786
			dol_syslog("Warning: fetch_optionals was called with param optionsArray defined when you should pass null now", LOG_WARNING);
4787
		}
4788
4789
		$table_element = $this->table_element;
4790
		if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4791
4792
		// Request to get complementary values
4793
		if (is_array($optionsArray) && count($optionsArray) > 0)
4794
		{
4795
			$sql = "SELECT rowid";
4796
			foreach ($optionsArray as $name => $label)
4797
			{
4798
				if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] != 'separate')
4799
				{
4800
					$sql.= ", ".$name;
4801
				}
4802
			}
4803
			$sql.= " FROM ".MAIN_DB_PREFIX.$table_element."_extrafields";
4804
			$sql.= " WHERE fk_object = ".$rowid;
4805
4806
			//dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG);		// Too verbose
4807
			$resql=$this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
4808
			if ($resql)
4809
			{
4810
				$this->array_options = array();
4811
				$numrows=$this->db->num_rows($resql);
4812
				if ($numrows)
4813
				{
4814
					$tab = $this->db->fetch_array($resql);
4815
4816
					foreach ($tab as $key => $value)
4817
					{
4818
						// Test fetch_array ! is_int($key) because fetch_array result is a mix table with Key as alpha and Key as int (depend db engine)
4819
						if ($key != 'rowid' && $key != 'tms' && $key != 'fk_member' && ! is_int($key))
4820
						{
4821
							// we can add this attribute to object
4822
							if (! empty($extrafields) && in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date','datetime')))
4823
							{
4824
								//var_dump($extrafields->attributes[$this->table_element]['type'][$key]);
4825
								$this->array_options["options_".$key]=$this->db->jdate($value);
4826
							}
4827
							else
4828
							{
4829
								$this->array_options["options_".$key]=$value;
4830
							}
4831
4832
							//var_dump('key '.$key.' '.$value.' type='.$extrafields->attributes[$this->table_element]['type'][$key].' '.$this->array_options["options_".$key]);
4833
						}
4834
					}
4835
				}
4836
4837
				$this->db->free($resql);
4838
4839
				if ($numrows) return $numrows;
4840
				else return 0;
4841
			}
4842
			else
4843
			{
4844
				dol_print_error($this->db);
4845
				return -1;
4846
			}
4847
		}
4848
		return 0;
4849
	}
4850
4851
	/**
4852
	 *	Delete all extra fields values for the current object.
4853
	 *
4854
	 *  @return	int		<0 if KO, >0 if OK
4855
	 */
4856
	function deleteExtraFields()
4857
	{
4858
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
4859
4860
		$table_element = $this->table_element;
4861
		if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4862
4863
		$sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
4864
		dol_syslog(get_class($this)."::deleteExtraFields delete", LOG_DEBUG);
4865
		$resql=$this->db->query($sql_del);
4866
		if (! $resql)
4867
		{
4868
			$this->error=$this->db->lasterror();
4869
			$this->db->rollback();
4870
			return -1;
4871
		}
4872
		else
4873
		{
4874
			$this->db->commit();
4875
			return 1;
4876
		}
4877
	}
4878
4879
	/**
4880
	 *	Add/Update all extra fields values for the current object.
4881
	 *  Data to describe values to insert/update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
4882
	 *  This function delete record with all extrafields and insert them again from the array $this->array_options.
4883
	 *
4884
	 *  @param	string		$trigger		If defined, call also the trigger (for example COMPANY_MODIFY)
4885
	 *  @param	User		$userused		Object user
4886
	 *  @return int 						-1=error, O=did nothing, 1=OK
4887
	 *  @see updateExtraField, setValueFrom
4888
	 */
4889
	function insertExtraFields($trigger='', $userused=null)
4890
	{
4891
		global $conf,$langs,$user;
4892
4893
		if (empty($userused)) $userused=$user;
4894
4895
		$error=0;
4896
4897
		if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0;	// For avoid conflicts if trigger used
4898
4899
		if (! empty($this->array_options))
4900
		{
4901
			// Check parameters
4902
			$langs->load('admin');
4903
			require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4904
			$extrafields = new ExtraFields($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
4905
			$target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
4906
4907
			//Eliminate copied source object extra_fields that do not exist in target object
4908
			$new_array_options=array();
4909
			foreach ($this->array_options as $key => $value) {
4910
				if (in_array(substr($key,8), array_keys($target_extrafields)))	// We remove the 'options_' from $key for test
4911
					$new_array_options[$key] = $value;
4912
				elseif (in_array($key, array_keys($target_extrafields)))		// We test on $key that does not contains the 'options_' prefix
4913
					$new_array_options['options_'.$key] = $value;
4914
			}
4915
4916
			foreach($new_array_options as $key => $value)
4917
			{
4918
			   	$attributeKey      = substr($key,8);   // Remove 'options_' prefix
4919
			   	$attributeType     = $extrafields->attributes[$this->table_element]['type'][$attributeKey];
4920
			   	$attributeLabel    = $extrafields->attributes[$this->table_element]['label'][$attributeKey];
4921
			   	$attributeParam    = $extrafields->attributes[$this->table_element]['param'][$attributeKey];
4922
			   	$attributeRequired = $extrafields->attributes[$this->table_element]['required'][$attributeKey];
4923
4924
			   	if ($attributeRequired)
4925
			   	{
4926
			   		$mandatorypb=false;
4927
			   		if ($attributeType == 'link' && $this->array_options[$key] == '-1') $mandatorypb=true;
4928
			   		if ($this->array_options[$key] === '') $mandatorypb=true;
4929
			   		if ($mandatorypb)
4930
			   		{
4931
			   			dol_syslog($this->error);
4932
			   			$this->errors[]=$langs->trans('ErrorFieldRequired', $attributeLabel);
4933
			   			return -1;
4934
			   		}
4935
			   	}
4936
4937
				//dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
4938
				//dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
4939
4940
			   	switch ($attributeType)
4941
			   	{
4942
			   		case 'int':
4943
			  			if (!is_numeric($value) && $value!='')
4944
			   			{
4945
			   				$this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4946
			   				return -1;
4947
			  			}
4948
			   			elseif ($value=='')
4949
			   			{
4950
			   				$new_array_options[$key] = null;
4951
			   			}
4952
			 			break;
4953
					case 'double':
4954
						$value = price2num($value);
4955
						if (!is_numeric($value) && $value!='')
4956
						{
4957
							dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
4958
							$this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4959
							return -1;
4960
						}
4961
						elseif ($value=='')
4962
						{
4963
							$new_array_options[$key] = null;
4964
						}
4965
						//dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
4966
						$new_array_options[$key] = $value;
4967
						break;
4968
			 		/*case 'select':	// Not required, we chosed value='0' for undefined values
4969
             			if ($value=='-1')
4970
             			{
4971
             				$this->array_options[$key] = null;
4972
             			}
4973
             			break;*/
4974
			   		case 'password':
4975
			   			$algo='';
4976
			   			if ($this->array_options[$key] != '' && is_array($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']))
4977
			   			{
4978
			   				// If there is an encryption choice, we use it to crypt data before insert
4979
			   				$tmparrays = array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']);
4980
			   				$algo=reset($tmparrays);
4981
			   				if ($algo != '')
4982
			   				{
4983
			   					//global $action;		// $action may be 'create', 'update', 'update_extras'...
4984
			   					//var_dump($action);
4985
			   					//var_dump($this->oldcopy);exit;
4986
			   					if (is_object($this->oldcopy))		// If this->oldcopy is not defined, we can't know if we change attribute or not, so we must keep value
4987
			   					{
4988
			   						//var_dump($this->oldcopy->array_options[$key]); var_dump($this->array_options[$key]);
4989
				   					if ($this->array_options[$key] == $this->oldcopy->array_options[$key])	// If old value crypted in database is same than submited new value, it means we don't change it, so we don't update.
4990
				   					{
4991
				   						$new_array_options[$key] = $this->array_options[$key];	// Value is kept
4992
				   					}
4993
									else
4994
									{
4995
										// var_dump($algo);
4996
										$newvalue = dol_hash($this->array_options[$key], $algo);
4997
										$new_array_options[$key] = $newvalue;
4998
									}
4999
			   					}
5000
			   					else
5001
			   					{
5002
			   						$new_array_options[$key] = $this->array_options[$key];	// Value is kept
5003
			   					}
5004
			   				}
5005
			   			}
5006
			   			else	// Common usage
5007
			   			{
5008
			   				$new_array_options[$key] = $this->array_options[$key];
5009
			   			}
5010
			   			break;
5011
			   		case 'price':
5012
						$new_array_options[$key] = price2num($this->array_options[$key]);
5013
						break;
5014
					case 'date':
5015
						$new_array_options[$key] = $this->db->idate($this->array_options[$key]);
5016
						break;
5017
					case 'datetime':
5018
						// If data is a string instead of a timestamp, we convert it
5019
						if (! is_int($this->array_options[$key])) {
5020
							$this->array_options[$key] = strtotime($this->array_options[$key]);
5021
						}
5022
						$new_array_options[$key] = $this->db->idate($this->array_options[$key]);
5023
						break;
5024
		   			case 'link':
5025
						$param_list=array_keys($attributeParam['options']);
5026
						// 0 : ObjectName
5027
						// 1 : classPath
5028
						$InfoFieldList = explode(":", $param_list[0]);
5029
						dol_include_once($InfoFieldList[1]);
5030
						if ($InfoFieldList[0] && class_exists($InfoFieldList[0]))
5031
						{
5032
							if ($value == '-1')	// -1 is key for no defined in combo list of objects
5033
							{
5034
								$new_array_options[$key]='';
5035
							}
5036
							elseif ($value)
5037
							{
5038
								$object = new $InfoFieldList[0]($this->db);
5039
								if (is_numeric($value)) $res=$object->fetch($value);
5040
								else $res=$object->fetch('',$value);
5041
5042
								if ($res > 0) $new_array_options[$key]=$object->id;
5043
								else
5044
								{
5045
									$this->error="Id/Ref '".$value."' for object '".$object->element."' not found";
5046
									$this->db->rollback();
5047
									return -1;
5048
								}
5049
							}
5050
						}
5051
						else
5052
						{
5053
							dol_syslog('Error bad setup of extrafield', LOG_WARNING);
5054
						}
5055
						break;
5056
			   	}
5057
			}
5058
5059
			$this->db->begin();
5060
5061
			$table_element = $this->table_element;
5062
			if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
5063
5064
			$sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
5065
			dol_syslog(get_class($this)."::insertExtraFields delete", LOG_DEBUG);
5066
			$this->db->query($sql_del);
5067
5068
			$sql = "INSERT INTO ".MAIN_DB_PREFIX.$table_element."_extrafields (fk_object";
5069
			foreach($new_array_options as $key => $value)
5070
			{
5071
				$attributeKey = substr($key,8);   // Remove 'options_' prefix
5072
				// Add field of attribut
5073
				if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator
5074
					$sql.=",".$attributeKey;
5075
			}
5076
			$sql .= ") VALUES (".$this->id;
5077
5078
			foreach($new_array_options as $key => $value)
5079
			{
5080
				$attributeKey = substr($key,8);   // Remove 'options_' prefix
5081
				// Add field of attribute
5082
				if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator)
5083
				{
5084
					if ($new_array_options[$key] != '')
5085
					{
5086
						$sql.=",'".$this->db->escape($new_array_options[$key])."'";
5087
					}
5088
					else
5089
					{
5090
						$sql.=",null";
5091
					}
5092
				}
5093
			}
5094
			$sql.=")";
5095
5096
			dol_syslog(get_class($this)."::insertExtraFields insert", LOG_DEBUG);
5097
			$resql = $this->db->query($sql);
5098
			if (! $resql)
5099
			{
5100
				$this->error=$this->db->lasterror();
5101
				$error++;
5102
			}
5103
5104
			if (! $error && $trigger)
5105
			{
5106
				// Call trigger
5107
				$this->context=array('extrafieldaddupdate'=>1);
5108
				$result=$this->call_trigger($trigger, $userused);
5109
				if ($result < 0) $error++;
5110
				// End call trigger
5111
			}
5112
5113
			if ($error)
5114
			{
5115
				$this->db->rollback();
5116
				return -1;
5117
			}
5118
			else
5119
			{
5120
				$this->db->commit();
5121
				return 1;
5122
			}
5123
		}
5124
		else return 0;
5125
	}
5126
5127
	/**
5128
	 *	Update an extra field value for the current object.
5129
	 *  Data to describe values to update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
5130
	 *
5131
	 *  @param  string      $key    		Key of the extrafield (without starting 'options_')
5132
	 *  @param	string		$trigger		If defined, call also the trigger (for example COMPANY_MODIFY)
5133
	 *  @param	User		$userused		Object user
5134
	 *  @return int                 		-1=error, O=did nothing, 1=OK
5135
	 *  @see setValueFrom, insertExtraFields
5136
	 */
5137
	function updateExtraField($key, $trigger=null, $userused=null)
5138
	{
5139
		global $conf,$langs,$user;
5140
5141
		if (empty($userused)) $userused=$user;
5142
5143
		$error=0;
5144
5145
		if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0;	// For avoid conflicts if trigger used
5146
5147
		if (! empty($this->array_options) && isset($this->array_options["options_".$key]))
5148
		{
5149
			// Check parameters
5150
			$langs->load('admin');
5151
			require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
5152
			$extrafields = new ExtraFields($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
5153
			$target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
5154
5155
			$value=$this->array_options["options_".$key];
5156
5157
			$attributeType     = $extrafields->attributes[$this->table_element]['type'][$key];
5158
			$attributeLabel    = $extrafields->attributes[$this->table_element]['label'][$key];
5159
			$attributeParam    = $extrafields->attributes[$this->table_element]['param'][$key];
5160
			$attributeRequired = $extrafields->attributes[$this->table_element]['required'][$key];
5161
5162
			//dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
5163
			//dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
5164
5165
			switch ($attributeType)
5166
			{
5167
				case 'int':
5168
					if (!is_numeric($value) && $value!='')
5169
					{
5170
						$this->errors[]=$langs->trans("ExtraFieldHasWrongValue",$attributeLabel);
5171
						return -1;
5172
					}
5173
					elseif ($value=='')
5174
					{
5175
						$this->array_options["options_".$key] = null;
5176
					}
5177
					break;
5178
				case 'double':
5179
					$value = price2num($value);
5180
					if (!is_numeric($value) && $value!='')
5181
					{
5182
						dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
5183
						$this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
5184
						return -1;
5185
					}
5186
					elseif ($value=='')
5187
					{
5188
						$this->array_options["options_".$key] = null;
5189
					}
5190
					//dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
5191
					$this->array_options["options_".$key] = $value;
5192
					break;
5193
			 	/*case 'select':	// Not required, we chosed value='0' for undefined values
5194
             		if ($value=='-1')
5195
             		{
5196
             			$this->array_options[$key] = null;
5197
             		}
5198
             		break;*/
5199
				case 'price':
5200
					$this->array_options["options_".$key] = price2num($this->array_options["options_".$key]);
5201
					break;
5202
				case 'date':
5203
					$this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
5204
					break;
5205
				case 'datetime':
5206
					$this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
5207
					break;
5208
				case 'link':
5209
					$param_list=array_keys($attributeParam['options']);
5210
					// 0 : ObjectName
5211
					// 1 : classPath
5212
					$InfoFieldList = explode(":", $param_list[0]);
5213
					dol_include_once($InfoFieldList[1]);
5214
					if ($value)
5215
					{
5216
						$object = new $InfoFieldList[0]($this->db);
5217
						$object->fetch(0,$value);
5218
						$this->array_options["options_".$key]=$object->id;
5219
					}
5220
					break;
5221
			}
5222
5223
			$this->db->begin();
5224
			$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element."_extrafields SET ".$key."='".$this->db->escape($this->array_options["options_".$key])."'";
5225
			$sql .= " WHERE fk_object = ".$this->id;
5226
			$resql = $this->db->query($sql);
5227
			if (! $resql)
5228
			{
5229
				$error++;
5230
				$this->error=$this->db->lasterror();
5231
			}
5232
5233
			if (! $error && $trigger)
5234
			{
5235
				// Call trigger
5236
				$this->context=array('extrafieldupdate'=>1);
5237
				$result=$this->call_trigger($trigger, $userused);
5238
				if ($result < 0) $error++;
5239
				// End call trigger
5240
			}
5241
5242
			if ($error)
5243
			{
5244
				dol_syslog(get_class($this) . "::".__METHOD__ . $this->error, LOG_ERR);
5245
				$this->db->rollback();
5246
				return -1;
5247
			}
5248
			else
5249
			{
5250
				$this->db->commit();
5251
				return 1;
5252
			}
5253
		}
5254
		else return 0;
5255
	}
5256
5257
5258
	/**
5259
	 * Return HTML string to put an input field into a page
5260
	 * Code very similar with showInputField of extra fields
5261
	 *
5262
	 * @param  array   		$val	       Array of properties for field to show
5263
	 * @param  string  		$key           Key of attribute
5264
	 * @param  string  		$value         Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value)
5265
	 * @param  string  		$moreparam     To add more parameters on html input tag
5266
	 * @param  string  		$keysuffix     Prefix string to add into name and id of field (can be used to avoid duplicate names)
5267
	 * @param  string  		$keyprefix     Suffix string to add into name and id of field (can be used to avoid duplicate names)
5268
	 * @param  string|int		$morecss       Value for css to define style/length of field. May also be a numeric.
5269
	 * @return string
5270
	 */
5271
	function showInputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $morecss=0)
5272
	{
5273
		global $conf,$langs,$form;
5274
5275
		if (! is_object($form))
5276
		{
5277
			require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5278
			$form=new Form($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
5279
		}
5280
5281
		$val=$this->fields[$key];
5282
5283
		$out='';
5284
        $type='';
5285
        $param = array();
5286
        $param['options']=array();
5287
        $size =$this->fields[$key]['size'];
5288
        // Because we work on extrafields
5289
        if(preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)){
5290
            $param['options']=array($reg[1].':'.$reg[2]=>'N');
5291
            $type ='link';
5292
        } elseif(preg_match('/^link:(.*):(.*)/i', $val['type'], $reg)) {
5293
            $param['options']=array($reg[1].':'.$reg[2]=>'N');
5294
            $type ='link';
5295
        } elseif(preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
5296
            $param['options']=array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4]=>'N');
5297
            $type ='sellist';
5298
        } elseif(preg_match('/varchar\((\d+)\)/', $val['type'],$reg)) {
5299
            $param['options']=array();
5300
            $type ='varchar';
5301
            $size=$reg[1];
5302
        } elseif(preg_match('/varchar/', $val['type'])) {
5303
            $param['options']=array();
5304
            $type ='varchar';
5305
        } elseif(is_array($this->fields[$key]['arrayofkeyval'])) {
5306
            $param['options']=$this->fields[$key]['arrayofkeyval'];
5307
            $type ='select';
5308
        } else {
5309
            $param['options']=array();
5310
            $type =$this->fields[$key]['type'];
5311
        }
5312
5313
		$label=$this->fields[$key]['label'];
5314
		//$elementtype=$this->fields[$key]['elementtype'];	// Seems not used
5315
		$default=$this->fields[$key]['default'];
5316
		$computed=$this->fields[$key]['computed'];
5317
		$unique=$this->fields[$key]['unique'];
5318
		$required=$this->fields[$key]['required'];
5319
5320
		$langfile=$this->fields[$key]['langfile'];
5321
		$list=$this->fields[$key]['list'];
5322
		$hidden=abs($this->fields[$key]['visible'])!=1?1:0;
5323
5324
		$objectid = $this->id;
5325
5326
5327
		if ($computed)
5328
		{
5329
			if (! preg_match('/^search_/', $keyprefix)) return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
5330
			else return '';
5331
		}
5332
5333
5334
		// Use in priority showsize from parameters, then $val['css'] then autodefine
5335
		if (empty($morecss) && ! empty($val['css']))
5336
		{
5337
			$showsize = $val['css'];
5338
		}
5339
		if (empty($morecss))
5340
		{
5341
			if ($type == 'date')
5342
			{
5343
				$morecss = 'minwidth100imp';
5344
			}
5345
			elseif ($type == 'datetime')
5346
			{
5347
				$morecss = 'minwidth200imp';
5348
			}
5349
			elseif (in_array($type,array('int','integer','price')) || preg_match('/^double(\([0-9],[0-9]\)){0,1}/',$type))
5350
			{
5351
				$morecss = 'maxwidth75';
5352
                        }elseif ($type == 'url')
5353
			{
5354
				$morecss='minwidth400';
5355
			}
5356
			elseif ($type == 'boolean')
5357
			{
5358
				$morecss='';
5359
			}
5360
			else
5361
			{
5362
				if (round($size) < 12)
5363
				{
5364
					$morecss = 'minwidth100';
5365
				}
5366
				else if (round($size) <= 48)
5367
				{
5368
					$morecss = 'minwidth200';
5369
				}
5370
				else
5371
				{
5372
					$morecss = 'minwidth400';
5373
				}
5374
			}
5375
		}
5376
5377
		if (in_array($type,array('date','datetime')))
5378
		{
5379
			$tmp=explode(',',$size);
5380
			$newsize=$tmp[0];
5381
5382
			$showtime = in_array($type,array('datetime')) ? 1 : 0;
5383
5384
			// Do not show current date when field not required (see selectDate() method)
5385
			if (!$required && $value == '') $value = '-1';
5386
5387
			// TODO Must also support $moreparam
5388
			$out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
5389
		}
5390
		elseif (in_array($type,array('int','integer')))
5391
		{
5392
			$tmp=explode(',',$size);
5393
			$newsize=$tmp[0];
5394
			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" maxlength="'.$newsize.'" value="'.dol_escape_htmltag($value).'"'.($moreparam?$moreparam:'').'>';
5395
		}
5396
		elseif (preg_match('/varchar/', $type))
5397
		{
5398
			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" maxlength="'.$size.'" value="'.dol_escape_htmltag($value).'"'.($moreparam?$moreparam:'').'>';
5399
		}
5400
		elseif (in_array($type, array('mail', 'phone', 'url')))
5401
		{
5402
			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5403
		}
5404
		elseif ($type == 'text')
5405
		{
5406
			if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
5407
			{
5408
				require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
5409
				$doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,false,ROWS_5,'90%');
0 ignored issues
show
Bug introduced by
The type Alixar\Base\DolEditor was not found. Did you mean DolEditor? If so, make sure to prefix the type with \.
Loading history...
5410
				$out=$doleditor->Create(1);
5411
			}
5412
			else
5413
			{
5414
				$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5415
			}
5416
		}
5417
		elseif ($type == 'html')
5418
		{
5419
			if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
5420
			{
5421
				require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
5422
				$doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,! empty($conf->fckeditor->enabled) && $conf->global->FCKEDITOR_ENABLE_SOCIETE,ROWS_5,'90%');
5423
				$out=$doleditor->Create(1);
5424
			}
5425
			else
5426
			{
5427
				$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5428
			}
5429
		}
5430
		elseif ($type == 'boolean')
5431
		{
5432
			$checked='';
5433
			if (!empty($value)) {
5434
				$checked=' checked value="1" ';
5435
			} else {
5436
				$checked=' value="1" ';
5437
			}
5438
			$out='<input type="checkbox" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam?$moreparam:'').'>';
5439
		}
5440
		elseif ($type == 'price')
5441
		{
5442
			if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
5443
				$value=price($value);
5444
			}
5445
			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> '.$langs->getCurrencySymbol($conf->currency);
5446
		}
5447
		elseif (preg_match('/^double(\([0-9],[0-9]\)){0,1}/',$type))
5448
		{
5449
			if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
5450
				$value=price($value);
5451
			}
5452
			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> ';
5453
		}
5454
		elseif ($type == 'select')
5455
		{
5456
			$out = '';
5457
			if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
5458
			{
5459
				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5460
				$out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
5461
			}
5462
5463
			$out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
5464
                if((! isset($this->fields[$key]['default'])) ||($this->fields[$key]['notnull']!=1))$out.='<option value="0">&nbsp;</option>';
5465
			foreach ($param['options'] as $key => $val)
0 ignored issues
show
introduced by
$val is overwriting one of the parameters of this function.
Loading history...
introduced by
$key is overwriting one of the parameters of this function.
Loading history...
5466
			{
5467
				if ((string) $key == '') continue;
5468
				list($val, $parent) = explode('|', $val);
5469
				$out.='<option value="'.$key.'"';
5470
				$out.= (((string) $value == (string) $key)?' selected':'');
5471
				$out.= (!empty($parent)?' parent="'.$parent.'"':'');
5472
				$out.='>'.$val.'</option>';
5473
			}
5474
			$out.='</select>';
5475
		}
5476
		elseif ($type == 'sellist')
5477
		{
5478
			$out = '';
5479
			if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
5480
			{
5481
				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5482
				$out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
5483
			}
5484
5485
			$out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
5486
			if (is_array($param['options']))
5487
			{
5488
				$param_list=array_keys($param['options']);
5489
				$InfoFieldList = explode(":", $param_list[0]);
5490
				$parentName='';
5491
				$parentField='';
5492
				// 0 : tableName
5493
				// 1 : label field name
5494
				// 2 : key fields name (if differ of rowid)
5495
				// 3 : key field parent (for dependent lists)
5496
				// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5497
				$keyList=(empty($InfoFieldList[2])?'rowid':$InfoFieldList[2].' as rowid');
5498
5499
5500
				if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4]))
5501
				{
5502
					if (strpos($InfoFieldList[4], 'extra.') !== false)
5503
					{
5504
						$keyList='main.'.$InfoFieldList[2].' as rowid';
5505
					} else {
5506
						$keyList=$InfoFieldList[2].' as rowid';
5507
					}
5508
				}
5509
				if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3]))
5510
				{
5511
					list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
5512
					$keyList.= ', '.$parentField;
5513
				}
5514
5515
				$fields_label = explode('|',$InfoFieldList[1]);
5516
				if (is_array($fields_label))
5517
				{
5518
					$keyList .=', ';
5519
					$keyList .= implode(', ', $fields_label);
5520
				}
5521
5522
				$sqlwhere='';
5523
				$sql = 'SELECT '.$keyList;
5524
				$sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
5525
				if (!empty($InfoFieldList[4]))
5526
				{
5527
					// can use SELECT request
5528
					if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5529
						$InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5530
					}
5531
5532
					// current object id can be use into filter
5533
					if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5534
						$InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5535
					} else {
5536
						$InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5537
					}
5538
					//We have to join on extrafield table
5539
					if (strpos($InfoFieldList[4], 'extra')!==false)
5540
					{
5541
						$sql.= ' as main, '.MAIN_DB_PREFIX .$InfoFieldList[0].'_extrafields as extra';
5542
						$sqlwhere.= ' WHERE extra.fk_object=main.'.$InfoFieldList[2]. ' AND '.$InfoFieldList[4];
5543
					}
5544
					else
5545
					{
5546
						$sqlwhere.= ' WHERE '.$InfoFieldList[4];
5547
					}
5548
				}
5549
				else
5550
				{
5551
					$sqlwhere.= ' WHERE 1=1';
5552
				}
5553
				// Some tables may have field, some other not. For the moment we disable it.
5554
				if (in_array($InfoFieldList[0],array('tablewithentity')))
5555
				{
5556
					$sqlwhere.= ' AND entity = '.$conf->entity;
5557
				}
5558
				$sql.=$sqlwhere;
5559
				//print $sql;
5560
5561
				$sql .= ' ORDER BY ' . implode(', ', $fields_label);
5562
5563
				dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
5564
				$resql = $this->db->query($sql);
5565
				if ($resql)
5566
				{
5567
					$out.='<option value="0">&nbsp;</option>';
5568
					$num = $this->db->num_rows($resql);
5569
					$i = 0;
5570
					while ($i < $num)
5571
					{
5572
						$labeltoshow='';
5573
						$obj = $this->db->fetch_object($resql);
5574
5575
						// Several field into label (eq table:code|libelle:rowid)
5576
						$notrans = false;
5577
						$fields_label = explode('|',$InfoFieldList[1]);
5578
						if (is_array($fields_label))
5579
						{
5580
							$notrans = true;
5581
							foreach ($fields_label as $field_toshow)
5582
							{
5583
								$labeltoshow.= $obj->$field_toshow.' ';
5584
							}
5585
						}
5586
						else
5587
						{
5588
							$labeltoshow=$obj->{$InfoFieldList[1]};
5589
						}
5590
						$labeltoshow=dol_trunc($labeltoshow,45);
5591
5592
						if ($value == $obj->rowid)
5593
						{
5594
							foreach ($fields_label as $field_toshow)
5595
							{
5596
								$translabel=$langs->trans($obj->$field_toshow);
5597
								if ($translabel!=$obj->$field_toshow) {
5598
									$labeltoshow=dol_trunc($translabel,18).' ';
5599
								}else {
5600
									$labeltoshow=dol_trunc($obj->$field_toshow,18).' ';
5601
								}
5602
							}
5603
							$out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5604
						}
5605
						else
5606
						{
5607
							if (! $notrans)
5608
							{
5609
								$translabel=$langs->trans($obj->{$InfoFieldList[1]});
5610
								if ($translabel!=$obj->{$InfoFieldList[1]}) {
5611
									$labeltoshow=dol_trunc($translabel,18);
5612
								}
5613
								else {
5614
									$labeltoshow=dol_trunc($obj->{$InfoFieldList[1]},18);
5615
								}
5616
							}
5617
							if (empty($labeltoshow)) $labeltoshow='(not defined)';
5618
							if ($value==$obj->rowid)
5619
							{
5620
								$out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5621
							}
5622
5623
							if (!empty($InfoFieldList[3]) && $parentField)
5624
							{
5625
								$parent = $parentName.':'.$obj->{$parentField};
5626
							}
5627
5628
							$out.='<option value="'.$obj->rowid.'"';
5629
							$out.= ($value==$obj->rowid?' selected':'');
5630
							$out.= (!empty($parent)?' parent="'.$parent.'"':'');
5631
							$out.='>'.$labeltoshow.'</option>';
5632
						}
5633
5634
						$i++;
5635
					}
5636
					$this->db->free($resql);
5637
				}
5638
				else {
5639
					print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
5640
				}
5641
			}
5642
			$out.='</select>';
5643
		}
5644
		elseif ($type == 'checkbox')
5645
		{
5646
			$value_arr=explode(',',$value);
5647
			$out=$form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options'])?null:$param['options']), $value_arr, '', 0, '', 0, '100%');
5648
		}
5649
		elseif ($type == 'radio')
5650
		{
5651
			$out='';
5652
			foreach ($param['options'] as $keyopt => $val)
0 ignored issues
show
introduced by
$val is overwriting one of the parameters of this function.
Loading history...
5653
			{
5654
				$out.='<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'');
5655
				$out.=' value="'.$keyopt.'"';
5656
				$out.=' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
5657
				$out.= ($value==$keyopt?'checked':'');
5658
				$out.='/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$val.'</label><br>';
5659
			}
5660
		}
5661
		elseif ($type == 'chkbxlst')
5662
		{
5663
			if (is_array($value)) {
5664
				$value_arr = $value;
5665
			}
5666
			else {
5667
				$value_arr = explode(',', $value);
5668
			}
5669
5670
			if (is_array($param['options'])) {
5671
				$param_list = array_keys($param['options']);
5672
				$InfoFieldList = explode(":", $param_list[0]);
5673
				$parentName='';
5674
				$parentField='';
5675
				// 0 : tableName
5676
				// 1 : label field name
5677
				// 2 : key fields name (if differ of rowid)
5678
				// 3 : key field parent (for dependent lists)
5679
				// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5680
				$keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
5681
5682
				if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3])) {
5683
					list ( $parentName, $parentField ) = explode('|', $InfoFieldList[3]);
5684
					$keyList .= ', ' . $parentField;
5685
				}
5686
				if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4])) {
5687
					if (strpos($InfoFieldList[4], 'extra.') !== false) {
5688
						$keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
5689
					} else {
5690
						$keyList = $InfoFieldList[2] . ' as rowid';
5691
					}
5692
				}
5693
5694
				$fields_label = explode('|', $InfoFieldList[1]);
5695
				if (is_array($fields_label)) {
5696
					$keyList .= ', ';
5697
					$keyList .= implode(', ', $fields_label);
5698
				}
5699
5700
				$sqlwhere = '';
5701
				$sql = 'SELECT ' . $keyList;
5702
				$sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
5703
				if (! empty($InfoFieldList[4])) {
5704
5705
					// can use SELECT request
5706
					if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5707
						$InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5708
					}
5709
5710
					// current object id can be use into filter
5711
					if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5712
						$InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5713
					} else {
5714
						$InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5715
					}
5716
5717
					// We have to join on extrafield table
5718
					if (strpos($InfoFieldList[4], 'extra') !== false) {
5719
						$sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
5720
						$sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
5721
					} else {
5722
						$sqlwhere .= ' WHERE ' . $InfoFieldList[4];
5723
					}
5724
				} else {
5725
					$sqlwhere .= ' WHERE 1=1';
5726
				}
5727
				// Some tables may have field, some other not. For the moment we disable it.
5728
				if (in_array($InfoFieldList[0], array ('tablewithentity')))
5729
				{
5730
					$sqlwhere .= ' AND entity = ' . $conf->entity;
5731
				}
5732
				// $sql.=preg_replace('/^ AND /','',$sqlwhere);
5733
				// print $sql;
5734
5735
				$sql .= $sqlwhere;
5736
				dol_syslog(get_class($this) . '::showInputField type=chkbxlst',LOG_DEBUG);
5737
				$resql = $this->db->query($sql);
5738
				if ($resql) {
5739
					$num = $this->db->num_rows($resql);
5740
					$i = 0;
5741
5742
					$data=array();
5743
5744
					while ( $i < $num ) {
5745
						$labeltoshow = '';
5746
						$obj = $this->db->fetch_object($resql);
5747
5748
						$notrans = false;
5749
						// Several field into label (eq table:code|libelle:rowid)
5750
						$fields_label = explode('|', $InfoFieldList[1]);
5751
						if (is_array($fields_label)) {
5752
							$notrans = true;
5753
							foreach ( $fields_label as $field_toshow ) {
5754
								$labeltoshow .= $obj->$field_toshow . ' ';
5755
							}
5756
						} else {
5757
							$labeltoshow = $obj->{$InfoFieldList[1]};
5758
						}
5759
						$labeltoshow = dol_trunc($labeltoshow, 45);
5760
5761
						if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5762
							foreach ( $fields_label as $field_toshow ) {
5763
								$translabel = $langs->trans($obj->$field_toshow);
5764
								if ($translabel != $obj->$field_toshow) {
5765
									$labeltoshow = dol_trunc($translabel, 18) . ' ';
5766
								} else {
5767
									$labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
5768
								}
5769
							}
5770
5771
							$data[$obj->rowid]=$labeltoshow;
5772
						} else {
5773
							if (! $notrans) {
5774
								$translabel = $langs->trans($obj->{$InfoFieldList[1]});
5775
								if ($translabel != $obj->{$InfoFieldList[1]}) {
5776
									$labeltoshow = dol_trunc($translabel, 18);
5777
								} else {
5778
									$labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
5779
								}
5780
							}
5781
							if (empty($labeltoshow))
5782
								$labeltoshow = '(not defined)';
5783
5784
								if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5785
									$data[$obj->rowid]=$labeltoshow;
5786
								}
5787
5788
								if (! empty($InfoFieldList[3]) && $parentField) {
5789
									$parent = $parentName . ':' . $obj->{$parentField};
5790
								}
5791
5792
								$data[$obj->rowid]=$labeltoshow;
5793
						}
5794
5795
						$i ++;
5796
					}
5797
					$this->db->free($resql);
5798
5799
					$out=$form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
5800
				} else {
5801
					print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
5802
				}
5803
			}
5804
		}
5805
		elseif ($type == 'link')
5806
		{
5807
			$param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
5808
			$showempty=(($required && $default != '')?0:1);
5809
			$out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty);
5810
			if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
5811
			{
5812
            			list($class,$classfile)=explode(':',$param_list[0]);
5813
            			if (file_exists(dol_buildpath(dirname(dirname($classfile)).'/card.php'))) $url_path=dol_buildpath(dirname(dirname($classfile)).'/card.php',1);
5814
            			else $url_path=dol_buildpath(dirname(dirname($classfile)).'/'.$class.'_card.php',1);
5815
            			$out.='<a class="butActionNew" href="'.$url_path.'?action=create&backtopage='.$_SERVER['PHP_SELF'].'"><span class="fa fa-plus-circle valignmiddle"></span></a>';
5816
            			// TODO Add Javascript code to add input fields contents to new elements urls
5817
			}
5818
		}
5819
		elseif ($type == 'password')
5820
		{
5821
			// If prefix is 'search_', field is used as a filter, we use a common text field.
5822
			$out='<input type="'.($keyprefix=='search_'?'text':'password').'" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'>';
5823
		}
5824
		elseif ($type == 'array')
5825
		{
5826
			$newval = $val;
5827
			$newval['type'] = 'varchar(256)';
5828
5829
			$out='';
5830
5831
			$inputs = array();
5832
			if(! empty($value)) {
5833
				foreach($value as $option) {
0 ignored issues
show
Bug introduced by
The expression $value of type string is not traversable.
Loading history...
5834
					$out.= '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
5835
					$out.= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', $option, $moreparam, '', '', $showsize).'<br></span>';
5836
				}
5837
			}
5838
5839
			$out.= '<a id="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_add" href="javascript:;"><span class="fa fa-plus-circle valignmiddle"></span></a>';
5840
5841
			$newInput = '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
5842
			$newInput.= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', '', $moreparam, '', '', $showsize).'<br></span>';
5843
5844
			if(! empty($conf->use_javascript_ajax)) {
5845
				$out.= '
5846
					<script type="text/javascript">
5847
					$(document).ready(function() {
5848
						$("a#'.dol_escape_js($keyprefix.$key.$keysuffix).'_add").click(function() {
5849
							$("'.dol_escape_js($newInput).'").insertBefore(this);
5850
						});
5851
5852
						$(document).on("click", "a.'.dol_escape_js($keyprefix.$key.$keysuffix).'_del", function() {
5853
							$(this).parent().remove();
5854
						});
5855
					});
5856
					</script>';
5857
			}
5858
		}
5859
		if (!empty($hidden)) {
5860
			$out='<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
5861
		}
5862
		/* Add comments
5863
		 if ($type == 'date') $out.=' (YYYY-MM-DD)';
5864
		 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
5865
		 */
5866
		return $out;
5867
	}
5868
5869
	/**
5870
	 * Return HTML string to show a field into a page
5871
	 * Code very similar with showOutputField of extra fields
5872
	 *
5873
	 * @param  array   $val		       Array of properties of field to show
5874
	 * @param  string  $key            Key of attribute
5875
	 * @param  string  $value          Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value)
5876
	 * @param  string  $moreparam      To add more parametes on html input tag
5877
	 * @param  string  $keysuffix      Prefix string to add into name and id of field (can be used to avoid duplicate names)
5878
	 * @param  string  $keyprefix      Suffix string to add into name and id of field (can be used to avoid duplicate names)
5879
	 * @param  mixed   $showsize       Value for css to define size. May also be a numeric.
5880
	 * @return string
5881
	 */
5882
	function showOutputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $showsize=0)
5883
	{
5884
		global $conf,$langs,$form;
5885
5886
		if (! is_object($form))
5887
		{
5888
			require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5889
			$form=new Form($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
5890
		}
5891
5892
		$objectid = $this->id;
5893
		$label = $val['label'];
5894
		$type  = $val['type'];
5895
		$size  = $val['css'];
5896
5897
		// Convert var to be able to share same code than showOutputField of extrafields
5898
		if (preg_match('/varchar\((\d+)\)/', $type, $reg))
5899
		{
5900
			$type = 'varchar';		// convert varchar(xx) int varchar
5901
			$size = $reg[1];
5902
		}
5903
		elseif (preg_match('/varchar/', $type)) $type = 'varchar';		// convert varchar(xx) int varchar
5904
		if (is_array($val['arrayofkeyval'])) $type='select';
5905
		if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) $type='link';
5906
5907
		$default=$val['default'];
5908
		$computed=$val['computed'];
5909
		$unique=$val['unique'];
5910
		$required=$val['required'];
5911
		$param=$val['param'];
5912
		if (is_array($val['arrayofkeyval'])) $param['options'] = $val['arrayofkeyval'];
5913
		if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg))
5914
		{
5915
			$type='link';
5916
			$param['options']=array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
5917
		}
5918
		$langfile=$val['langfile'];
5919
		$list=$val['list'];
5920
		$help=$val['help'];
5921
		$hidden=(($val['visible'] == 0) ? 1 : 0);			// If zero, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller)
5922
5923
		if ($hidden) return '';
5924
5925
		// If field is a computed field, value must become result of compute
5926
		if ($computed)
5927
		{
5928
			// Make the eval of compute string
5929
			//var_dump($computed);
5930
			$value = dol_eval($computed, 1, 0);
5931
		}
5932
5933
		if (empty($showsize))
5934
		{
5935
			if ($type == 'date')
5936
			{
5937
				//$showsize=10;
5938
				$showsize = 'minwidth100imp';
5939
			}
5940
			elseif ($type == 'datetime')
5941
			{
5942
				//$showsize=19;
5943
				$showsize = 'minwidth200imp';
5944
			}
5945
			elseif (in_array($type,array('int','double','price')))
5946
			{
5947
				//$showsize=10;
5948
				$showsize = 'maxwidth75';
5949
			}
5950
			elseif ($type == 'url')
5951
			{
5952
				$showsize='minwidth400';
5953
			}
5954
			elseif ($type == 'boolean')
5955
			{
5956
				$showsize='';
5957
			}
5958
			else
5959
			{
5960
				if (round($size) < 12)
5961
				{
5962
					$showsize = 'minwidth100';
5963
				}
5964
				else if (round($size) <= 48)
5965
				{
5966
					$showsize = 'minwidth200';
5967
				}
5968
				else
5969
				{
5970
					//$showsize=48;
5971
					$showsize = 'minwidth400';
5972
				}
5973
			}
5974
		}
5975
5976
		// Format output value differently according to properties of field
5977
		if ($key == 'ref' && method_exists($this, 'getNomUrl')) $value=$this->getNomUrl(1, '', 0, '', 1);
5978
		elseif ($key == 'status' && method_exists($this, 'getLibStatut')) $value=$this->getLibStatut(3);
5979
		elseif ($type == 'date')
5980
		{
5981
			if(! empty($value)) {
5982
				$value=dol_print_date($value,'day');
5983
			} else {
5984
				$value='';
5985
			}
5986
		}
5987
		elseif ($type == 'datetime')
5988
		{
5989
			if(! empty($value)) {
5990
				$value=dol_print_date($value,'dayhour');
5991
			} else {
5992
				$value='';
5993
			}
5994
		}
5995
		elseif ($type == 'double')
5996
		{
5997
			if (!empty($value)) {
5998
				$value=price($value);
5999
			}
6000
		}
6001
		elseif ($type == 'boolean')
6002
		{
6003
			$checked='';
6004
			if (!empty($value)) {
6005
				$checked=' checked ';
6006
			}
6007
			$value='<input type="checkbox" '.$checked.' '.($moreparam?$moreparam:'').' readonly disabled>';
6008
		}
6009
		elseif ($type == 'mail')
6010
		{
6011
			$value=dol_print_email($value,0,0,0,64,1,1);
6012
		}
6013
		elseif ($type == 'url')
6014
		{
6015
			$value=dol_print_url($value,'_blank',32,1);
6016
		}
6017
		elseif ($type == 'phone')
6018
		{
6019
			$value=dol_print_phone($value, '', 0, 0, '', '&nbsp;', 1);
6020
		}
6021
		elseif ($type == 'price')
6022
		{
6023
			$value=price($value,0,$langs,0,0,-1,$conf->currency);
6024
		}
6025
		elseif ($type == 'select')
6026
		{
6027
			$value=$param['options'][$value];
6028
		}
6029
		elseif ($type == 'sellist')
6030
		{
6031
			$param_list=array_keys($param['options']);
6032
			$InfoFieldList = explode(":", $param_list[0]);
6033
6034
			$selectkey="rowid";
6035
			$keyList='rowid';
6036
6037
			if (count($InfoFieldList)>=3)
6038
			{
6039
				$selectkey = $InfoFieldList[2];
6040
				$keyList=$InfoFieldList[2].' as rowid';
6041
			}
6042
6043
			$fields_label = explode('|',$InfoFieldList[1]);
6044
			if(is_array($fields_label)) {
6045
				$keyList .=', ';
6046
				$keyList .= implode(', ', $fields_label);
6047
			}
6048
6049
			$sql = 'SELECT '.$keyList;
6050
			$sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
6051
			if (strpos($InfoFieldList[4], 'extra')!==false)
6052
			{
6053
				$sql.= ' as main';
6054
			}
6055
			if ($selectkey=='rowid' && empty($value)) {
6056
				$sql.= " WHERE ".$selectkey."=0";
6057
			} elseif ($selectkey=='rowid') {
6058
				$sql.= " WHERE ".$selectkey."=".$this->db->escape($value);
6059
			}else {
6060
				$sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
6061
			}
6062
6063
			//$sql.= ' AND entity = '.$conf->entity;
6064
6065
			dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
6066
			$resql = $this->db->query($sql);
6067
			if ($resql)
6068
			{
6069
				$value='';	// value was used, so now we reste it to use it to build final output
6070
6071
				$obj = $this->db->fetch_object($resql);
6072
6073
				// Several field into label (eq table:code|libelle:rowid)
6074
				$fields_label = explode('|',$InfoFieldList[1]);
6075
6076
				if(is_array($fields_label) && count($fields_label)>1)
6077
				{
6078
					foreach ($fields_label as $field_toshow)
6079
					{
6080
						$translabel='';
6081
						if (!empty($obj->$field_toshow)) {
6082
							$translabel=$langs->trans($obj->$field_toshow);
6083
						}
6084
						if ($translabel!=$field_toshow) {
6085
							$value.=dol_trunc($translabel,18).' ';
6086
						}else {
6087
							$value.=$obj->$field_toshow.' ';
6088
						}
6089
					}
6090
				}
6091
				else
6092
				{
6093
					$translabel='';
6094
					if (!empty($obj->{$InfoFieldList[1]})) {
6095
						$translabel=$langs->trans($obj->{$InfoFieldList[1]});
6096
					}
6097
					if ($translabel!=$obj->{$InfoFieldList[1]}) {
6098
						$value=dol_trunc($translabel,18);
6099
					}else {
6100
						$value=$obj->{$InfoFieldList[1]};
6101
					}
6102
				}
6103
			}
6104
			else dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
6105
		}
6106
		elseif ($type == 'radio')
6107
		{
6108
			$value=$param['options'][$value];
6109
		}
6110
		elseif ($type == 'checkbox')
6111
		{
6112
			$value_arr=explode(',',$value);
6113
			$value='';
6114
			if (is_array($value_arr) && count($value_arr)>0)
6115
			{
6116
				foreach ($value_arr as $keyval=>$valueval) {
6117
					$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$param['options'][$valueval].'</li>';
6118
				}
6119
				$value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $toprint seems to be defined by a foreach iteration on line 6116. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
6120
			}
6121
		}
6122
		elseif ($type == 'chkbxlst')
6123
		{
6124
			$value_arr = explode(',', $value);
6125
6126
			$param_list = array_keys($param['options']);
6127
			$InfoFieldList = explode(":", $param_list[0]);
6128
6129
			$selectkey = "rowid";
6130
			$keyList = 'rowid';
6131
6132
			if (count($InfoFieldList) >= 3) {
6133
				$selectkey = $InfoFieldList[2];
6134
				$keyList = $InfoFieldList[2] . ' as rowid';
6135
			}
6136
6137
			$fields_label = explode('|', $InfoFieldList[1]);
6138
			if (is_array($fields_label)) {
6139
				$keyList .= ', ';
6140
				$keyList .= implode(', ', $fields_label);
6141
			}
6142
6143
			$sql = 'SELECT ' . $keyList;
6144
			$sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
6145
			if (strpos($InfoFieldList[4], 'extra') !== false) {
6146
				$sql .= ' as main';
6147
			}
6148
			// $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
6149
			// $sql.= ' AND entity = '.$conf->entity;
6150
6151
			dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst',LOG_DEBUG);
6152
			$resql = $this->db->query($sql);
6153
			if ($resql) {
6154
				$value = ''; // value was used, so now we reste it to use it to build final output
6155
				$toprint=array();
6156
				while ( $obj = $this->db->fetch_object($resql) ) {
6157
6158
					// Several field into label (eq table:code|libelle:rowid)
6159
					$fields_label = explode('|', $InfoFieldList[1]);
6160
					if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
6161
						if (is_array($fields_label) && count($fields_label) > 1) {
6162
							foreach ( $fields_label as $field_toshow ) {
6163
								$translabel = '';
6164
								if (! empty($obj->$field_toshow)) {
6165
									$translabel = $langs->trans($obj->$field_toshow);
6166
								}
6167
								if ($translabel != $field_toshow) {
6168
									$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
6169
								} else {
6170
									$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->$field_toshow.'</li>';
6171
								}
6172
							}
6173
						} else {
6174
							$translabel = '';
6175
							if (! empty($obj->{$InfoFieldList[1]})) {
6176
								$translabel = $langs->trans($obj->{$InfoFieldList[1]});
6177
							}
6178
							if ($translabel != $obj->{$InfoFieldList[1]}) {
6179
								$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
6180
							} else {
6181
								$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->{$InfoFieldList[1]}.'</li>';
6182
							}
6183
						}
6184
					}
6185
				}
6186
				$value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6187
			} else {
6188
				dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING);
6189
			}
6190
		}
6191
		elseif ($type == 'link')
6192
		{
6193
			$out='';
6194
6195
			// only if something to display (perf)
6196
			if ($value)
6197
			{
6198
				$param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
6199
6200
				$InfoFieldList = explode(":", $param_list[0]);
6201
				$classname=$InfoFieldList[0];
6202
				$classpath=$InfoFieldList[1];
6203
				$getnomurlparam=(empty($InfoFieldList[2]) ? 3 : $InfoFieldList[2]);
6204
				if (! empty($classpath))
6205
				{
6206
					dol_include_once($InfoFieldList[1]);
6207
					if ($classname && class_exists($classname))
6208
					{
6209
						$object = new $classname($this->db);
6210
						$object->fetch($value);
6211
						$value=$object->getNomUrl($getnomurlparam);
6212
					}
6213
				}
6214
				else
6215
				{
6216
					dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6217
					return 'Error bad setup of extrafield';
6218
				}
6219
			}
6220
			else $value='';
6221
		}
6222
		elseif ($type == 'text' || $type == 'html')
6223
		{
6224
			$value=dol_htmlentitiesbr($value);
6225
		}
6226
		elseif ($type == 'password')
6227
		{
6228
			$value=preg_replace('/./i','*',$value);
6229
		}
6230
		elseif ($type == 'array')
6231
		{
6232
			$value = implode('<br>', $value);
6233
		}
6234
6235
		//print $type.'-'.$size;
6236
		$out=$value;
6237
6238
		return $out;
6239
	}
6240
6241
6242
	/**
6243
	 * Function to show lines of extrafields with output datas
6244
	 *
6245
	 * @param 	Extrafields $extrafields    Extrafield Object
6246
	 * @param 	string      $mode           Show output (view) or input (edit) for extrafield
6247
	 * @param 	array       $params         Optional parameters. Example: array('style'=>'class="oddeven"', 'colspan'=>$colspan)
6248
	 * @param 	string      $keysuffix      Suffix string to add after name and id of field (can be used to avoid duplicate names)
6249
	 * @param 	string      $keyprefix      Prefix string to add before name and id of field (can be used to avoid duplicate names)
6250
	 * @param	string		$onetrtd		All fields in same tr td
6251
	 * @return 	string
6252
	 */
6253
	function showOptionals($extrafields, $mode='view', $params=null, $keysuffix='', $keyprefix='', $onetrtd=0)
6254
	{
6255
		global $db, $conf, $langs, $action, $form;
6256
6257
		if (! is_object($form)) $form=new Form($db);
6258
6259
		$out = '';
6260
6261
		if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label']) > 0)
6262
		{
6263
			$out .= "\n";
6264
			$out .= '<!-- showOptionalsInput --> ';
6265
			$out .= "\n";
6266
6267
			$e = 0;
6268
			foreach($extrafields->attributes[$this->table_element]['label'] as $key=>$label)
6269
			{
6270
				// Show only the key field in params
6271
				if (is_array($params) && array_key_exists('onlykey',$params) && $key != $params['onlykey']) continue;
6272
6273
				$enabled = 1;
6274
				if ($enabled && isset($extrafields->attributes[$this->table_element]['list'][$key]))
6275
				{
6276
					$enabled = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1);
6277
				}
6278
6279
				$perms = 1;
6280
				if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key]))
6281
				{
6282
					$perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1);
6283
				}
6284
6285
				if (($mode == 'create' || $mode == 'edit') && abs($enabled) != 1 && abs($enabled) != 3) continue;	// <> -1 and <> 1 and <> 3 = not visible on forms, only on list
6286
				if (empty($perms)) continue;
6287
6288
				// Load language if required
6289
				if (! empty($extrafields->attributes[$this->table_element]['langfile'][$key])) $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
6290
6291
				$colspan='3';
6292
				if (is_array($params) && count($params)>0) {
6293
					if (array_key_exists('colspan',$params)) {
6294
						$colspan=$params['colspan'];
6295
					}
6296
				}
6297
6298
				switch($mode) {
6299
					case "view":
6300
						$value=$this->array_options["options_".$key.$keysuffix];
6301
						break;
6302
					case "edit":
6303
						$getposttemp = GETPOST($keyprefix.'options_'.$key.$keysuffix, 'none');				// GETPOST can get value from GET, POST or setup of default values.
6304
						// GETPOST("options_" . $key) can be 'abc' or array(0=>'abc')
6305
						if (is_array($getposttemp) || $getposttemp != '' || GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix))
6306
						{
6307
							if (is_array($getposttemp)) {
6308
								// $getposttemp is an array but following code expects a comma separated string
6309
								$value = implode(",", $getposttemp);
6310
							} else {
6311
								$value = $getposttemp;
6312
							}
6313
						} else {
6314
							$value = $this->array_options["options_" . $key];			// No GET, no POST, no default value, so we take value of object.
6315
						}
6316
						//var_dump($keyprefix.' - '.$key.' - '.$keysuffix.' - '.$keyprefix.'options_'.$key.$keysuffix.' - '.$this->array_options["options_".$key.$keysuffix].' - '.$getposttemp.' - '.$value);
6317
						break;
6318
				}
6319
6320
				if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate')
6321
				{
6322
					$out .= $extrafields->showSeparator($key, $this);
6323
				}
6324
				else
6325
				{
6326
					$csstyle='';
6327
					$class=(!empty($extrafields->attributes[$this->table_element]['hidden'][$key]) ? 'hideobject ' : '');
6328
					if (is_array($params) && count($params)>0) {
6329
						if (array_key_exists('style',$params)) {
6330
							$csstyle=$params['style'];
6331
						}
6332
					}
6333
6334
					// add html5 elements
6335
					$domData  = ' data-element="extrafield"';
6336
					$domData .= ' data-targetelement="'.$this->element.'"';
6337
					$domData .= ' data-targetid="'.$this->id.'"';
6338
6339
					$html_id = !empty($this->id) ? 'extrarow-'.$this->element.'_'.$key.'_'.$this->id : '';
6340
6341
					$out .= '<tr id="'.$html_id.'" '.$csstyle.' class="'.$class.$this->element.'_extras_'.$key.'" '.$domData.' >';
6342
6343
					if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0)
6344
					{
6345
						if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) { $colspan='0'; }
6346
					}
6347
6348
					if ($action == 'selectlines') { $colspan++; }
6349
6350
					// Convert date into timestamp format (value in memory must be a timestamp)
6351
					if (in_array($extrafields->attributes[$this->table_element]['type'][$key],array('date','datetime')))
6352
					{
6353
						$datenotinstring = $this->array_options['options_' . $key];
6354
						if (! is_numeric($this->array_options['options_' . $key]))	// For backward compatibility
6355
						{
6356
							$datenotinstring = $this->db->jdate($datenotinstring);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
6357
						}
6358
						$value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?dol_mktime(GETPOST($keyprefix.'options_'.$key.$keysuffix."hour", 'int', 3), GETPOST($keyprefix.'options_'.$key.$keysuffix."min",'int',3), 0, GETPOST($keyprefix.'options_'.$key.$keysuffix."month",'int',3), GETPOST($keyprefix.'options_'.$key.$keysuffix."day",'int',3), GETPOST($keyprefix.'options_'.$key.$keysuffix."year",'int',3)):$datenotinstring;
6359
					}
6360
					// Convert float submited string into real php numeric (value in memory must be a php numeric)
6361
					if (in_array($extrafields->attributes[$this->table_element]['type'][$key],array('price','double')))
6362
					{
6363
						$value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?price2num(GETPOST($keyprefix.'options_'.$key.$keysuffix, 'alpha', 3)):$this->array_options['options_'.$key];
6364
					}
6365
6366
					$labeltoshow = $langs->trans($label);
6367
6368
					$out .= '<td class="titlefield';
6369
					if (GETPOST('action','none') == 'create') $out.='create';
6370
					if ($mode != 'view' && ! empty($extrafields->attributes[$this->table_element]['required'][$key])) $out .= ' fieldrequired';
6371
					$out .= '">';
6372
					if (! empty($extrafields->attributes[$object->table_element]['help'][$key])) $out .= $form->textwithpicto($labeltoshow, $extrafields->attributes[$object->table_element]['help'][$key]);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $object seems to be never defined.
Loading history...
6373
					else $out .= $labeltoshow;
6374
					$out .= '</td>';
6375
6376
					$html_id = !empty($this->id) ? $this->element.'_extras_'.$key.'_'.$this->id : '';
6377
					$out .='<td id="'.$html_id.'" class="'.$this->element.'_extras_'.$key.'" '.($colspan?' colspan="'.$colspan.'"':'').'>';
6378
6379
					switch($mode) {
6380
						case "view":
6381
							$out .= $extrafields->showOutputField($key, $value);
6382
							break;
6383
						case "edit":
6384
							$out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id);
6385
							break;
6386
					}
6387
6388
					$out .= '</td>';
6389
6390
					if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && (($e % 2) == 1)) $out .= '</tr>';
6391
					else $out .= '</tr>';
6392
					$e++;
6393
				}
6394
			}
6395
			$out .= "\n";
6396
			// Add code to manage list depending on others
6397
			if (! empty($conf->use_javascript_ajax)) {
6398
				$out .= '
6399
				<script type="text/javascript">
6400
				    jQuery(document).ready(function() {
6401
				    	function showOptions(child_list, parent_list)
6402
				    	{
6403
				    		var val = $("select[name=\"options_"+parent_list+"\"]").val();
6404
				    		var parentVal = parent_list + ":" + val;
6405
							if(val > 0) {
6406
					    		$("select[name=\""+child_list+"\"] option[parent]").hide();
6407
					    		$("select[name=\""+child_list+"\"] option[parent=\""+parentVal+"\"]").show();
6408
							} else {
6409
								$("select[name=\""+child_list+"\"] option").show();
6410
							}
6411
				    	}
6412
						function setListDependencies() {
6413
					    	jQuery("select option[parent]").parent().each(function() {
6414
					    		var child_list = $(this).attr("name");
6415
								var parent = $(this).find("option[parent]:first").attr("parent");
6416
								var infos = parent.split(":");
6417
								var parent_list = infos[0];
6418
								$("select[name=\""+parent_list+"\"]").change(function() {
6419
									showOptions(child_list, parent_list);
6420
								});
6421
					    	});
6422
						}
6423
6424
						setListDependencies();
6425
				    });
6426
				</script>'."\n";
6427
				$out .= '<!-- /showOptionalsInput --> '."\n";
6428
			}
6429
		}
6430
		return $out;
6431
	}
6432
6433
6434
	/**
6435
	 * Returns the rights used for this class
6436
	 * @return stdClass
0 ignored issues
show
Bug introduced by
The type Alixar\Base\stdClass was not found. Did you mean stdClass? If so, make sure to prefix the type with \.
Loading history...
6437
	 */
6438
	public function getRights()
6439
	{
6440
		global $user;
6441
6442
		$element = $this->element;
6443
		if ($element == 'facturerec') $element='facture';
6444
6445
		return $user->rights->{$element};
6446
	}
6447
6448
	/**
6449
	 * Function used to replace a thirdparty id with another one.
6450
	 * This function is meant to be called from replaceThirdparty with the appropiate tables
6451
	 * Column name fk_soc MUST be used to identify thirdparties
6452
	 *
6453
	 * @param  DoliDB 	   $db 			  Database handler
6454
	 * @param  int 		   $origin_id     Old thirdparty id (the thirdparty to delete)
6455
	 * @param  int 		   $dest_id       New thirdparty id (the thirdparty that will received element of the other)
6456
	 * @param  string[]    $tables        Tables that need to be changed
6457
	 * @param  int         $ignoreerrors  Ignore errors. Return true even if errors. We need this when replacement can fails like for categories (categorie of old thirdparty may already exists on new one)
6458
	 * @return bool						  True if success, False if error
6459
	 */
6460
	public static function commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
0 ignored issues
show
Bug introduced by
The type Alixar\Base\DoliDB was not found. Did you mean DoliDB? If so, make sure to prefix the type with \.
Loading history...
6461
	{
6462
		foreach ($tables as $table)
6463
		{
6464
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_soc = '.$dest_id.' WHERE fk_soc = '.$origin_id;
6465
6466
			if (! $db->query($sql))
6467
			{
6468
				if ($ignoreerrors) return true;		// TODO Not enough. If there is A-B on kept thirdarty and B-C on old one, we must get A-B-C after merge. Not A-B.
6469
				//$this->errors = $db->lasterror();
6470
				return false;
6471
			}
6472
		}
6473
6474
		return true;
6475
	}
6476
6477
	/**
6478
	 * Get buy price to use for margin calculation. This function is called when buy price is unknown.
6479
	 *	 Set buy price = sell price if ForceBuyingPriceIfNull configured,
6480
	 *   else if calculation MARGIN_TYPE = 'costprice' and costprice is defined, use costprice as buyprice
6481
	 *	 else if calculation MARGIN_TYPE = 'pmp' and pmp is calculated, use pmp as buyprice
6482
	 *	 else set min buy price as buy price
6483
	 *
6484
	 * @param float		$unitPrice		 Product unit price
6485
	 * @param float		$discountPercent Line discount percent
6486
	 * @param int		$fk_product		 Product id
6487
	 * @return	float                    <0 if KO, buyprice if OK
6488
	 */
6489
	public function defineBuyPrice($unitPrice = 0.0, $discountPercent = 0.0, $fk_product = 0)
6490
	{
6491
		global $conf;
6492
6493
		$buyPrice = 0;
6494
6495
		if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) // In most cases, test here is false
6496
		{
6497
			$buyPrice = $unitPrice * (1 - $discountPercent / 100);
6498
		}
6499
		else
6500
		{
6501
			// Get cost price for margin calculation
6502
			if (! empty($fk_product))
6503
			{
6504
				if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'costprice')
6505
				{
6506
					require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6507
					$product = new Product($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
6508
					$result = $product->fetch($fk_product);
6509
					if ($result <= 0)
6510
					{
6511
						$this->errors[] = 'ErrorProductIdDoesNotExists';
6512
						return -1;
6513
					}
6514
					if ($product->cost_price > 0)
6515
					{
6516
						$buyPrice = $product->cost_price;
6517
					}
6518
					else if ($product->pmp > 0)
6519
					{
6520
						$buyPrice = $product->pmp;
6521
					}
6522
				}
6523
				else if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'pmp')
6524
				{
6525
					require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6526
					$product = new Product($this->db);
6527
					$result = $product->fetch($fk_product);
6528
					if ($result <= 0)
6529
					{
6530
						$this->errors[] = 'ErrorProductIdDoesNotExists';
6531
						return -1;
6532
					}
6533
					if ($product->pmp > 0)
6534
					{
6535
						$buyPrice = $product->pmp;
6536
					}
6537
				}
6538
6539
				if (empty($buyPrice) && isset($conf->global->MARGIN_TYPE) && in_array($conf->global->MARGIN_TYPE, array('1','pmp','costprice')))
6540
				{
6541
					require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
6542
					$productFournisseur = new ProductFournisseur($this->db);
0 ignored issues
show
Bug introduced by
The type Alixar\Base\ProductFournisseur was not found. Did you mean ProductFournisseur? If so, make sure to prefix the type with \.
Loading history...
6543
					if (($result = $productFournisseur->find_min_price_product_fournisseur($fk_product)) > 0)
6544
					{
6545
						$buyPrice = $productFournisseur->fourn_unitprice;
6546
					}
6547
					else if ($result < 0)
6548
					{
6549
						$this->errors[] = $productFournisseur->error;
6550
						return -2;
6551
					}
6552
				}
6553
			}
6554
		}
6555
		return $buyPrice;
6556
	}
6557
6558
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
6559
	/**
6560
	 *  Show photos of an object (nbmax maximum), into several columns
6561
	 *
6562
	 *  @param		string	$modulepart		'product', 'ticket', ...
6563
	 *  @param      string	$sdir        	Directory to scan (full absolute path)
6564
	 *  @param      int		$size        	0=original size, 1='small' use thumbnail if possible
6565
	 *  @param      int		$nbmax       	Nombre maximum de photos (0=pas de max)
6566
	 *  @param      int		$nbbyrow     	Number of image per line or -1 to use div. Used only if size=1.
6567
	 * 	@param		int		$showfilename	1=Show filename
6568
	 * 	@param		int		$showaction		1=Show icon with action links (resize, delete)
6569
	 * 	@param		int		$maxHeight		Max height of original image when size='small' (so we can use original even if small requested). If 0, always use 'small' thumb image.
6570
	 * 	@param		int		$maxWidth		Max width of original image when size='small'
6571
	 *  @param      int     $nolink         Do not add a href link to view enlarged imaged into a new tab
6572
	 *  @param      int     $notitle        Do not add title tag on image
6573
	 *  @param		int		$usesharelink	Use the public shared link of image (if not available, the 'nophoto' image will be shown instead)
6574
	 *  @return     string					Html code to show photo. Number of photos shown is saved in this->nbphoto
6575
	 */
6576
	function show_photos($modulepart, $sdir, $size=0, $nbmax=0, $nbbyrow=5, $showfilename=0, $showaction=0, $maxHeight=120, $maxWidth=160, $nolink=0, $notitle=0, $usesharelink=0)
6577
	{
6578
        // phpcs:enable
6579
		global $conf,$user,$langs;
6580
6581
		include_once DOL_DOCUMENT_ROOT .'/core/lib/files.lib.php';
6582
		include_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';
6583
6584
		$sortfield='position_name';
6585
		$sortorder='asc';
6586
6587
		$dir = $sdir . '/';
6588
		$pdir = '/';
6589
		if ($modulepart == 'ticket')
6590
		{
6591
			$dir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->track_id.'/';
0 ignored issues
show
Bug Best Practice introduced by
The property track_id does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
6592
			$pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->track_id.'/';
6593
		}
6594
		else
6595
		{
6596
			$dir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->ref.'/';
6597
			$pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->ref.'/';
6598
		}
6599
6600
		// For backward compatibility
6601
		if ($modulepart == 'product' && ! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))
6602
		{
6603
			$dir = $sdir . '/'. get_exdir($this->id,2,0,0,$this,$modulepart) . $this->id ."/photos/";
6604
			$pdir = '/' . get_exdir($this->id,2,0,0,$this,$modulepart) . $this->id ."/photos/";
6605
		}
6606
6607
		// Defined relative dir to DOL_DATA_ROOT
6608
		$relativedir = '';
6609
		if ($dir)
6610
		{
6611
			$relativedir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $dir);
6612
			$relativedir = preg_replace('/^[\\/]/','',$relativedir);
6613
			$relativedir = preg_replace('/[\\/]$/','',$relativedir);
6614
		}
6615
6616
		$dirthumb = $dir.'thumbs/';
6617
		$pdirthumb = $pdir.'thumbs/';
6618
6619
		$return ='<!-- Photo -->'."\n";
6620
		$nbphoto=0;
6621
6622
		$filearray=dol_dir_list($dir,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
6623
6624
		/*if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))    // For backward compatiblity, we scan also old dirs
6625
		 {
6626
		 $filearrayold=dol_dir_list($dirold,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
6627
		 $filearray=array_merge($filearray, $filearrayold);
6628
		 }*/
6629
6630
		completeFileArrayWithDatabaseInfo($filearray, $relativedir);
6631
6632
		if (count($filearray))
6633
		{
6634
			if ($sortfield && $sortorder)
6635
			{
6636
				$filearray=dol_sort_array($filearray, $sortfield, $sortorder);
6637
			}
6638
6639
			foreach($filearray as $key => $val)
6640
			{
6641
				$photo='';
6642
				$file = $val['name'];
6643
6644
				//if (! utf8_check($file)) $file=utf8_encode($file);	// To be sure file is stored in UTF8 in memory
6645
6646
				//if (dol_is_file($dir.$file) && image_format_supported($file) >= 0)
6647
				if (image_format_supported($file) >= 0)
6648
				{
6649
					$nbphoto++;
6650
					$photo = $file;
6651
					$viewfilename = $file;
6652
6653
					if ($size == 1 || $size == 'small') {   // Format vignette
6654
6655
						// Find name of thumb file
6656
						$photo_vignette=basename(getImageFileNameForSize($dir.$file, '_small'));
6657
						if (! dol_is_file($dirthumb.$photo_vignette)) $photo_vignette='';
6658
6659
						// Get filesize of original file
6660
						$imgarray=dol_getImageSize($dir.$photo);
6661
6662
						if ($nbbyrow > 0)
6663
						{
6664
							if ($nbphoto == 1) $return.= '<table width="100%" valign="top" align="center" border="0" cellpadding="2" cellspacing="2">';
6665
6666
							if ($nbphoto % $nbbyrow == 1) $return.= '<tr align=center valign=middle border=1>';
6667
							$return.= '<td width="'.ceil(100/$nbbyrow).'%" class="photo">';
6668
						}
6669
						else if ($nbbyrow < 0) $return .= '<div class="inline-block">';
6670
6671
						$return.= "\n";
6672
6673
						$relativefile=preg_replace('/^\//', '', $pdir.$photo);
6674
						if (empty($nolink))
6675
						{
6676
							$urladvanced=getAdvancedPreviewUrl($modulepart, $relativefile, 0, 'entity='.$this->entity);
6677
							if ($urladvanced) $return.='<a href="'.$urladvanced.'">';
6678
							else $return.= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'" class="aphoto" target="_blank">';
6679
						}
6680
6681
						// Show image (width height=$maxHeight)
6682
						// Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine
6683
						$alt=$langs->transnoentitiesnoconv('File').': '.$relativefile;
6684
						$alt.=' - '.$langs->transnoentitiesnoconv('Size').': '.$imgarray['width'].'x'.$imgarray['height'];
6685
						if ($notitle) $alt='';
6686
6687
						if ($usesharelink)
6688
						{
6689
							if ($val['share'])
6690
							{
6691
								if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight)
6692
								{
6693
									$return.= '<!-- Show original file (thumb not yet available with shared links) -->';
6694
									$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).'" title="'.dol_escape_htmltag($alt).'">';
6695
								}
6696
								else {
6697
									$return.= '<!-- Show original file -->';
6698
									$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).'" title="'.dol_escape_htmltag($alt).'">';
6699
								}
6700
							}
6701
							else
6702
							{
6703
								$return.= '<!-- Show nophoto file (because file is not shared) -->';
6704
								$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/public/theme/common/nophoto.png" title="'.dol_escape_htmltag($alt).'">';
6705
							}
6706
						}
6707
						else
6708
						{
6709
							if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight)
6710
							{
6711
								$return.= '<!-- Show thumb -->';
6712
								$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdirthumb.$photo_vignette).'" title="'.dol_escape_htmltag($alt).'">';
6713
							}
6714
							else {
6715
								$return.= '<!-- Show original file -->';
6716
								$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'" title="'.dol_escape_htmltag($alt).'">';
6717
							}
6718
						}
6719
6720
						if (empty($nolink)) $return.= '</a>';
6721
						$return.="\n";
6722
6723
						if ($showfilename) $return.= '<br>'.$viewfilename;
6724
						if ($showaction)
6725
						{
6726
							$return.= '<br>';
6727
							// On propose la generation de la vignette si elle n'existe pas et si la taille est superieure aux limites
6728
							if ($photo_vignette && (image_format_supported($photo) > 0) && ($this->imgWidth > $maxWidth || $this->imgHeight > $maxHeight))
6729
							{
6730
								$return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=addthumb&amp;file='.urlencode($pdir.$viewfilename).'">'.img_picto($langs->trans('GenerateThumb'),'refresh').'&nbsp;&nbsp;</a>';
6731
							}
6732
							// Special cas for product
6733
							if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer))
6734
							{
6735
								// Link to resize
6736
								$return.= '<a href="'.DOL_URL_ROOT.'/core/photos_resize.php?modulepart='.urlencode('produit|service').'&id='.$this->id.'&amp;file='.urlencode($pdir.$viewfilename).'" title="'.dol_escape_htmltag($langs->trans("Resize")).'">'.img_picto($langs->trans("Resize"), 'resize', '').'</a> &nbsp; ';
6737
6738
								// Link to delete
6739
								$return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=delete&amp;file='.urlencode($pdir.$viewfilename).'">';
6740
								$return.= img_delete().'</a>';
6741
							}
6742
						}
6743
						$return.= "\n";
6744
6745
						if ($nbbyrow > 0)
6746
						{
6747
							$return.= '</td>';
6748
							if (($nbphoto % $nbbyrow) == 0) $return.= '</tr>';
6749
						}
6750
						else if ($nbbyrow < 0) $return.='</div>';
6751
					}
6752
6753
					if (empty($size)) {     // Format origine
6754
						$return.= '<img class="photo photowithmargin" border="0" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'">';
6755
6756
						if ($showfilename) $return.= '<br>'.$viewfilename;
6757
						if ($showaction)
6758
						{
6759
							// Special case for product
6760
							if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer))
6761
							{
6762
								// Link to resize
6763
								$return.= '<a href="'.DOL_URL_ROOT.'/core/photos_resize.php?modulepart='.urlencode('produit|service').'&id='.$this->id.'&amp;file='.urlencode($pdir.$viewfilename).'" title="'.dol_escape_htmltag($langs->trans("Resize")).'">'.img_picto($langs->trans("Resize"), 'resize', '').'</a> &nbsp; ';
6764
6765
								// Link to delete
6766
								$return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=delete&amp;file='.urlencode($pdir.$viewfilename).'">';
6767
								$return.= img_delete().'</a>';
6768
							}
6769
						}
6770
					}
6771
6772
					// On continue ou on arrete de boucler ?
6773
					if ($nbmax && $nbphoto >= $nbmax) break;
6774
				}
6775
			}
6776
6777
			if ($size==1 || $size=='small')
6778
			{
6779
				if ($nbbyrow > 0)
6780
				{
6781
					// Ferme tableau
6782
					while ($nbphoto % $nbbyrow)
6783
					{
6784
						$return.= '<td width="'.ceil(100/$nbbyrow).'%">&nbsp;</td>';
6785
						$nbphoto++;
6786
					}
6787
6788
					if ($nbphoto) $return.= '</table>';
6789
				}
6790
			}
6791
		}
6792
6793
		$this->nbphoto = $nbphoto;
6794
6795
		return $return;
6796
	}
6797
6798
6799
	/**
6800
	 * Function test if type is array
6801
	 *
6802
	 * @param   array   $info   content informations of field
6803
	 * @return                  bool
6804
	 */
6805
	protected function isArray($info)
6806
	{
6807
		if(is_array($info))
6808
		{
6809
			if(isset($info['type']) && $info['type']=='array') return true;
6810
			else return false;
6811
		}
6812
		else return false;
6813
	}
6814
6815
	/**
6816
	 * Function test if type is null
6817
	 *
6818
	 * @param   array   $info   content informations of field
6819
	 * @return                  bool
6820
	 */
6821
	protected function isNull($info)
6822
	{
6823
		if(is_array($info))
6824
		{
6825
			if(isset($info['type']) && $info['type']=='null') return true;
6826
			else return false;
6827
		}
6828
		else return false;
6829
	}
6830
6831
	/**
6832
	 * Function test if type is date
6833
	 *
6834
	 * @param   array   $info   content informations of field
6835
	 * @return                  bool
6836
	 */
6837
	public function isDate($info)
6838
	{
6839
		if(isset($info['type']) && ($info['type']=='date' || $info['type']=='datetime' || $info['type']=='timestamp')) return true;
6840
		else return false;
6841
	}
6842
6843
	/**
6844
	 * Function test if type is integer
6845
	 *
6846
	 * @param   array   $info   content informations of field
6847
	 * @return                  bool
6848
	 */
6849
	public function isInt($info)
6850
	{
6851
		if(is_array($info))
6852
		{
6853
			if(isset($info['type']) && ($info['type']=='int' || preg_match('/^integer/i',$info['type']) ) ) return true;
6854
			else return false;
6855
		}
6856
		else return false;
6857
	}
6858
6859
	/**
6860
	 * Function test if type is float
6861
	 *
6862
	 * @param   array   $info   content informations of field
6863
	 * @return                  bool
6864
	 */
6865
	public function isFloat($info)
6866
	{
6867
		if(is_array($info))
6868
		{
6869
			if (isset($info['type']) && (preg_match('/^(double|real)/i', $info['type']))) return true;
6870
			else return false;
6871
		}
6872
		else return false;
6873
	}
6874
6875
	/**
6876
	 * Function test if type is text
6877
	 *
6878
	 * @param   array   $info   content informations of field
6879
	 * @return                  bool
6880
	 */
6881
	public function isText($info)
6882
	{
6883
		if(is_array($info))
6884
		{
6885
			if(isset($info['type']) && $info['type']=='text') return true;
6886
			else return false;
6887
		}
6888
		else return false;
6889
	}
6890
6891
	/**
6892
	 * Function test if is indexed
6893
	 *
6894
	 * @param   array   $info   content informations of field
6895
	 * @return                  bool
6896
	 */
6897
	protected function isIndex($info)
6898
	{
6899
		if(is_array($info))
6900
		{
6901
			if(isset($info['index']) && $info['index']==true) return true;
6902
			else return false;
6903
		}
6904
		else return false;
6905
	}
6906
6907
	/**
6908
	 * Function to prepare the values to insert.
6909
	 * Note $this->${field} are set by the page that make the createCommon or the updateCommon.
6910
	 *
6911
	 * @return array
6912
	 */
6913
	protected function setSaveQuery()
6914
	{
6915
		global $conf;
6916
6917
		$queryarray=array();
6918
		foreach ($this->fields as $field=>$info)	// Loop on definition of fields
6919
		{
6920
			// Depending on field type ('datetime', ...)
6921
			if($this->isDate($info))
6922
			{
6923
				if(empty($this->{$field}))
6924
				{
6925
					$queryarray[$field] = null;
6926
				}
6927
				else
6928
				{
6929
					$queryarray[$field] = $this->db->idate($this->{$field});
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
6930
				}
6931
			}
6932
			else if($this->isArray($info))
6933
			{
6934
				if(! empty($this->{$field})) {
6935
					if(! is_array($this->{$field})) {
6936
						$this->{$field} = array($this->{$field});
6937
					}
6938
					$queryarray[$field] = serialize($this->{$field});
6939
				} else {
6940
					$queryarray[$field] = null;
6941
				}
6942
			}
6943
			else if($this->isInt($info))
6944
			{
6945
				if ($field == 'entity' && is_null($this->{$field})) $queryarray[$field]=$conf->entity;
6946
				else
6947
				{
6948
					$queryarray[$field] = (int) price2num($this->{$field});
6949
					if (empty($queryarray[$field])) $queryarray[$field]=0;		// May be reset to null later if property 'notnull' is -1 for this field.
6950
				}
6951
			}
6952
			else if($this->isFloat($info))
6953
			{
6954
				$queryarray[$field] = (double) price2num($this->{$field});
6955
				if (empty($queryarray[$field])) $queryarray[$field]=0;
6956
			}
6957
			else
6958
			{
6959
				$queryarray[$field] = $this->{$field};
6960
			}
6961
6962
			if ($info['type'] == 'timestamp' && empty($queryarray[$field])) unset($queryarray[$field]);
6963
			if (! empty($info['notnull']) && $info['notnull'] == -1 && empty($queryarray[$field])) $queryarray[$field] = null;
6964
		}
6965
6966
		return $queryarray;
6967
	}
6968
6969
	/**
6970
	 * Function to load data from a SQL pointer into properties of current object $this
6971
	 *
6972
	 * @param   stdClass    $obj    Contain data of object from database
6973
     * @return void
6974
	 */
6975
	protected function setVarsFromFetchObj(&$obj)
6976
	{
6977
		foreach ($this->fields as $field => $info)
6978
		{
6979
			if($this->isDate($info))
6980
			{
6981
				if(empty($obj->{$field}) || $obj->{$field} === '0000-00-00 00:00:00' || $obj->{$field} === '1000-01-01 00:00:00') $this->{$field} = 0;
6982
				else $this->{$field} = strtotime($obj->{$field});
6983
			}
6984
			elseif($this->isArray($info))
6985
			{
6986
				if(! empty($obj->{$field})) {
6987
					$this->{$field} = @unserialize($obj->{$field});
6988
					// Hack for data not in UTF8
6989
					if($this->{$field } === false) @unserialize(utf8_decode($obj->{$field}));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unserialize(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

6989
					if($this->{$field } === false) /** @scrutinizer ignore-unhandled */ @unserialize(utf8_decode($obj->{$field}));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
6990
				} else {
6991
					$this->{$field} = array();
6992
				}
6993
			}
6994
			elseif($this->isInt($info))
6995
			{
6996
				if ($field == 'rowid') $this->id = (int) $obj->{$field};
6997
				else $this->{$field} = (int) $obj->{$field};
6998
			}
6999
			elseif($this->isFloat($info))
7000
			{
7001
				$this->{$field} = (double) $obj->{$field};
7002
			}
7003
			elseif($this->isNull($info))
7004
			{
7005
				$val = $obj->{$field};
7006
				// zero is not null
7007
				$this->{$field} = (is_null($val) || (empty($val) && $val!==0 && $val!=='0') ? null : $val);
7008
			}
7009
			else
7010
			{
7011
				$this->{$field} = $obj->{$field};
7012
			}
7013
		}
7014
7015
		// If there is no 'ref' field, we force property ->ref to ->id for a better compatibility with common functions.
7016
		if (! isset($this->fields['ref']) && isset($this->id)) $this->ref = $this->id;
7017
	}
7018
7019
	/**
7020
	 * Function to concat keys of fields
7021
	 *
7022
	 * @return string
7023
	 */
7024
	protected function getFieldList()
7025
	{
7026
		$keys = array_keys($this->fields);
7027
		return implode(',', $keys);
7028
	}
7029
7030
	/**
7031
	 * Add quote to field value if necessary
7032
	 *
7033
	 * @param 	string|int	$value			Value to protect
7034
	 * @param	array		$fieldsentry	Properties of field
7035
	 * @return 	string
7036
	 */
7037
    protected function quote($value, $fieldsentry)
7038
    {
7039
		if (is_null($value)) return 'NULL';
7040
		else if (preg_match('/^(int|double|real)/i', $fieldsentry['type'])) return $this->db->escape("$value");
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
7041
		else return "'".$this->db->escape($value)."'";
7042
	}
7043
7044
7045
	/**
7046
	 * Create object into database
7047
	 *
7048
	 * @param  User $user      User that creates
7049
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
7050
	 * @return int             <0 if KO, Id of created object if OK
7051
	 */
7052
	public function createCommon(User $user, $notrigger = false)
7053
	{
7054
		global $langs;
7055
7056
		$error = 0;
7057
7058
		$now=dol_now();
7059
7060
		$fieldvalues = $this->setSaveQuery();
7061
		if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) $fieldvalues['date_creation']=$this->db->idate($now);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
7062
		if (array_key_exists('fk_user_creat', $fieldvalues) && ! ($fieldvalues['fk_user_creat'] > 0)) $fieldvalues['fk_user_creat']=$user->id;
7063
		unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into insert.
7064
7065
		$keys=array();
7066
		$values = array();
7067
		foreach ($fieldvalues as $k => $v) {
7068
			$keys[$k] = $k;
7069
			$value = $this->fields[$k];
7070
			$values[$k] = $this->quote($v, $value);
7071
		}
7072
7073
		// Clean and check mandatory
7074
		foreach($keys as $key)
7075
		{
7076
			// If field is an implicit foreign key field
7077
			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';
7078
			if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';
7079
7080
			//var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7081
			if (isset($this->fields[$key]['notnull']) && $this->fields[$key]['notnull'] == 1 && ! isset($values[$key]) && is_null($val['default']))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $val does not exist. Did you maybe mean $value?
Loading history...
7082
			{
7083
				$error++;
7084
				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7085
			}
7086
7087
			// If field is an implicit foreign key field
7088
			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && empty($values[$key])) $values[$key]='null';
7089
			if (! empty($this->fields[$key]['foreignkey']) && empty($values[$key])) $values[$key]='null';
7090
		}
7091
7092
		if ($error) return -1;
7093
7094
		$this->db->begin();
7095
7096
		if (! $error)
7097
		{
7098
			$sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
7099
			$sql.= ' ('.implode( ", ", $keys ).')';
7100
			$sql.= ' VALUES ('.implode( ", ", $values ).')';
7101
7102
			$res = $this->db->query($sql);
7103
			if ($res===false) {
7104
				$error++;
7105
				$this->errors[] = $this->db->lasterror();
7106
			}
7107
		}
7108
7109
		if (! $error)
7110
		{
7111
			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
7112
		}
7113
7114
		// Create extrafields
7115
		if (! $error)
7116
		{
7117
			$result=$this->insertExtraFields();
7118
			if ($result < 0) $error++;
7119
		}
7120
7121
		// Triggers
7122
		if (! $error && ! $notrigger)
7123
		{
7124
			// Call triggers
7125
			$result=$this->call_trigger(strtoupper(get_class($this)).'_CREATE',$user);
7126
			if ($result < 0) { $error++; }
7127
			// End call triggers
7128
		}
7129
7130
		// Commit or rollback
7131
		if ($error) {
7132
			$this->db->rollback();
7133
			return -1;
7134
		} else {
7135
			$this->db->commit();
7136
			return $this->id;
7137
		}
7138
	}
7139
7140
7141
	/**
7142
	 * Load object in memory from the database
7143
	 *
7144
	 * @param	int    $id				Id object
7145
	 * @param	string $ref				Ref
7146
	 * @param	string	$morewhere		More SQL filters (' AND ...')
7147
	 * @return 	int         			<0 if KO, 0 if not found, >0 if OK
7148
	 */
7149
	public function fetchCommon($id, $ref = null, $morewhere = '')
7150
	{
7151
		if (empty($id) && empty($ref) && empty($morewhere)) return -1;
7152
7153
		$sql = 'SELECT '.$this->getFieldList();
7154
		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
7155
7156
		if (!empty($id))  $sql.= ' WHERE rowid = '.$id;
7157
		elseif (!empty($ref)) $sql.= " WHERE ref = ".$this->quote($ref, $this->fields['ref']);
7158
		else $sql.=' WHERE 1 = 1';	// usage with empty id and empty ref is very rare
7159
		if ($morewhere)   $sql.= $morewhere;
7160
		$sql.=' LIMIT 1';	// This is a fetch, to be sure to get only one record
7161
7162
		$res = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
7163
		if ($res)
7164
		{
7165
			$obj = $this->db->fetch_object($res);
7166
			if ($obj)
7167
			{
7168
				$this->setVarsFromFetchObj($obj);
7169
				return $this->id;
7170
			}
7171
			else
7172
			{
7173
				return 0;
7174
			}
7175
		}
7176
		else
7177
		{
7178
			$this->error = $this->db->lasterror();
7179
			$this->errors[] = $this->error;
7180
			return -1;
7181
		}
7182
	}
7183
7184
	/**
7185
	 * Update object into database
7186
	 *
7187
	 * @param  User $user      	User that modifies
7188
	 * @param  bool $notrigger 	false=launch triggers after, true=disable triggers
7189
	 * @return int             	<0 if KO, >0 if OK
7190
	 */
7191
	public function updateCommon(User $user, $notrigger = false)
7192
	{
7193
		global $conf, $langs;
7194
7195
		$error = 0;
7196
7197
		$now=dol_now();
7198
7199
		$fieldvalues = $this->setSaveQuery();
7200
		if (array_key_exists('date_modification', $fieldvalues) && empty($fieldvalues['date_modification'])) $fieldvalues['date_modification']=$this->db->idate($now);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
7201
		if (array_key_exists('fk_user_modif', $fieldvalues) && ! ($fieldvalues['fk_user_modif'] > 0)) $fieldvalues['fk_user_modif']=$user->id;
7202
		unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into update.
7203
7204
		$keys=array();
7205
		$values = array();
7206
		foreach ($fieldvalues as $k => $v) {
7207
			$keys[$k] = $k;
7208
			$value = $this->fields[$k];
7209
			$values[$k] = $this->quote($v, $value);
7210
			$tmp[] = $k.'='.$this->quote($v, $this->fields[$k]);
7211
		}
7212
7213
		// Clean and check mandatory
7214
		foreach($keys as $key)
7215
		{
7216
			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';		// This is an implicit foreign key field
7217
			if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';					// This is an explicit foreign key field
7218
7219
			//var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7220
			/*
7221
			if ($this->fields[$key]['notnull'] == 1 && empty($values[$key]))
7222
			{
7223
				$error++;
7224
				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7225
			}*/
7226
		}
7227
7228
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET '.implode( ',', $tmp ).' WHERE rowid='.$this->id ;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tmp seems to be defined by a foreach iteration on line 7206. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
7229
7230
		$this->db->begin();
7231
		if (! $error)
7232
		{
7233
			$res = $this->db->query($sql);
7234
			if ($res===false)
7235
			{
7236
				$error++;
7237
				$this->errors[] = $this->db->lasterror();
7238
			}
7239
		}
7240
7241
		// Update extrafield
7242
		if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options)>0)
7243
		{
7244
			$result=$this->insertExtraFields();
7245
			if ($result < 0)
7246
			{
7247
				$error++;
7248
			}
7249
		}
7250
7251
		// Triggers
7252
		if (! $error && ! $notrigger)
7253
		{
7254
			// Call triggers
7255
			$result=$this->call_trigger(strtoupper(get_class($this)).'_MODIFY',$user);
7256
			if ($result < 0) { $error++; } //Do also here what you must do to rollback action if trigger fail
7257
			// End call triggers
7258
		}
7259
7260
		// Commit or rollback
7261
		if ($error) {
7262
			$this->db->rollback();
7263
			return -1;
7264
		} else {
7265
			$this->db->commit();
7266
			return $this->id;
7267
		}
7268
	}
7269
7270
	/**
7271
	 * Delete object in database
7272
	 *
7273
	 * @param 	User 	$user       			User that deletes
7274
	 * @param 	bool 	$notrigger  			false=launch triggers after, true=disable triggers
7275
	 * @param	int		$forcechilddeletion		0=no, 1=Force deletion of children
7276
	 * @return 	int             				<=0 if KO, >0 if OK
7277
	 */
7278
	public function deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
7279
	{
7280
		$error=0;
7281
7282
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
7283
7284
		if ($forcechilddeletion)
7285
		{
7286
			foreach($this->childtables as $table)
0 ignored issues
show
Bug Best Practice introduced by
The property childtables does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
7287
			{
7288
				$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$table.' WHERE '.$this->fk_element.' = '.$this->id;
7289
				$resql = $this->db->query($sql);
7290
				if (! $resql)
7291
				{
7292
					$this->error=$this->db->lasterror();
7293
					$this->errors[]=$this->error;
7294
					$this->db->rollback();
7295
					return -1;
7296
				}
7297
			}
7298
		}
7299
		elseif (! empty($this->fk_element) && ! empty($this->childtables))	// If object has childs linked with a foreign key field, we check all child tables.
7300
		{
7301
			$objectisused = $this->isObjectUsed($this->id);
7302
			if (! empty($objectisused))
7303
			{
7304
				dol_syslog(get_class($this)."::deleteCommon Can't delete record as it has some child", LOG_WARNING);
7305
				$this->error='ErrorRecordHasChildren';
7306
				$this->errors[]=$this->error;
7307
				$this->db->rollback();
7308
				return 0;
7309
			}
7310
		}
7311
7312
		if (! $error) {
7313
			if (! $notrigger) {
7314
				// Call triggers
7315
				$result=$this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user);
7316
				if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
7317
				// End call triggers
7318
			}
7319
		}
7320
7321
		if (! $error && ! empty($this->isextrafieldmanaged))
7322
		{
7323
			$sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element."_extrafields";
7324
			$sql.= " WHERE fk_object=" . $this->id;
7325
7326
			$resql = $this->db->query($sql);
7327
			if (! $resql)
7328
			{
7329
				$this->errors[] = $this->db->lasterror();
7330
				$error++;
7331
			}
7332
		}
7333
7334
		if (! $error)
7335
		{
7336
			$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
7337
7338
			$res = $this->db->query($sql);
7339
			if($res===false) {
7340
				$error++;
7341
				$this->errors[] = $this->db->lasterror();
7342
			}
7343
		}
7344
7345
		// Commit or rollback
7346
		if ($error) {
7347
			$this->db->rollback();
7348
			return -1;
7349
		} else {
7350
			$this->db->commit();
7351
			return 1;
7352
		}
7353
	}
7354
7355
	/**
7356
	 * Initialise object with example values
7357
	 * Id must be 0 if object instance is a specimen
7358
	 *
7359
	 * @return void
7360
	 */
7361
	public function initAsSpecimenCommon()
7362
	{
7363
		$this->id = 0;
7364
7365
		// TODO...
7366
	}
7367
7368
7369
	/* Part for comments */
7370
7371
	/**
7372
	 * Load comments linked with current task
7373
	 *	@return boolean	1 if ok
7374
	 */
7375
	public function fetchComments()
7376
	{
7377
		require_once DOL_DOCUMENT_ROOT.'/core/class/comment.class.php';
7378
7379
		$comment = new Comment($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\CommonObject. Did you maybe forget to declare it?
Loading history...
Bug introduced by
The type Alixar\Base\Comment was not found. Did you mean Comment? If so, make sure to prefix the type with \.
Loading history...
7380
		$result=$comment->fetchAllFor($this->element, $this->id);
7381
		if ($result<0) {
7382
			$this->errors=array_merge($this->errors, $comment->errors);
7383
			return -1;
7384
		} else {
7385
			$this->comments = $comment->comments;
7386
		}
7387
		return count($this->comments);
7388
	}
7389
7390
	/**
7391
	 * Return nb comments already posted
7392
	 *
7393
	 * @return int
7394
	 */
7395
	public function getNbComments()
7396
	{
7397
		return count($this->comments);
7398
	}
7399
7400
    /**
7401
     * Trim object parameters
7402
     * @param string[] $parameters array of parameters to trim
7403
     *
7404
     * @return void
7405
     */
7406
    public function trimParameters($parameters)
7407
    {
7408
        if (!is_array($parameters)) return;
7409
        foreach ($parameters as $parameter) {
7410
            if (isset($this->$parameter)) {
7411
                $this->$parameter = trim($this->$parameter);
7412
            }
7413
        }
7414
    }
7415
}
7416