Passed
Push — master ( 8f7a8e...7e4a07 )
by Alxarafe
20:11
created
dolibarr/htdocs/core/class/workboardresponse.class.php 1 patch
Indentation   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -25,51 +25,51 @@
 block discarded – undo
25 25
 class WorkboardResponse
26 26
 {
27 27
 
28
-	/**
29
-	 * Image URL to represent the board item
30
-	 * @var string
31
-	 */
32
-	public $img;
28
+    /**
29
+     * Image URL to represent the board item
30
+     * @var string
31
+     */
32
+    public $img;
33 33
 
34
-	/**
35
-	 * Label of the warning
36
-	 * @var string
37
-	 */
38
-	public $label;
34
+    /**
35
+     * Label of the warning
36
+     * @var string
37
+     */
38
+    public $label;
39 39
 
40
-	/**
41
-	 * URL to list to do items
42
-	 * @var string
43
-	 */
44
-	public $url;
40
+    /**
41
+     * URL to list to do items
42
+     * @var string
43
+     */
44
+    public $url;
45 45
 
46
-	/**
47
-	 * (optional) If set, to do late items will link to this url
48
-	 * @var string
49
-	 */
50
-	public $url_late;
46
+    /**
47
+     * (optional) If set, to do late items will link to this url
48
+     * @var string
49
+     */
50
+    public $url_late;
51 51
 
52
-	/**
53
-	 * Delay time to mark an item as late. In number of days.
54
-	 * @var double
55
-	 */
56
-	public $warning_delay;
52
+    /**
53
+     * Delay time to mark an item as late. In number of days.
54
+     * @var double
55
+     */
56
+    public $warning_delay;
57 57
 
58
-	/**
59
-	 * Number of items to do
60
-	 * @var int
61
-	 */
62
-	public $nbtodo = 0;
58
+    /**
59
+     * Number of items to do
60
+     * @var int
61
+     */
62
+    public $nbtodo = 0;
63 63
 
64
-	/**
65
-	 * Number of to do items which are late
66
-	 * @var int
67
-	 */
68
-	public $nbtodolate = 0;
64
+    /**
65
+     * Number of to do items which are late
66
+     * @var int
67
+     */
68
+    public $nbtodolate = 0;
69 69
 
70
-	/**
71
-	 * total price of items
72
-	 * @var int
73
-	 */
74
-	public $total = 0;
70
+    /**
71
+     * total price of items
72
+     * @var int
73
+     */
74
+    public $total = 0;
75 75
 }
Please login to merge, or discard this patch.
dolibarr/htdocs/core/class/commonobject.class.php 1 patch
Indentation   +7091 added lines, -7091 removed lines patch added patch discarded remove patch
@@ -41,7387 +41,7387 @@
 block discarded – undo
41 41
  */
42 42
 abstract class CommonObject
43 43
 {
44
-	/**
45
-	 * @var DoliDb		Database handler (result of a new DoliDB)
46
-	 */
47
-	public $db;
48
-
49
-	/**
50
-	 * @var int The object identifier
51
-	 */
52
-	public $id;
53
-
54
-	/**
55
-	 * @var string 		Error string
56
-	 * @see             errors
57
-	 */
58
-	public $error;
59
-
60
-	/**
61
-	 * @var string[]	Array of error strings
62
-	 */
63
-	public $errors=array();
64
-
65
-	/**
66
-	 * @var string ID to identify managed object
67
-	 */
68
-	public $element;
69
-
70
-	/**
71
-	 * @var string Name of table without prefix where object is stored
72
-	 */
73
-	public $table_element;
74
-
75
-	/**
76
-	 * @var int    Name of subtable line
77
-	 */
78
-	public $table_element_line='';
79
-
80
-	/**
81
-	 * @var string		Key value used to track if data is coming from import wizard
82
-	 */
83
-	public $import_key;
84
-
85
-	/**
86
-	 * @var mixed		Contains data to manage extrafields
87
-	 */
88
-	public $array_options=array();
89
-
90
-	/**
91
-	 * @var int[][]		Array of linked objects ids. Loaded by ->fetchObjectLinked
92
-	 */
93
-	public $linkedObjectsIds;
94
-
95
-	/**
96
-	 * @var mixed		Array of linked objects. Loaded by ->fetchObjectLinked
97
-	 */
98
-	public $linkedObjects;
99
-
100
-	/**
101
-	 * @var Object      To store a cloned copy of object before to edit it and keep track of old properties
102
-	 */
103
-	public $oldcopy;
104
-
105
-	/**
106
-	 * @var string		Column name of the ref field.
107
-	 */
108
-	protected $table_ref_field = '';
109
-
110
-
111
-
112
-	// Following vars are used by some objects only. We keep this property here in CommonObject to be able to provide common method using them.
113
-
114
-	/**
115
-	 * @var array<string,mixed>		Can be used to pass information when only object is provided to method
116
-	 */
117
-	public $context=array();
118
-
119
-	/**
120
-	 * @var string		Contains canvas name if record is an alternative canvas record
121
-	 */
122
-	public $canvas;
123
-
124
-	/**
125
-	 * @var Project The related project
126
-	 * @see fetch_projet()
127
-	 */
128
-	public $project;
129
-
130
-	/**
131
-	 * @var int The related project ID
132
-	 * @see setProject(), project
133
-	 */
134
-	public $fk_project;
135
-
136
-	/**
137
-	 * @deprecated
138
-	 * @see project
139
-	 */
140
-	public $projet;
141
-
142
-	/**
143
-	 * @var Contact a related contact
144
-	 * @see fetch_contact()
145
-	 */
146
-	public $contact;
147
-
148
-	/**
149
-	 * @var int The related contact ID
150
-	 * @see fetch_contact()
151
-	 */
152
-	public $contact_id;
153
-
154
-	/**
155
-	 * @var Societe A related thirdparty
156
-	 * @see fetch_thirdparty()
157
-	 */
158
-	public $thirdparty;
159
-
160
-	/**
161
-	 * @var User A related user
162
-	 * @see fetch_user()
163
-	 */
164
-	public $user;
165
-
166
-	/**
167
-	 * @var string 	The type of originating object ('commande', 'facture', ...)
168
-	 * @see fetch_origin()
169
-	 */
170
-	public $origin;
171
-
172
-	/**
173
-	 * @var int 	The id of originating object
174
-	 * @see fetch_origin()
175
-	 */
176
-	public $origin_id;
177
-
178
-	/**
179
-	 * @var string The object's reference
180
-	 */
181
-	public $ref;
182
-
183
-	/**
184
-	 * @var string The object's previous reference
185
-	 */
186
-	public $ref_previous;
187
-
188
-	/**
189
-	 * @var string The object's next reference
190
-	 */
191
-	public $ref_next;
192
-
193
-	/**
194
-	 * @var string An external reference for the object
195
-	 */
196
-	public $ref_ext;
197
-
198
-	/**
199
-	 * @var int The object's status
200
-	 * @see setStatut()
201
-	 */
202
-	public $statut;
203
-
204
-	/**
205
-	 * @var string
206
-	 * @see getFullAddress()
207
-	 */
208
-	public $country;
209
-
210
-	/**
211
-	 * @var int
212
-	 * @see getFullAddress(), country
213
-	 */
214
-	public $country_id;
215
-
216
-	/**
217
-	 * @var string
218
-	 * @see getFullAddress(), isInEEC(), country
219
-	 */
220
-    public $country_code;
221
-
222 44
     /**
223
-	 * @var string
224
-	 * @see getFullAddress()
225
-	 */
226
-	public $state;
227
-
228
-	/**
229
-	 * @var int
230
-	 * @see getFullAddress(), state
231
-	 */
232
-	public $state_id;
45
+     * @var DoliDb		Database handler (result of a new DoliDB)
46
+     */
47
+    public $db;
233 48
 
234
-	/**
235
-	 * @var string
236
-	 * @see getFullAddress(), state
237
-	 */
238
-    public $state_code;
49
+    /**
50
+     * @var int The object identifier
51
+     */
52
+    public $id;
239 53
 
240 54
     /**
241
-	 * @var string
242
-	 * @see getFullAddress(), region
243
-	 */
244
-	public $region;
55
+     * @var string 		Error string
56
+     * @see             errors
57
+     */
58
+    public $error;
245 59
 
246
-	/**
247
-	 * @var string
248
-	 * @see getFullAddress(), region
249
-	 */
250
-    public $region_code;
60
+    /**
61
+     * @var string[]	Array of error strings
62
+     */
63
+    public $errors=array();
251 64
 
252
-	/**
253
-	 * @var int
254
-	 * @see fetch_barcode()
255
-	 */
256
-	public $barcode_type;
257
-
258
-	/**
259
-	 * @var string
260
-	 * @see fetch_barcode(), barcode_type
261
-	 */
262
-	public $barcode_type_code;
263
-
264
-	/**
265
-	 * @var string
266
-	 * @see fetch_barcode(), barcode_type
267
-	 */
268
-	public $barcode_type_label;
269
-
270
-	/**
271
-	 * @var string
272
-	 * @see fetch_barcode(), barcode_type
273
-	 */
274
-	public $barcode_type_coder;
275
-
276
-	/**
277
-	 * @var int Payment method ID (cheque, cash, ...)
278
-	 * @see setPaymentMethods()
279
-	 */
280
-	public $mode_reglement_id;
281
-
282
-	/**
283
-	 * @var int Payment terms ID
284
-	 * @see setPaymentTerms()
285
-	 */
286
-	public $cond_reglement_id;
287
-
288
-	/**
289
-	 * @var int Payment terms ID
290
-	 * @deprecated Kept for compatibility
291
-	 * @see cond_reglement_id;
292
-	 */
293
-	public $cond_reglement;
294
-
295
-	/**
296
-	 * @var int Delivery address ID
297
-	 * @deprecated
298
-	 * @see setDeliveryAddress()
299
-	 */
300
-	public $fk_delivery_address;
301
-
302
-	/**
303
-	 * @var int Shipping method ID
304
-	 * @see setShippingMethod()
305
-	 */
306
-	public $shipping_method_id;
307
-
308
-	/**
309
-	 * @var string
310
-	 * @see SetDocModel()
311
-	 */
312
-	public $modelpdf;
313
-
314
-	/**
315
-	 * @var int Bank account ID
316
-	 * @see SetBankAccount()
317
-	 */
318
-	public $fk_account;
319
-
320
-	/**
321
-	 * @var string Public note
322
-	 * @see update_note()
323
-	 */
324
-	public $note_public;
325
-
326
-	/**
327
-	 * @var string Private note
328
-	 * @see update_note()
329
-	 */
330
-	public $note_private;
331
-
332
-	/**
333
-	 * @deprecated
334
-	 * @see note_public
335
-	 */
336
-	public $note;
337
-
338
-	/**
339
-	 * @var float Total amount before taxes
340
-	 * @see update_price()
341
-	 */
342
-	public $total_ht;
343
-
344
-	/**
345
-	 * @var float Total VAT amount
346
-	 * @see update_price()
347
-	 */
348
-	public $total_tva;
349
-
350
-	/**
351
-	 * @var float Total local tax 1 amount
352
-	 * @see update_price()
353
-	 */
354
-	public $total_localtax1;
355
-
356
-	/**
357
-	 * @var float Total local tax 2 amount
358
-	 * @see update_price()
359
-	 */
360
-	public $total_localtax2;
361
-
362
-	/**
363
-	 * @var float Total amount with taxes
364
-	 * @see update_price()
365
-	 */
366
-	public $total_ttc;
367
-
368
-	/**
369
-	 * @var CommonObjectLine[]
370
-	 */
371
-	public $lines;
372
-
373
-	/**
374
-	 * @var mixed		Contains comments
375
-	 * @see fetchComments()
376
-	 */
377
-	public $comments=array();
378
-
379
-	/**
380
-	 * @var int
381
-	 * @see setIncoterms()
382
-	 */
383
-	public $fk_incoterms;
384
-
385
-	/**
386
-	 * @var string
387
-	 * @see SetIncoterms()
388
-	 */
389
-	public $libelle_incoterms;
390
-
391
-	/**
392
-	 * @var string
393
-	 * @see display_incoterms()
394
-	 */
395
-	public $location_incoterms;
396
-
397
-	public $name;
398
-	public $lastname;
399
-	public $firstname;
400
-	public $civility_id;
401
-
402
-	// Dates
403
-	public $date_creation;			// Date creation
404
-	public $date_validation;		// Date validation
405
-	public $date_modification;		// Date last change (tms field)
406
-
407
-
408
-
409
-	// No constructor as it is an abstract class
410
-
411
-	/**
412
-	 * Check an object id/ref exists
413
-	 * If you don't need/want to instantiate object and just need to know if object exists, use this method instead of fetch
414
-	 *
415
-	 *  @param	string	$element   	String of element ('product', 'facture', ...)
416
-	 *  @param	int		$id      	Id of object
417
-	 *  @param  string	$ref     	Ref of object to check
418
-	 *  @param	string	$ref_ext	Ref ext of object to check
419
-	 *  @return int     			<0 if KO, 0 if OK but not found, >0 if OK and exists
420
-	 */
421
-	static function isExistingObject($element, $id, $ref='', $ref_ext='')
422
-	{
423
-		global $db,$conf;
424
-
425
-		$sql = "SELECT rowid, ref, ref_ext";
426
-		$sql.= " FROM ".MAIN_DB_PREFIX.$element;
427
-		$sql.= " WHERE entity IN (".getEntity($element).")" ;
428
-
429
-		if ($id > 0) $sql.= " AND rowid = ".$db->escape($id);
430
-		else if ($ref) $sql.= " AND ref = '".$db->escape($ref)."'";
431
-		else if ($ref_ext) $sql.= " AND ref_ext = '".$db->escape($ref_ext)."'";
432
-		else {
433
-			$error='ErrorWrongParameters';
434
-			dol_print_error(get_class()."::isExistingObject ".$error, LOG_ERR);
435
-			return -1;
436
-		}
437
-		if ($ref || $ref_ext) $sql.= " AND entity = ".$conf->entity;
438
-
439
-		dol_syslog(get_class()."::isExistingObject", LOG_DEBUG);
440
-		$resql = $db->query($sql);
441
-		if ($resql)
442
-		{
443
-			$num=$db->num_rows($resql);
444
-			if ($num > 0) return 1;
445
-			else return 0;
446
-		}
447
-		return -1;
448
-	}
449
-
450
-	/**
451
-	 * Method to output saved errors
452
-	 *
453
-	 * @return	string		String with errors
454
-	 */
455
-	function errorsToString()
456
-	{
457
-		return $this->error.(is_array($this->errors)?(($this->error!=''?', ':'').join(', ',$this->errors)):'');
458
-	}
459
-
460
-	/**
461
-	 *	Return full name (civility+' '+name+' '+lastname)
462
-	 *
463
-	 *	@param	Translate	$langs			Language object for translation of civility (used only if option is 1)
464
-	 *	@param	int			$option			0=No option, 1=Add civility
465
-	 * 	@param	int			$nameorder		-1=Auto, 0=Lastname+Firstname, 1=Firstname+Lastname, 2=Firstname
466
-	 * 	@param	int			$maxlen			Maximum length
467
-	 * 	@return	string						String with full name
468
-	 */
469
-	function getFullName($langs,$option=0,$nameorder=-1,$maxlen=0)
470
-	{
471
-		//print "lastname=".$this->lastname." name=".$this->name." nom=".$this->nom."<br>\n";
472
-		$lastname=$this->lastname;
473
-		$firstname=$this->firstname;
474
-		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:'')))));
475
-
476
-		$ret='';
477
-		if ($option && $this->civility_id)
478
-		{
479
-			if ($langs->transnoentitiesnoconv("Civility".$this->civility_id)!="Civility".$this->civility_id) $ret.=$langs->transnoentitiesnoconv("Civility".$this->civility_id).' ';
480
-			else $ret.=$this->civility_id.' ';
481
-		}
482
-
483
-		$ret.=dolGetFirstLastname($firstname, $lastname, $nameorder);
484
-
485
-		return dol_trunc($ret,$maxlen);
486
-	}
487
-
488
-	/**
489
-	 * 	Return full address of contact
490
-	 *
491
-	 * 	@param		int			$withcountry		1=Add country into address string
492
-	 *  @param		string		$sep				Separator to use to build string
493
-	 *  @param		int		    $withregion			1=Add region into address string
494
-	 *	@return		string							Full address string
495
-	 */
496
-	function getFullAddress($withcountry=0, $sep="\n", $withregion=0)
497
-	{
498
-		if ($withcountry && $this->country_id && (empty($this->country_code) || empty($this->country)))
499
-		{
500
-			require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php';
501
-			$tmparray=getCountry($this->country_id,'all');
502
-			$this->country_code=$tmparray['code'];
503
-			$this->country     =$tmparray['label'];
504
-		}
65
+    /**
66
+     * @var string ID to identify managed object
67
+     */
68
+    public $element;
505 69
 
506
-        if ($withregion && $this->state_id && (empty($this->state_code) || empty($this->state) || empty($this->region) || empty($this->region_cpde)))
507
-    	{
508
-    		require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php';
509
-    		$tmparray=getState($this->state_id,'all',0,1);
510
-			$this->state_code   =$tmparray['code'];
511
-			$this->state        =$tmparray['label'];
512
-			$this->region_code  =$tmparray['region_code'];
513
-			$this->region       =$tmparray['region'];
514
-        }
515
-
516
-		return dol_format_address($this, $withcountry, $sep);
517
-	}
518
-
519
-
520
-	/**
521
-	 * 	Return full address for banner
522
-	 *
523
-	 * 	@param		string		$htmlkey            HTML id to make banner content unique
524
-	 *  @param      Object      $object				Object (thirdparty, thirdparty of contact for contact, null for a member)
525
-	 *	@return		string							Full address string
526
-	 */
527
-	function getBannerAddress($htmlkey, $object)
528
-	{
529
-		global $conf, $langs;
530
-
531
-		$countriesusingstate=array('AU','US','IN','GB','ES','UK','TR');    // See also option MAIN_FORCE_STATE_INTO_ADDRESS
532
-
533
-		$contactid=0;
534
-		$thirdpartyid=0;
535
-		if ($this->element == 'societe')
536
-		{
537
-			$thirdpartyid=$this->id;
538
-		}
539
-		if ($this->element == 'contact')
540
-		{
541
-			$contactid=$this->id;
542
-			$thirdpartyid=$object->fk_soc;
543
-		}
544
-		if ($this->element == 'user')
545
-		{
546
-			$contactid=$this->contact_id;
547
-			$thirdpartyid=$object->fk_soc;
548
-		}
549
-
550
-		$out='<!-- BEGIN part to show address block -->';
551
-
552
-		$outdone=0;
553
-		$coords = $this->getFullAddress(1,', ',$conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT);
554
-		if ($coords)
555
-		{
556
-			if (! empty($conf->use_javascript_ajax))
557
-			{
558
-				$namecoords = $this->getFullName($langs,1).'<br>'.$coords;
559
-				// hideonsmatphone because copyToClipboard call jquery dialog that does not work with jmobile
560
-				$out.='<a href="#" class="hideonsmartphone" onclick="return copyToClipboard(\''.dol_escape_js($namecoords).'\',\''.dol_escape_js($langs->trans("HelpCopyToClipboard")).'\');">';
561
-				$out.=img_picto($langs->trans("Address"), 'object_address.png');
562
-				$out.='</a> ';
563
-			}
564
-			$out.=dol_print_address($coords, 'address_'.$htmlkey.'_'.$this->id, $this->element, $this->id, 1, ', '); $outdone++;
565
-			$outdone++;
566
-		}
567
-
568
-		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
569
-				&& empty($conf->global->SOCIETE_DISABLE_STATE) && $this->state)
570
-		{
571
-            if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 && $this->region) {
572
-                $out.=($outdone?' - ':'').$this->region.' - '.$this->state;
573
-            }
574
-            else {
575
-                $out.=($outdone?' - ':'').$this->state;
576
-            }
577
-			$outdone++;
578
-		}
579
-
580
-		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>':'');
581
-		if (! empty($this->phone) && empty($this->phone_pro)) {		// For objects that store pro phone into ->phone
582
-			$out.=dol_print_phone($this->phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
583
-		}
584
-		if (! empty($this->phone_pro)) {
585
-			$out.=dol_print_phone($this->phone_pro,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
586
-		}
587
-		if (! empty($this->phone_mobile)) {
588
-			$out.=dol_print_phone($this->phone_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','mobile',$langs->trans("PhoneMobile")); $outdone++;
589
-		}
590
-		if (! empty($this->phone_perso)) {
591
-			$out.=dol_print_phone($this->phone_perso,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePerso")); $outdone++;
592
-		}
593
-		if (! empty($this->office_phone)) {
594
-			$out.=dol_print_phone($this->office_phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
595
-		}
596
-		if (! empty($this->user_mobile)) {
597
-			$out.=dol_print_phone($this->user_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','mobile',$langs->trans("PhoneMobile")); $outdone++;
598
-		}
599
-		if (! empty($this->fax)) {
600
-			$out.=dol_print_phone($this->fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX','&nbsp;','fax',$langs->trans("Fax")); $outdone++;
601
-		}
602
-		if (! empty($this->office_fax)) {
603
-			$out.=dol_print_phone($this->office_fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX','&nbsp;','fax',$langs->trans("Fax")); $outdone++;
604
-		}
605
-
606
-		$out.='<div style="clear: both;"></div>';
607
-		$outdone=0;
608
-		if (! empty($this->email))
609
-		{
610
-			$out.=dol_print_email($this->email,$this->id,$object->id,'AC_EMAIL',0,0,1);
611
-			$outdone++;
612
-		}
613
-		if (! empty($this->url))
614
-		{
615
-			$out.=dol_print_url($this->url,'_goout',0,1);
616
-			$outdone++;
617
-		}
618
-		$out.='<div style="clear: both;">';
619
-		if (! empty($conf->socialnetworks->enabled))
620
-		{
621
-			if ($this->skype) $out.=dol_print_socialnetworks($this->skype,$this->id,$object->id,'skype');
622
-			$outdone++;
623
-			if ($this->jabberid) $out.=dol_print_socialnetworks($this->jabberid,$this->id,$object->id,'jabber');
624
-			$outdone++;
625
-			if ($this->twitter) $out.=dol_print_socialnetworks($this->twitter,$this->id,$object->id,'twitter');
626
-			$outdone++;
627
-			if ($this->facebook) $out.=dol_print_socialnetworks($this->facebook,$this->id,$object->id,'facebook');
628
-			$outdone++;
629
-		}
630
-		$out.='</div>';
631
-
632
-		$out.='<!-- END Part to show address block -->';
633
-
634
-		return $out;
635
-	}
636
-
637
-	/**
638
-	 * Return the link of last main doc file for direct public download.
639
-	 *
640
-	 * @param	string	$modulepart			Module related to document
641
-	 * @param	int		$initsharekey		Init the share key if it was not yet defined
642
-	 * @param	int		$relativelink		0=Return full external link, 1=Return link relative to root of file
643
-	 * @return	string						Link or empty string if there is no download link
644
-	 */
645
-	function getLastMainDocLink($modulepart, $initsharekey=0, $relativelink=0)
646
-	{
647
-		global $user, $dolibarr_main_url_root;
648
-
649
-		if (empty($this->last_main_doc))
650
-		{
651
-			return '';		// No way to known which document name to use
652
-		}
653
-
654
-		include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
655
-		$ecmfile=new EcmFiles($this->db);
656
-		$result = $ecmfile->fetch(0, '', $this->last_main_doc);
657
-		if ($result < 0)
658
-		{
659
-			$this->error = $ecmfile->error;
660
-			$this->errors = $ecmfile->errors;
661
-			return -1;
662
-		}
663
-
664
-		if (empty($ecmfile->id))
665
-		{
666
-			// Add entry into index
667
-			if ($initsharekey)
668
-			{
669
-				require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
670
-				// TODO We can't, we dont' have full path of file, only last_main_doc adn ->element, so we must rebuild full path first
671
-				/*
672
-				$ecmfile->filepath = $rel_dir;
673
-				$ecmfile->filename = $filename;
674
-				$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
675
-				$ecmfile->fullpath_orig = '';
676
-				$ecmfile->gen_or_uploaded = 'generated';
677
-				$ecmfile->description = '';    // indexed content
678
-				$ecmfile->keyword = '';        // keyword content
679
-				$ecmfile->share = getRandomPassword(true);
680
-				$result = $ecmfile->create($user);
681
-				if ($result < 0)
682
-				{
683
-					$this->error = $ecmfile->error;
684
-					$this->errors = $ecmfile->errors;
685
-				}
686
-				*/
687
-			}
688
-			else return '';
689
-		}
690
-		elseif (empty($ecmfile->share))
691
-		{
692
-			// Add entry into index
693
-			if ($initsharekey)
694
-			{
695
-				require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
696
-				$ecmfile->share = getRandomPassword(true);
697
-				$ecmfile->update($user);
698
-			}
699
-			else return '';
700
-		}
701
-
702
-		// Define $urlwithroot
703
-		$urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
704
-		$urlwithroot=$urlwithouturlroot.DOL_URL_ROOT;		// This is to use external domain name found into config file
705
-		//$urlwithroot=DOL_MAIN_URL_ROOT;					// This is to use same domain name than current
706
-
707
-		$forcedownload=0;
708
-
709
-		$paramlink='';
710
-		//if (! empty($modulepart)) $paramlink.=($paramlink?'&':'').'modulepart='.$modulepart;		// For sharing with hash (so public files), modulepart is not required.
711
-		//if (! empty($ecmfile->entity)) $paramlink.='&entity='.$ecmfile->entity; 					// For sharing with hash (so public files), entity is not required.
712
-		//$paramlink.=($paramlink?'&':'').'file='.urlencode($filepath);								// No need of name of file for public link, we will use the hash
713
-		if (! empty($ecmfile->share)) $paramlink.=($paramlink?'&':'').'hashp='.$ecmfile->share;			// Hash for public share
714
-		if ($forcedownload) $paramlink.=($paramlink?'&':'').'attachment=1';
715
-
716
-		if ($relativelink)
717
-		{
718
-			$linktoreturn='document.php'.($paramlink?'?'.$paramlink:'');
719
-		}
720
-		else
721
-		{
722
-			$linktoreturn=$urlwithroot.'/document.php'.($paramlink?'?'.$paramlink:'');
723
-		}
724
-
725
-		// Here $ecmfile->share is defined
726
-		return $linktoreturn;
727
-	}
70
+    /**
71
+     * @var string Name of table without prefix where object is stored
72
+     */
73
+    public $table_element;
728 74
 
75
+    /**
76
+     * @var int    Name of subtable line
77
+     */
78
+    public $table_element_line='';
729 79
 
730
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
731
-	/**
732
-	 *  Add a link between element $this->element and a contact
733
-	 *
734
-	 *  @param	int		$fk_socpeople       Id of thirdparty contact (if source = 'external') or id of user (if souce = 'internal') to link
735
-	 *  @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
736
-	 *  @param  string	$source             external=Contact extern (llx_socpeople), internal=Contact intern (llx_user)
737
-	 *  @param  int		$notrigger			Disable all triggers
738
-	 *  @return int                 		<0 if KO, >0 if OK
739
-	 */
740
-	function add_contact($fk_socpeople, $type_contact, $source='external',$notrigger=0)
741
-	{
742
-        // phpcs:enable
743
-		global $user,$langs;
744
-
745
-
746
-		dol_syslog(get_class($this)."::add_contact $fk_socpeople, $type_contact, $source, $notrigger");
747
-
748
-		// Check parameters
749
-		if ($fk_socpeople <= 0)
750
-		{
751
-			$langs->load("errors");
752
-			$this->error=$langs->trans("ErrorWrongValueForParameterX","1");
753
-			dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
754
-			return -1;
755
-		}
756
-		if (! $type_contact)
757
-		{
758
-			$langs->load("errors");
759
-			$this->error=$langs->trans("ErrorWrongValueForParameterX","2");
760
-			dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
761
-			return -2;
762
-		}
763
-
764
-		$id_type_contact=0;
765
-		if (is_numeric($type_contact))
766
-		{
767
-			$id_type_contact=$type_contact;
768
-		}
769
-		else
770
-		{
771
-			// We look for id type_contact
772
-			$sql = "SELECT tc.rowid";
773
-			$sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
774
-			$sql.= " WHERE tc.element='".$this->db->escape($this->element)."'";
775
-			$sql.= " AND tc.source='".$this->db->escape($source)."'";
776
-			$sql.= " AND tc.code='".$this->db->escape($type_contact)."' AND tc.active=1";
777
-			//print $sql;
778
-			$resql=$this->db->query($sql);
779
-			if ($resql)
780
-			{
781
-				$obj = $this->db->fetch_object($resql);
782
-				if ($obj) $id_type_contact=$obj->rowid;
783
-			}
784
-		}
785
-
786
-		if ($id_type_contact == 0)
787
-		{
788
-			$this->error='CODE_NOT_VALID_FOR_THIS_ELEMENT';
789
-			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");
790
-			return -3;
791
-		}
792
-
793
-		$datecreate = dol_now();
794
-
795
-		// Socpeople must have already been added by some trigger, then we have to check it to avoid DB_ERROR_RECORD_ALREADY_EXISTS error
796
-		$TListeContacts=$this->liste_contact(-1, $source);
797
-		$already_added=false;
798
-		if(!empty($TListeContacts)) {
799
-			foreach($TListeContacts as $array_contact) {
800
-				if($array_contact['status'] == 4 && $array_contact['id'] == $fk_socpeople && $array_contact['fk_c_type_contact'] == $id_type_contact) {
801
-					$already_added=true;
802
-					break;
803
-				}
804
-			}
805
-		}
80
+    /**
81
+     * @var string		Key value used to track if data is coming from import wizard
82
+     */
83
+    public $import_key;
806 84
 
807
-		if(!$already_added) {
85
+    /**
86
+     * @var mixed		Contains data to manage extrafields
87
+     */
88
+    public $array_options=array();
808 89
 
809
-			$this->db->begin();
90
+    /**
91
+     * @var int[][]		Array of linked objects ids. Loaded by ->fetchObjectLinked
92
+     */
93
+    public $linkedObjectsIds;
810 94
 
811
-			// Insert into database
812
-			$sql = "INSERT INTO ".MAIN_DB_PREFIX."element_contact";
813
-			$sql.= " (element_id, fk_socpeople, datecreate, statut, fk_c_type_contact) ";
814
-			$sql.= " VALUES (".$this->id.", ".$fk_socpeople." , " ;
815
-			$sql.= "'".$this->db->idate($datecreate)."'";
816
-			$sql.= ", 4, ". $id_type_contact;
817
-			$sql.= ")";
95
+    /**
96
+     * @var mixed		Array of linked objects. Loaded by ->fetchObjectLinked
97
+     */
98
+    public $linkedObjects;
818 99
 
819
-			$resql=$this->db->query($sql);
820
-			if ($resql)
821
-			{
822
-				if (! $notrigger)
823
-				{
824
-					$result=$this->call_trigger(strtoupper($this->element).'_ADD_CONTACT', $user);
825
-					if ($result < 0)
826
-					{
827
-						$this->db->rollback();
828
-						return -1;
829
-					}
830
-				}
100
+    /**
101
+     * @var Object      To store a cloned copy of object before to edit it and keep track of old properties
102
+     */
103
+    public $oldcopy;
831 104
 
832
-				$this->db->commit();
833
-				return 1;
834
-			}
835
-			else
836
-			{
837
-				if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS')
838
-				{
839
-					$this->error=$this->db->errno();
840
-					$this->db->rollback();
841
-					echo 'err rollback';
842
-					return -2;
843
-				}
844
-				else
845
-				{
846
-					$this->error=$this->db->error();
847
-					$this->db->rollback();
848
-					return -1;
849
-				}
850
-			}
851
-		} else return 0;
852
-	}
105
+    /**
106
+     * @var string		Column name of the ref field.
107
+     */
108
+    protected $table_ref_field = '';
853 109
 
854
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
855
-	/**
856
-	 *    Copy contact from one element to current
857
-	 *
858
-	 *    @param    CommonObject    $objFrom    Source element
859
-	 *    @param    string          $source     Nature of contact ('internal' or 'external')
860
-	 *    @return   int                         >0 if OK, <0 if KO
861
-	 */
862
-	function copy_linked_contact($objFrom, $source='internal')
863
-	{
864
-        // phpcs:enable
865
-		$contacts = $objFrom->liste_contact(-1, $source);
866
-		foreach($contacts as $contact)
867
-		{
868
-			if ($this->add_contact($contact['id'], $contact['fk_c_type_contact'], $contact['source']) < 0)
869
-			{
870
-				$this->error=$this->db->lasterror();
871
-				return -1;
872
-			}
873
-		}
874
-		return 1;
875
-	}
876 110
 
877
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
878
-	/**
879
-	 *      Update a link to contact line
880
-	 *
881
-	 *      @param	int		$rowid              Id of line contact-element
882
-	 * 		@param	int		$statut	            New status of link
883
-	 *      @param  int		$type_contact_id    Id of contact type (not modified if 0)
884
-	 *      @param  int		$fk_socpeople	    Id of soc_people to update (not modified if 0)
885
-	 *      @return int                 		<0 if KO, >= 0 if OK
886
-	 */
887
-	function update_contact($rowid, $statut, $type_contact_id=0, $fk_socpeople=0)
888
-	{
889
-        // phpcs:enable
890
-		// Insert into database
891
-		$sql = "UPDATE ".MAIN_DB_PREFIX."element_contact set";
892
-		$sql.= " statut = ".$statut;
893
-		if ($type_contact_id) $sql.= ", fk_c_type_contact = '".$type_contact_id ."'";
894
-		if ($fk_socpeople) $sql.= ", fk_socpeople = '".$fk_socpeople ."'";
895
-		$sql.= " where rowid = ".$rowid;
896
-		$resql=$this->db->query($sql);
897
-		if ($resql)
898
-		{
899
-			return 0;
900
-		}
901
-		else
902
-		{
903
-			$this->error=$this->db->lasterror();
904
-			return -1;
905
-		}
906
-	}
907 111
 
908
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
909
-	/**
910
-	 *    Delete a link to contact line
911
-	 *
912
-	 *    @param	int		$rowid			Id of contact link line to delete
913
-	 *    @param	int		$notrigger		Disable all triggers
914
-	 *    @return   int						>0 if OK, <0 if KO
915
-	 */
916
-	function delete_contact($rowid, $notrigger=0)
917
-	{
918
-        // phpcs:enable
919
-		global $user;
112
+    // Following vars are used by some objects only. We keep this property here in CommonObject to be able to provide common method using them.
920 113
 
114
+    /**
115
+     * @var array<string,mixed>		Can be used to pass information when only object is provided to method
116
+     */
117
+    public $context=array();
921 118
 
922
-		$this->db->begin();
119
+    /**
120
+     * @var string		Contains canvas name if record is an alternative canvas record
121
+     */
122
+    public $canvas;
923 123
 
924
-		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
925
-		$sql.= " WHERE rowid =".$rowid;
124
+    /**
125
+     * @var Project The related project
126
+     * @see fetch_projet()
127
+     */
128
+    public $project;
926 129
 
927
-		dol_syslog(get_class($this)."::delete_contact", LOG_DEBUG);
928
-		if ($this->db->query($sql))
929
-		{
930
-			if (! $notrigger)
931
-			{
932
-				$result=$this->call_trigger(strtoupper($this->element).'_DELETE_CONTACT', $user);
933
-				if ($result < 0) { $this->db->rollback(); return -1; }
934
-			}
935
-
936
-			$this->db->commit();
937
-			return 1;
938
-		}
939
-		else
940
-		{
941
-			$this->error=$this->db->lasterror();
942
-			$this->db->rollback();
943
-			return -1;
944
-		}
945
-	}
130
+    /**
131
+     * @var int The related project ID
132
+     * @see setProject(), project
133
+     */
134
+    public $fk_project;
946 135
 
947
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
948
-	/**
949
-	 *    Delete all links between an object $this and all its contacts
950
-	 *
951
-	 *	  @param	string	$source		'' or 'internal' or 'external'
952
-	 *	  @param	string	$code		Type of contact (code or id)
953
-	 *    @return   int					>0 if OK, <0 if KO
954
-	 */
955
-	function delete_linked_contact($source='',$code='')
956
-	{
957
-        // phpcs:enable
958
-		$temp = array();
959
-		$typeContact = $this->liste_type_contact($source,'',0,0,$code);
960
-
961
-		foreach($typeContact as $key => $value)
962
-		{
963
-			array_push($temp,$key);
964
-		}
965
-		$listId = implode(",", $temp);
966
-
967
-		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
968
-		$sql.= " WHERE element_id = ".$this->id;
969
-		if ($listId)
970
-			$sql.= " AND fk_c_type_contact IN (".$listId.")";
971
-
972
-		dol_syslog(get_class($this)."::delete_linked_contact", LOG_DEBUG);
973
-		if ($this->db->query($sql))
974
-		{
975
-			return 1;
976
-		}
977
-		else
978
-		{
979
-			$this->error=$this->db->lasterror();
980
-			return -1;
981
-		}
982
-	}
136
+    /**
137
+     * @deprecated
138
+     * @see project
139
+     */
140
+    public $projet;
983 141
 
984
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
985
-	/**
986
-	 *    Get array of all contacts for an object
987
-	 *
988
-	 *    @param	int			$statut		Status of links to get (-1=all)
989
-	 *    @param	string		$source		Source of contact: external or thirdparty (llx_socpeople) or internal (llx_user)
990
-	 *    @param	int         $list       0:Return array contains all properties, 1:Return array contains just id
991
-	 *    @param    string      $code       Filter on this code of contact type ('SHIPPING', 'BILLING', ...)
992
-	 *    @return	array|int		        Array of contacts, -1 if error
993
-	 */
994
-	function liste_contact($statut=-1,$source='external',$list=0,$code='')
995
-	{
996
-        // phpcs:enable
997
-		global $langs;
998
-
999
-		$tab=array();
1000
-
1001
-		$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
1002
-		if ($source == 'internal') $sql.=", '-1' as socid, t.statut as statuscontact, t.login, t.photo";
1003
-		if ($source == 'external' || $source == 'thirdparty') $sql.=", t.fk_soc as socid, t.statut as statuscontact";
1004
-		$sql.= ", t.civility as civility, t.lastname as lastname, t.firstname, t.email";
1005
-		$sql.= ", tc.source, tc.element, tc.code, tc.libelle";
1006
-		$sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact tc";
1007
-		$sql.= ", ".MAIN_DB_PREFIX."element_contact ec";
1008
-		if ($source == 'internal') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid";
1009
-		if ($source == 'external'|| $source == 'thirdparty') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid";
1010
-		$sql.= " WHERE ec.element_id =".$this->id;
1011
-		$sql.= " AND ec.fk_c_type_contact=tc.rowid";
1012
-		$sql.= " AND tc.element='".$this->db->escape($this->element)."'";
1013
-		if ($code) $sql.= " AND tc.code = '".$this->db->escape($code)."'";
1014
-		if ($source == 'internal') $sql.= " AND tc.source = 'internal'";
1015
-		if ($source == 'external' || $source == 'thirdparty') $sql.= " AND tc.source = 'external'";
1016
-		$sql.= " AND tc.active=1";
1017
-		if ($statut >= 0) $sql.= " AND ec.statut = '".$statut."'";
1018
-		$sql.=" ORDER BY t.lastname ASC";
1019
-
1020
-		dol_syslog(get_class($this)."::liste_contact", LOG_DEBUG);
1021
-		$resql=$this->db->query($sql);
1022
-		if ($resql)
1023
-		{
1024
-			$num=$this->db->num_rows($resql);
1025
-			$i=0;
1026
-			while ($i < $num)
1027
-			{
1028
-				$obj = $this->db->fetch_object($resql);
142
+    /**
143
+     * @var Contact a related contact
144
+     * @see fetch_contact()
145
+     */
146
+    public $contact;
1029 147
 
1030
-				if (! $list)
1031
-				{
1032
-					$transkey="TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
1033
-					$libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
1034
-					$tab[$i]=array('source'=>$obj->source,'socid'=>$obj->socid,'id'=>$obj->id,
1035
-								   'nom'=>$obj->lastname,      // For backward compatibility
1036
-								   'civility'=>$obj->civility, 'lastname'=>$obj->lastname, 'firstname'=>$obj->firstname, 'email'=>$obj->email, 'login'=>$obj->login, 'photo'=>$obj->photo, 'statuscontact'=>$obj->statuscontact,
1037
-								   'rowid'=>$obj->rowid, 'code'=>$obj->code, 'libelle'=>$libelle_type, 'status'=>$obj->statuslink, 'fk_c_type_contact'=>$obj->fk_c_type_contact);
1038
-				}
1039
-				else
1040
-				{
1041
-					$tab[$i]=$obj->id;
1042
-				}
148
+    /**
149
+     * @var int The related contact ID
150
+     * @see fetch_contact()
151
+     */
152
+    public $contact_id;
1043 153
 
1044
-				$i++;
1045
-			}
1046
-
1047
-			return $tab;
1048
-		}
1049
-		else
1050
-		{
1051
-			$this->error=$this->db->lasterror();
1052
-			dol_print_error($this->db);
1053
-			return -1;
1054
-		}
1055
-	}
1056
-
1057
-
1058
-	/**
1059
-	 * 		Update status of a contact linked to object
1060
-	 *
1061
-	 * 		@param	int		$rowid		Id of link between object and contact
1062
-	 * 		@return	int					<0 if KO, >=0 if OK
1063
-	 */
1064
-	function swapContactStatus($rowid)
1065
-	{
1066
-		$sql = "SELECT ec.datecreate, ec.statut, ec.fk_socpeople, ec.fk_c_type_contact,";
1067
-		$sql.= " tc.code, tc.libelle";
1068
-		//$sql.= ", s.fk_soc";
1069
-		$sql.= " FROM (".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as tc)";
1070
-		//$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
1071
-		$sql.= " WHERE ec.rowid =".$rowid;
1072
-		$sql.= " AND ec.fk_c_type_contact=tc.rowid";
1073
-		$sql.= " AND tc.element = '".$this->db->escape($this->element)."'";
1074
-
1075
-		dol_syslog(get_class($this)."::swapContactStatus", LOG_DEBUG);
1076
-		$resql=$this->db->query($sql);
1077
-		if ($resql)
1078
-		{
1079
-			$obj = $this->db->fetch_object($resql);
1080
-			$newstatut = ($obj->statut == 4) ? 5 : 4;
1081
-			$result = $this->update_contact($rowid, $newstatut);
1082
-			$this->db->free($resql);
1083
-			return $result;
1084
-		}
1085
-		else
1086
-		{
1087
-			$this->error=$this->db->error();
1088
-			dol_print_error($this->db);
1089
-			return -1;
1090
-		}
1091
-	}
154
+    /**
155
+     * @var Societe A related thirdparty
156
+     * @see fetch_thirdparty()
157
+     */
158
+    public $thirdparty;
1092 159
 
1093
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1094
-	/**
1095
-	 *      Return array with list of possible values for type of contacts
1096
-	 *
1097
-	 *      @param	string	$source     'internal', 'external' or 'all'
1098
-	 *      @param	string	$order		Sort order by : 'position', 'code', 'rowid'...
1099
-	 *      @param  int		$option     0=Return array id->label, 1=Return array code->label
1100
-	 *      @param  int		$activeonly 0=all status of contact, 1=only the active
1101
-	 *		@param	string	$code		Type of contact (Example: 'CUSTOMER', 'SERVICE')
1102
-	 *      @return array       		Array list of type of contacts (id->label if option=0, code->label if option=1)
1103
-	 */
1104
-	function liste_type_contact($source='internal', $order='position', $option=0, $activeonly=0, $code='')
1105
-	{
1106
-        // phpcs:enable
1107
-		global $langs;
1108
-
1109
-		if (empty($order)) $order='position';
1110
-		if ($order == 'position') $order.=',code';
1111
-
1112
-		$tab = array();
1113
-		$sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position";
1114
-		$sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
1115
-		$sql.= " WHERE tc.element='".$this->db->escape($this->element)."'";
1116
-		if ($activeonly == 1) $sql.= " AND tc.active=1"; // only the active types
1117
-		if (! empty($source) && $source != 'all') $sql.= " AND tc.source='".$this->db->escape($source)."'";
1118
-		if (! empty($code)) $sql.= " AND tc.code='".$this->db->escape($code)."'";
1119
-		$sql.= $this->db->order($order,'ASC');
1120
-
1121
-		//print "sql=".$sql;
1122
-		$resql=$this->db->query($sql);
1123
-		if ($resql)
1124
-		{
1125
-			$num=$this->db->num_rows($resql);
1126
-			$i=0;
1127
-			while ($i < $num)
1128
-			{
1129
-				$obj = $this->db->fetch_object($resql);
1130
-
1131
-				$transkey="TypeContact_".$this->element."_".$source."_".$obj->code;
1132
-				$libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
1133
-				if (empty($option)) $tab[$obj->rowid]=$libelle_type;
1134
-				else $tab[$obj->code]=$libelle_type;
1135
-				$i++;
1136
-			}
1137
-			return $tab;
1138
-		}
1139
-		else
1140
-		{
1141
-			$this->error=$this->db->lasterror();
1142
-			//dol_print_error($this->db);
1143
-			return null;
1144
-		}
1145
-	}
1146
-
1147
-	/**
1148
-	 *      Return id of contacts for a source and a contact code.
1149
-	 *      Example: contact client de facturation ('external', 'BILLING')
1150
-	 *      Example: contact client de livraison ('external', 'SHIPPING')
1151
-	 *      Example: contact interne suivi paiement ('internal', 'SALESREPFOLL')
1152
-	 *
1153
-	 *		@param	string	$source		'external' or 'internal'
1154
-	 *		@param	string	$code		'BILLING', 'SHIPPING', 'SALESREPFOLL', ...
1155
-	 *		@param	int		$status		limited to a certain status
1156
-	 *      @return array       		List of id for such contacts
1157
-	 */
1158
-	function getIdContact($source,$code,$status=0)
1159
-	{
1160
-		global $conf;
1161
-
1162
-		$result=array();
1163
-		$i=0;
1164
-		//cas particulier pour les expeditions
1165
-		if($this->element=='shipping' && $this->origin_id != 0) {
1166
-			$id=$this->origin_id;
1167
-			$element='commande';
1168
-        } else if($this->element=='reception' && $this->origin_id != 0) {
1169
-            $id=$this->origin_id;
1170
-            $element='order_supplier';
1171
-		} else {
1172
-			$id=$this->id;
1173
-			$element=$this->element;
1174
-		}
1175
-
1176
-		$sql = "SELECT ec.fk_socpeople";
1177
-		$sql.= " FROM ".MAIN_DB_PREFIX."element_contact as ec,";
1178
-		if ($source == 'internal') $sql.= " ".MAIN_DB_PREFIX."user as c,";
1179
-		if ($source == 'external') $sql.= " ".MAIN_DB_PREFIX."socpeople as c,";
1180
-		$sql.= " ".MAIN_DB_PREFIX."c_type_contact as tc";
1181
-		$sql.= " WHERE ec.element_id = ".$id;
1182
-		$sql.= " AND ec.fk_socpeople = c.rowid";
1183
-		if ($source == 'internal') $sql.= " AND c.entity IN (".getEntity('user').")";
1184
-		if ($source == 'external') $sql.= " AND c.entity IN (".getEntity('societe').")";
1185
-		$sql.= " AND ec.fk_c_type_contact = tc.rowid";
1186
-		$sql.= " AND tc.element = '".$element."'";
1187
-		$sql.= " AND tc.source = '".$source."'";
1188
-		$sql.= " AND tc.code = '".$code."'";
1189
-		$sql.= " AND tc.active = 1";
1190
-		if ($status) $sql.= " AND ec.statut = ".$status;
1191
-
1192
-		dol_syslog(get_class($this)."::getIdContact", LOG_DEBUG);
1193
-		$resql=$this->db->query($sql);
1194
-		if ($resql)
1195
-		{
1196
-			while ($obj = $this->db->fetch_object($resql))
1197
-			{
1198
-				$result[$i]=$obj->fk_socpeople;
1199
-				$i++;
1200
-			}
1201
-		}
1202
-		else
1203
-		{
1204
-			$this->error=$this->db->error();
1205
-			return null;
1206
-		}
1207
-
1208
-		return $result;
1209
-	}
160
+    /**
161
+     * @var User A related user
162
+     * @see fetch_user()
163
+     */
164
+    public $user;
1210 165
 
1211
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1212
-	/**
1213
-	 *		Load object contact with id=$this->contactid into $this->contact
1214
-	 *
1215
-	 *		@param	int		$contactid      Id du contact. Use this->contactid if empty.
1216
-	 *		@return	int						<0 if KO, >0 if OK
1217
-	 */
1218
-	function fetch_contact($contactid=null)
1219
-	{
1220
-        // phpcs:enable
1221
-		if (empty($contactid)) $contactid=$this->contactid;
166
+    /**
167
+     * @var string 	The type of originating object ('commande', 'facture', ...)
168
+     * @see fetch_origin()
169
+     */
170
+    public $origin;
1222 171
 
1223
-		if (empty($contactid)) return 0;
172
+    /**
173
+     * @var int 	The id of originating object
174
+     * @see fetch_origin()
175
+     */
176
+    public $origin_id;
1224 177
 
1225
-		require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1226
-		$contact = new Contact($this->db);
1227
-		$result=$contact->fetch($contactid);
1228
-		$this->contact = $contact;
1229
-		return $result;
1230
-	}
178
+    /**
179
+     * @var string The object's reference
180
+     */
181
+    public $ref;
1231 182
 
1232
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1233
-	/**
1234
-	 *    	Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty
1235
-	 *
1236
-	 *		@param		int		$force_thirdparty_id	Force thirdparty id
1237
-	 *		@return		int								<0 if KO, >0 if OK
1238
-	 */
1239
-	function fetch_thirdparty($force_thirdparty_id=0)
1240
-	{
1241
-        // phpcs:enable
1242
-		global $conf;
183
+    /**
184
+     * @var string The object's previous reference
185
+     */
186
+    public $ref_previous;
1243 187
 
1244
-		if (empty($this->socid) && empty($this->fk_soc) && empty($this->fk_thirdparty) && empty($force_thirdparty_id))
1245
-			return 0;
188
+    /**
189
+     * @var string The object's next reference
190
+     */
191
+    public $ref_next;
1246 192
 
1247
-		require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
193
+    /**
194
+     * @var string An external reference for the object
195
+     */
196
+    public $ref_ext;
1248 197
 
1249
-		$idtofetch = isset($this->socid) ? $this->socid : (isset($this->fk_soc) ? $this->fk_soc : $this->fk_thirdparty);
1250
-		if ($force_thirdparty_id)
1251
-			$idtofetch = $force_thirdparty_id;
198
+    /**
199
+     * @var int The object's status
200
+     * @see setStatut()
201
+     */
202
+    public $statut;
1252 203
 
1253
-		if ($idtofetch) {
1254
-			$thirdparty = new Societe($this->db);
1255
-			$result = $thirdparty->fetch($idtofetch);
1256
-			$this->thirdparty = $thirdparty;
204
+    /**
205
+     * @var string
206
+     * @see getFullAddress()
207
+     */
208
+    public $country;
1257 209
 
1258
-			// Use first price level if level not defined for third party
1259
-			if (!empty($conf->global->PRODUIT_MULTIPRICES) && empty($this->thirdparty->price_level)) {
1260
-				$this->thirdparty->price_level = 1;
1261
-			}
210
+    /**
211
+     * @var int
212
+     * @see getFullAddress(), country
213
+     */
214
+    public $country_id;
1262 215
 
1263
-			return $result;
1264
-		} else
1265
-			return -1;
1266
-	}
216
+    /**
217
+     * @var string
218
+     * @see getFullAddress(), isInEEC(), country
219
+     */
220
+    public $country_code;
1267 221
 
222
+    /**
223
+     * @var string
224
+     * @see getFullAddress()
225
+     */
226
+    public $state;
1268 227
 
1269
-	/**
1270
-	 * Looks for an object with ref matching the wildcard provided
1271
-	 * It does only work when $this->table_ref_field is set
1272
-	 *
1273
-	 * @param string $ref Wildcard
1274
-	 * @return int >1 = OK, 0 = Not found or table_ref_field not defined, <0 = KO
1275
-	 */
1276
-	public function fetchOneLike($ref)
1277
-	{
1278
-		if (!$this->table_ref_field) {
1279
-			return 0;
1280
-		}
228
+    /**
229
+     * @var int
230
+     * @see getFullAddress(), state
231
+     */
232
+    public $state_id;
1281 233
 
1282
-		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE '.$this->table_ref_field.' LIKE "'.$this->db->escape($ref).'" LIMIT 1';
234
+    /**
235
+     * @var string
236
+     * @see getFullAddress(), state
237
+     */
238
+    public $state_code;
1283 239
 
1284
-		$query = $this->db->query($sql);
240
+    /**
241
+     * @var string
242
+     * @see getFullAddress(), region
243
+     */
244
+    public $region;
1285 245
 
1286
-		if (!$this->db->num_rows($query)) {
1287
-			return 0;
1288
-		}
246
+    /**
247
+     * @var string
248
+     * @see getFullAddress(), region
249
+     */
250
+    public $region_code;
1289 251
 
1290
-		$result = $this->db->fetch_object($query);
252
+    /**
253
+     * @var int
254
+     * @see fetch_barcode()
255
+     */
256
+    public $barcode_type;
1291 257
 
1292
-		return $this->fetch($result->rowid);
1293
-	}
258
+    /**
259
+     * @var string
260
+     * @see fetch_barcode(), barcode_type
261
+     */
262
+    public $barcode_type_code;
1294 263
 
1295
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1296
-	/**
1297
-	 *	Load data for barcode into properties ->barcode_type*
1298
-	 *	Properties ->barcode_type that is id of barcode. Type is used to find other properties, but
1299
-	 *  if it is not defined, ->element must be defined to know default barcode type.
1300
-	 *
1301
-	 *	@return		int			<0 if KO, 0 if can't guess type of barcode (ISBN, EAN13...), >0 if OK (all barcode properties loaded)
1302
-	 */
1303
-	function fetch_barcode()
1304
-	{
1305
-        // phpcs:enable
1306
-		global $conf;
264
+    /**
265
+     * @var string
266
+     * @see fetch_barcode(), barcode_type
267
+     */
268
+    public $barcode_type_label;
1307 269
 
1308
-		dol_syslog(get_class($this).'::fetch_barcode this->element='.$this->element.' this->barcode_type='.$this->barcode_type);
270
+    /**
271
+     * @var string
272
+     * @see fetch_barcode(), barcode_type
273
+     */
274
+    public $barcode_type_coder;
1309 275
 
1310
-		$idtype=$this->barcode_type;
1311
-		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
1312
-		{
1313
-			if ($this->element == 'product')      $idtype = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
1314
-			else if ($this->element == 'societe') $idtype = $conf->global->GENBARCODE_BARCODETYPE_THIRDPARTY;
1315
-			else dol_syslog('Call fetch_barcode with barcode_type not defined and cant be guessed', LOG_WARNING);
1316
-		}
276
+    /**
277
+     * @var int Payment method ID (cheque, cash, ...)
278
+     * @see setPaymentMethods()
279
+     */
280
+    public $mode_reglement_id;
1317 281
 
1318
-		if ($idtype > 0)
1319
-		{
1320
-			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
1321
-			{
1322
-				$sql = "SELECT rowid, code, libelle as label, coder";
1323
-				$sql.= " FROM ".MAIN_DB_PREFIX."c_barcode_type";
1324
-				$sql.= " WHERE rowid = ".$idtype;
1325
-				dol_syslog(get_class($this).'::fetch_barcode', LOG_DEBUG);
1326
-				$resql = $this->db->query($sql);
1327
-				if ($resql)
1328
-				{
1329
-					$obj = $this->db->fetch_object($resql);
1330
-					$this->barcode_type       = $obj->rowid;
1331
-					$this->barcode_type_code  = $obj->code;
1332
-					$this->barcode_type_label = $obj->label;
1333
-					$this->barcode_type_coder = $obj->coder;
1334
-					return 1;
1335
-				}
1336
-				else
1337
-				{
1338
-					dol_print_error($this->db);
1339
-					return -1;
1340
-				}
1341
-			}
1342
-		}
1343
-		return 0;
1344
-	}
282
+    /**
283
+     * @var int Payment terms ID
284
+     * @see setPaymentTerms()
285
+     */
286
+    public $cond_reglement_id;
1345 287
 
1346
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1347
-	/**
1348
-	 *		Load the project with id $this->fk_project into this->project
1349
-	 *
1350
-	 *		@return		int			<0 if KO, >=0 if OK
1351
-	 */
1352
-	function fetch_projet()
1353
-	{
1354
-        // phpcs:enable
1355
-		include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
288
+    /**
289
+     * @var int Payment terms ID
290
+     * @deprecated Kept for compatibility
291
+     * @see cond_reglement_id;
292
+     */
293
+    public $cond_reglement;
1356 294
 
1357
-		if (empty($this->fk_project) && ! empty($this->fk_projet)) $this->fk_project = $this->fk_projet;	// For backward compatibility
1358
-		if (empty($this->fk_project)) return 0;
295
+    /**
296
+     * @var int Delivery address ID
297
+     * @deprecated
298
+     * @see setDeliveryAddress()
299
+     */
300
+    public $fk_delivery_address;
1359 301
 
1360
-		$project = new Project($this->db);
1361
-		$result = $project->fetch($this->fk_project);
302
+    /**
303
+     * @var int Shipping method ID
304
+     * @see setShippingMethod()
305
+     */
306
+    public $shipping_method_id;
1362 307
 
1363
-		$this->projet = $project;	// deprecated
1364
-		$this->project = $project;
1365
-		return $result;
1366
-	}
308
+    /**
309
+     * @var string
310
+     * @see SetDocModel()
311
+     */
312
+    public $modelpdf;
1367 313
 
1368
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1369
-	/**
1370
-	 *		Load the product with id $this->fk_product into this->product
1371
-	 *
1372
-	 *		@return		int			<0 if KO, >=0 if OK
1373
-	 */
1374
-	function fetch_product()
1375
-	{
1376
-        // phpcs:enable
1377
-		include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
314
+    /**
315
+     * @var int Bank account ID
316
+     * @see SetBankAccount()
317
+     */
318
+    public $fk_account;
1378 319
 
1379
-		if (empty($this->fk_product)) return 0;
320
+    /**
321
+     * @var string Public note
322
+     * @see update_note()
323
+     */
324
+    public $note_public;
1380 325
 
1381
-		$product = new Product($this->db);
1382
-		$result = $product->fetch($this->fk_product);
326
+    /**
327
+     * @var string Private note
328
+     * @see update_note()
329
+     */
330
+    public $note_private;
1383 331
 
1384
-		$this->product = $product;
1385
-		return $result;
1386
-	}
332
+    /**
333
+     * @deprecated
334
+     * @see note_public
335
+     */
336
+    public $note;
1387 337
 
1388
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1389
-	/**
1390
-	 *		Load the user with id $userid into this->user
1391
-	 *
1392
-	 *		@param	int		$userid 		Id du contact
1393
-	 *		@return	int						<0 if KO, >0 if OK
1394
-	 */
1395
-	function fetch_user($userid)
1396
-	{
1397
-        // phpcs:enable
1398
-		$user = new User($this->db);
1399
-		$result=$user->fetch($userid);
1400
-		$this->user = $user;
1401
-		return $result;
1402
-	}
338
+    /**
339
+     * @var float Total amount before taxes
340
+     * @see update_price()
341
+     */
342
+    public $total_ht;
1403 343
 
1404
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1405
-	/**
1406
-	 *	Read linked origin object
1407
-	 *
1408
-	 *	@return		void
1409
-	 */
1410
-	function fetch_origin()
1411
-	{
1412
-        // phpcs:enable
1413
-		if ($this->origin == 'shipping') $this->origin = 'expedition';
1414
-		if ($this->origin == 'delivery') $this->origin = 'livraison';
1415
-        if ($this->origin == 'order_supplier') $this->origin = 'commandeFournisseur';
344
+    /**
345
+     * @var float Total VAT amount
346
+     * @see update_price()
347
+     */
348
+    public $total_tva;
1416 349
 
1417
-		$origin = $this->origin;
350
+    /**
351
+     * @var float Total local tax 1 amount
352
+     * @see update_price()
353
+     */
354
+    public $total_localtax1;
1418 355
 
1419
-		$classname = ucfirst($origin);
1420
-		$this->$origin = new $classname($this->db);
1421
-		$this->$origin->fetch($this->origin_id);
1422
-	}
356
+    /**
357
+     * @var float Total local tax 2 amount
358
+     * @see update_price()
359
+     */
360
+    public $total_localtax2;
1423 361
 
1424
-	/**
1425
-     *  Load object from specific field
1426
-     *
1427
-     *  @param	string	$table		Table element or element line
1428
-     *  @param	string	$field		Field selected
1429
-     *  @param	string	$key		Import key
1430
-     *  @param	string	$element	Element name
1431
-     *	@return	int					<0 if KO, >0 if OK
362
+    /**
363
+     * @var float Total amount with taxes
364
+     * @see update_price()
1432 365
      */
1433
-	function fetchObjectFrom($table, $field, $key, $element = null)
1434
-	{
1435
-		global $conf;
1436
-
1437
-		$result=false;
1438
-
1439
-		$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$table;
1440
-		$sql.= " WHERE ".$field." = '".$key."'";
1441
-		if (! empty($element)) {
1442
-			$sql.= " AND entity IN (".getEntity($element).")";
1443
-		} else {
1444
-			$sql.= " AND entity = ".$conf->entity;
1445
-		}
1446
-
1447
-		dol_syslog(get_class($this).'::fetchObjectFrom', LOG_DEBUG);
1448
-		$resql = $this->db->query($sql);
1449
-		if ($resql)
1450
-		{
1451
-			$row = $this->db->fetch_row($resql);
1452
-			// Test for avoid error -1
1453
-			if ($row[0] > 0) {
1454
-				$result = $this->fetch($row[0]);
1455
-			}
1456
-		}
1457
-
1458
-		return $result;
1459
-	}
1460
-
1461
-	/**
1462
-	 *	Getter generic. Load value from a specific field
1463
-	 *
1464
-	 *	@param	string	$table		Table of element or element line
1465
-	 *	@param	int		$id			Element id
1466
-	 *	@param	string	$field		Field selected
1467
-	 *	@return	int					<0 if KO, >0 if OK
1468
-	 */
1469
-	function getValueFrom($table, $id, $field)
1470
-	{
1471
-		$result=false;
1472
-		if (!empty($id) && !empty($field) && !empty($table)) {
1473
-			$sql = "SELECT ".$field." FROM ".MAIN_DB_PREFIX.$table;
1474
-			$sql.= " WHERE rowid = ".$id;
1475
-
1476
-			dol_syslog(get_class($this).'::getValueFrom', LOG_DEBUG);
1477
-			$resql = $this->db->query($sql);
1478
-			if ($resql)
1479
-			{
1480
-				$row = $this->db->fetch_row($resql);
1481
-				$result = $row[0];
1482
-			}
1483
-		}
1484
-		return $result;
1485
-	}
1486
-
1487
-	/**
1488
-	 *	Setter generic. Update a specific field into database.
1489
-	 *  Warning: Trigger is run only if param trigkey is provided.
1490
-	 *
1491
-	 *	@param	string		$field			Field to update
1492
-	 *	@param	mixed		$value			New value
1493
-	 *	@param	string		$table			To force other table element or element line (should not be used)
1494
-	 *	@param	int			$id				To force other object id (should not be used)
1495
-	 *	@param	string		$format			Data format ('text', 'date'). 'text' is used if not defined
1496
-	 *	@param	string		$id_field		To force rowid field name. 'rowid' is used if not defined
1497
-	 *	@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'
1498
-	 *  @param  string      $trigkey    	Trigger key to run (in most cases something like 'XXX_MODIFY')
1499
-	 *  @param	string		$fk_user_field	Name of field to save user id making change
1500
-	 *	@return	int							<0 if KO, >0 if OK
1501
-	 *  @see updateExtraField
1502
-	 */
1503
-	function setValueFrom($field, $value, $table='', $id=null, $format='', $id_field='', $fuser=null, $trigkey='', $fk_user_field='fk_user_modif')
1504
-	{
1505
-		global $user,$langs,$conf;
1506
-
1507
-		if (empty($table)) 	  $table=$this->table_element;
1508
-		if (empty($id))    	  $id=$this->id;
1509
-		if (empty($format))   $format='text';
1510
-		if (empty($id_field)) $id_field='rowid';
1511
-
1512
-		$error=0;
1513
-
1514
-		$this->db->begin();
1515
-
1516
-		// Special case
1517
-		if ($table == 'product' && $field == 'note_private') $field='note';
1518
-		if (in_array($table, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))) $fk_user_field = 'fk_user_mod';
1519
-
1520
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$table." SET ";
1521
-
1522
-		if ($format == 'text') $sql.= $field." = '".$this->db->escape($value)."'";
1523
-		else if ($format == 'int') $sql.= $field." = ".$this->db->escape($value);
1524
-		else if ($format == 'date') $sql.= $field." = ".($value ? "'".$this->db->idate($value)."'" : "null");
1525
-
1526
-		if ($fk_user_field)
1527
-		{
1528
-			if (! empty($fuser) && is_object($fuser)) $sql.=", ".$fk_user_field." = ".$fuser->id;
1529
-			elseif (empty($fuser) || $fuser != 'none') $sql.=", ".$fk_user_field." = ".$user->id;
1530
-		}
1531
-
1532
-		$sql.= " WHERE ".$id_field." = ".$id;
1533
-
1534
-		dol_syslog(get_class($this)."::".__FUNCTION__."", LOG_DEBUG);
1535
-		$resql = $this->db->query($sql);
1536
-		if ($resql)
1537
-		{
1538
-			if ($trigkey)
1539
-			{
1540
-				// call trigger with updated object values
1541
-				if (empty($this->fields) && method_exists($this, 'fetch'))
1542
-				{
1543
-					$result = $this->fetch($id);
1544
-				}
1545
-				else
1546
-				{
1547
-					$result = $this->fetchCommon($id);
1548
-				}
1549
-				if ($result >= 0) $result=$this->call_trigger($trigkey, (! empty($fuser) && is_object($fuser)) ? $fuser : $user);   // This may set this->errors
1550
-				if ($result < 0) $error++;
1551
-			}
366
+    public $total_ttc;
1552 367
 
1553
-			if (! $error)
1554
-			{
1555
-				if (property_exists($this, $field)) $this->$field = $value;
1556
-				$this->db->commit();
1557
-				return 1;
1558
-			}
1559
-			else
1560
-			{
1561
-				$this->db->rollback();
1562
-				return -2;
1563
-			}
1564
-		}
1565
-		else
1566
-		{
1567
-			$this->error=$this->db->lasterror();
1568
-			$this->db->rollback();
1569
-			return -1;
1570
-		}
1571
-	}
368
+    /**
369
+     * @var CommonObjectLine[]
370
+     */
371
+    public $lines;
1572 372
 
1573
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1574
-	/**
1575
-	 *      Load properties id_previous and id_next by comparing $fieldid with $this->ref
1576
-	 *
1577
-	 *      @param	string	$filter		Optional filter. Example: " AND (t.field1 = 'aa' OR t.field2 = 'bb')"
1578
-	 *	 	@param  string	$fieldid   	Name of field to use for the select MAX and MIN
1579
-	 *		@param	int		$nodbprefix	Do not include DB prefix to forge table name
1580
-	 *      @return int         		<0 if KO, >0 if OK
1581
-	 */
1582
-	function load_previous_next_ref($filter, $fieldid, $nodbprefix=0)
1583
-	{
1584
-        // phpcs:enable
1585
-		global $conf, $user;
1586
-
1587
-		if (! $this->table_element)
1588
-		{
1589
-			dol_print_error('',get_class($this)."::load_previous_next_ref was called on objet with property table_element not defined");
1590
-			return -1;
1591
-		}
1592
-		if ($fieldid == 'none') return 1;
1593
-
1594
-		// Security on socid
1595
-		$socid = 0;
1596
-		if ($user->societe_id > 0) $socid = $user->societe_id;
1597
-
1598
-		// this->ismultientitymanaged contains
1599
-		// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
1600
-		$alias = 's';
1601
-		if ($this->element == 'societe') $alias = 'te';
1602
-
1603
-		$sql = "SELECT MAX(te.".$fieldid.")";
1604
-		$sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1605
-		if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1606
-			$sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
1607
-		}
1608
-		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
1609
-		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
1610
-		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
1611
-		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";
1612
-		$sql.= " WHERE te.".$fieldid." < '".$this->db->escape($this->ref)."'";  // ->ref must always be defined (set to id if field does not exists)
1613
-		if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1614
-		if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1615
-		if (! empty($filter))
1616
-		{
1617
-			if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND ";   // For backward compatibility
1618
-			$sql.=$filter;
1619
-		}
1620
-		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
1621
-		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
1622
-		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1623
-			if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1624
-				if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1625
-					$sql.= " AND te.entity IS NOT NULL"; // Show all users
1626
-				} else {
1627
-					$sql.= " AND ug.fk_user = te.rowid";
1628
-					$sql.= " AND ug.entity IN (".getEntity($this->element).")";
1629
-				}
1630
-			} else {
1631
-				$sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1632
-			}
1633
-		}
1634
-		if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1635
-		if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1636
-		if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1637
-		//print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1638
-
1639
-		$result = $this->db->query($sql);
1640
-		if (! $result)
1641
-		{
1642
-			$this->error=$this->db->lasterror();
1643
-			return -1;
1644
-		}
1645
-		$row = $this->db->fetch_row($result);
1646
-		$this->ref_previous = $row[0];
1647
-
1648
-
1649
-		$sql = "SELECT MIN(te.".$fieldid.")";
1650
-		$sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1651
-		if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1652
-			$sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
1653
-		}
1654
-		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
1655
-		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
1656
-		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
1657
-		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";
1658
-		$sql.= " WHERE te.".$fieldid." > '".$this->db->escape($this->ref)."'";  // ->ref must always be defined (set to id if field does not exists)
1659
-		if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1660
-		if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1661
-		if (! empty($filter))
1662
-		{
1663
-			if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND ";   // For backward compatibility
1664
-			$sql.=$filter;
1665
-		}
1666
-		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
1667
-		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
1668
-		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1669
-			if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1670
-				if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1671
-					$sql.= " AND te.entity IS NOT NULL"; // Show all users
1672
-				} else {
1673
-					$sql.= " AND ug.fk_user = te.rowid";
1674
-					$sql.= " AND ug.entity IN (".getEntity($this->element).")";
1675
-				}
1676
-			} else {
1677
-				$sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1678
-			}
1679
-		}
1680
-		if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1681
-		if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1682
-		if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1683
-		//print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1684
-		// 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
1685
-
1686
-		$result = $this->db->query($sql);
1687
-		if (! $result)
1688
-		{
1689
-			$this->error=$this->db->lasterror();
1690
-			return -2;
1691
-		}
1692
-		$row = $this->db->fetch_row($result);
1693
-		$this->ref_next = $row[0];
1694
-
1695
-		return 1;
1696
-	}
1697
-
1698
-
1699
-	/**
1700
-	 *      Return list of id of contacts of object
1701
-	 *
1702
-	 *      @param	string	$source     Source of contact: external (llx_socpeople) or internal (llx_user) or thirdparty (llx_societe)
1703
-	 *      @return array				Array of id of contacts (if source=external or internal)
1704
-	 * 									Array of id of third parties with at least one contact on object (if source=thirdparty)
1705
-	 */
1706
-	function getListContactId($source='external')
1707
-	{
1708
-		$contactAlreadySelected = array();
1709
-		$tab = $this->liste_contact(-1,$source);
1710
-		$num=count($tab);
1711
-		$i = 0;
1712
-		while ($i < $num)
1713
-		{
1714
-			if ($source == 'thirdparty') $contactAlreadySelected[$i] = $tab[$i]['socid'];
1715
-			else  $contactAlreadySelected[$i] = $tab[$i]['id'];
1716
-			$i++;
1717
-		}
1718
-		return $contactAlreadySelected;
1719
-	}
1720
-
1721
-
1722
-	/**
1723
-	 *	Link element with a project
1724
-	 *
1725
-	 *	@param     	int		$projectid		Project id to link element to
1726
-	 *	@return		int						<0 if KO, >0 if OK
1727
-	 */
1728
-	function setProject($projectid)
1729
-	{
1730
-		if (! $this->table_element)
1731
-		{
1732
-			dol_syslog(get_class($this)."::setProject was called on objet with property table_element not defined",LOG_ERR);
1733
-			return -1;
1734
-		}
1735
-
1736
-		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1737
-		if ($this->table_element == 'actioncomm')
1738
-		{
1739
-			if ($projectid) $sql.= ' SET fk_project = '.$projectid;
1740
-			else $sql.= ' SET fk_project = NULL';
1741
-			$sql.= ' WHERE id = '.$this->id;
1742
-		}
1743
-		else
1744
-		{
1745
-			if ($projectid) $sql.= ' SET fk_projet = '.$projectid;
1746
-			else $sql.= ' SET fk_projet = NULL';
1747
-			$sql.= ' WHERE rowid = '.$this->id;
1748
-		}
1749
-
1750
-		dol_syslog(get_class($this)."::setProject", LOG_DEBUG);
1751
-		if ($this->db->query($sql))
1752
-		{
1753
-			$this->fk_project = $projectid;
1754
-			return 1;
1755
-		}
1756
-		else
1757
-		{
1758
-			dol_print_error($this->db);
1759
-			return -1;
1760
-		}
1761
-	}
1762
-
1763
-	/**
1764
-	 *  Change the payments methods
1765
-	 *
1766
-	 *  @param		int		$id		Id of new payment method
1767
-	 *  @return		int				>0 if OK, <0 if KO
1768
-	 */
1769
-	function setPaymentMethods($id)
1770
-	{
1771
-		dol_syslog(get_class($this).'::setPaymentMethods('.$id.')');
1772
-		if ($this->statut >= 0 || $this->element == 'societe')
1773
-		{
1774
-			// TODO uniformize field name
1775
-			$fieldname = 'fk_mode_reglement';
1776
-			if ($this->element == 'societe') $fieldname = 'mode_reglement';
1777
-			if (get_class($this) == 'Fournisseur') $fieldname = 'mode_reglement_supplier';
1778
-
1779
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1780
-			$sql .= ' SET '.$fieldname.' = '.$id;
1781
-			$sql .= ' WHERE rowid='.$this->id;
1782
-
1783
-			if ($this->db->query($sql))
1784
-			{
1785
-				$this->mode_reglement_id = $id;
1786
-				// for supplier
1787
-				if (get_class($this) == 'Fournisseur') $this->mode_reglement_supplier_id = $id;
1788
-				return 1;
1789
-			}
1790
-			else
1791
-			{
1792
-				dol_syslog(get_class($this).'::setPaymentMethods Erreur '.$sql.' - '.$this->db->error());
1793
-				$this->error=$this->db->error();
1794
-				return -1;
1795
-			}
1796
-		}
1797
-		else
1798
-		{
1799
-			dol_syslog(get_class($this).'::setPaymentMethods, status of the object is incompatible');
1800
-			$this->error='Status of the object is incompatible '.$this->statut;
1801
-			return -2;
1802
-		}
1803
-	}
1804
-
1805
-	/**
1806
-	 *  Change the multicurrency code
1807
-	 *
1808
-	 *  @param		string	$code	multicurrency code
1809
-	 *  @return		int				>0 if OK, <0 if KO
1810
-	 */
1811
-	function setMulticurrencyCode($code)
1812
-	{
1813
-		dol_syslog(get_class($this).'::setMulticurrencyCode('.$id.')');
1814
-		if ($this->statut >= 0 || $this->element == 'societe')
1815
-		{
1816
-			$fieldname = 'multicurrency_code';
1817
-
1818
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1819
-			$sql .= ' SET '.$fieldname." = '".$this->db->escape($code)."'";
1820
-			$sql .= ' WHERE rowid='.$this->id;
1821
-
1822
-			if ($this->db->query($sql))
1823
-			{
1824
-				$this->multicurrency_code = $code;
373
+    /**
374
+     * @var mixed		Contains comments
375
+     * @see fetchComments()
376
+     */
377
+    public $comments=array();
1825 378
 
1826
-				list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code);
1827
-				if ($rate) $this->setMulticurrencyRate($rate,2);
379
+    /**
380
+     * @var int
381
+     * @see setIncoterms()
382
+     */
383
+    public $fk_incoterms;
1828 384
 
1829
-				return 1;
1830
-			}
1831
-			else
1832
-			{
1833
-				dol_syslog(get_class($this).'::setMulticurrencyCode Erreur '.$sql.' - '.$this->db->error());
1834
-				$this->error=$this->db->error();
1835
-				return -1;
1836
-			}
1837
-		}
1838
-		else
1839
-		{
1840
-			dol_syslog(get_class($this).'::setMulticurrencyCode, status of the object is incompatible');
1841
-			$this->error='Status of the object is incompatible '.$this->statut;
1842
-			return -2;
1843
-		}
1844
-	}
1845
-
1846
-	/**
1847
-	 *  Change the multicurrency rate
1848
-	 *
1849
-	 *  @param		double	$rate	multicurrency rate
1850
-	 *  @param		int		$mode	mode 1 : amounts in company currency will be recalculated, mode 2 : amounts in foreign currency
1851
-	 *  @return		int				>0 if OK, <0 if KO
1852
-	 */
1853
-	function setMulticurrencyRate($rate, $mode=1)
1854
-	{
1855
-		dol_syslog(get_class($this).'::setMulticurrencyRate('.$id.')');
1856
-		if ($this->statut >= 0 || $this->element == 'societe')
1857
-		{
1858
-			$fieldname = 'multicurrency_tx';
1859
-
1860
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1861
-			$sql .= ' SET '.$fieldname.' = '.$rate;
1862
-			$sql .= ' WHERE rowid='.$this->id;
1863
-
1864
-			if ($this->db->query($sql))
1865
-			{
1866
-				$this->multicurrency_tx = $rate;
385
+    /**
386
+     * @var string
387
+     * @see SetIncoterms()
388
+     */
389
+    public $libelle_incoterms;
1867 390
 
1868
-				// Update line price
1869
-				if (!empty($this->lines))
1870
-				{
1871
-					foreach ($this->lines as &$line)
1872
-					{
1873
-						if($mode == 1) {
1874
-							$line->subprice = 0;
1875
-						}
391
+    /**
392
+     * @var string
393
+     * @see display_incoterms()
394
+     */
395
+    public $location_incoterms;
1876 396
 
1877
-						switch ($this->element) {
1878
-							case 'propal':
1879
-								$this->updateline(
1880
-									$line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1881
-									($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1882
-									$line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start,
1883
-									$line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1884
-								);
1885
-								break;
1886
-							case 'commande':
1887
-								$this->updateline(
1888
-									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1889
-									$line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->date_start, $line->date_end,
1890
-									$line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1891
-									$line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1892
-								);
1893
-								break;
1894
-							case 'facture':
1895
-								$this->updateline(
1896
-									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1897
-									$line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits,
1898
-									$line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1899
-									$line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice
1900
-								);
1901
-								break;
1902
-							case 'supplier_proposal':
1903
-								$this->updateline(
1904
-									$line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1905
-									($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1906
-									$line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->array_options,
1907
-									$line->ref_fourn, $line->multicurrency_subprice
1908
-								);
1909
-								break;
1910
-							case 'order_supplier':
1911
-								$this->updateline(
1912
-									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1913
-									$line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, false,
1914
-									$line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1915
-								);
1916
-								break;
1917
-							case 'invoice_supplier':
1918
-								$this->updateline(
1919
-									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->tva_tx, $line->localtax1_tx,
1920
-									$line->localtax2_tx, $line->qty, 0, 'HT', $line->info_bits, $line->product_type, $line->remise_percent, false,
1921
-									$line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1922
-								);
1923
-								break;
1924
-							default:
1925
-								dol_syslog(get_class($this).'::setMulticurrencyRate no updateline defined', LOG_DEBUG);
1926
-								break;
1927
-						}
1928
-					}
1929
-				}
397
+    public $name;
398
+    public $lastname;
399
+    public $firstname;
400
+    public $civility_id;
1930 401
 
1931
-				return 1;
1932
-			}
1933
-			else
1934
-			{
1935
-				dol_syslog(get_class($this).'::setMulticurrencyRate Erreur '.$sql.' - '.$this->db->error());
1936
-				$this->error=$this->db->error();
1937
-				return -1;
1938
-			}
1939
-		}
1940
-		else
1941
-		{
1942
-			dol_syslog(get_class($this).'::setMulticurrencyRate, status of the object is incompatible');
1943
-			$this->error='Status of the object is incompatible '.$this->statut;
1944
-			return -2;
1945
-		}
1946
-	}
1947
-
1948
-	/**
1949
-	 *  Change the payments terms
1950
-	 *
1951
-	 *  @param		int		$id		Id of new payment terms
1952
-	 *  @return		int				>0 if OK, <0 if KO
1953
-	 */
1954
-	function setPaymentTerms($id)
1955
-	{
1956
-		dol_syslog(get_class($this).'::setPaymentTerms('.$id.')');
1957
-		if ($this->statut >= 0 || $this->element == 'societe')
1958
-		{
1959
-			// TODO uniformize field name
1960
-			$fieldname = 'fk_cond_reglement';
1961
-			if ($this->element == 'societe') $fieldname = 'cond_reglement';
1962
-			if (get_class($this) == 'Fournisseur') $fieldname = 'cond_reglement_supplier';
1963
-
1964
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1965
-			$sql .= ' SET '.$fieldname.' = '.$id;
1966
-			$sql .= ' WHERE rowid='.$this->id;
1967
-
1968
-			if ($this->db->query($sql))
1969
-			{
1970
-				$this->cond_reglement_id = $id;
1971
-				// for supplier
1972
-				if (get_class($this) == 'Fournisseur') $this->cond_reglement_supplier_id = $id;
1973
-				$this->cond_reglement = $id;	// for compatibility
1974
-				return 1;
1975
-			}
1976
-			else
1977
-			{
1978
-				dol_syslog(get_class($this).'::setPaymentTerms Erreur '.$sql.' - '.$this->db->error());
1979
-				$this->error=$this->db->error();
1980
-				return -1;
1981
-			}
1982
-		}
1983
-		else
1984
-		{
1985
-			dol_syslog(get_class($this).'::setPaymentTerms, status of the object is incompatible');
1986
-			$this->error='Status of the object is incompatible '.$this->statut;
1987
-			return -2;
1988
-		}
1989
-	}
1990
-
1991
-	/**
1992
-	 *	Define delivery address
1993
-	 *  @deprecated
1994
-	 *
1995
-	 *	@param      int		$id		Address id
1996
-	 *	@return     int				<0 si ko, >0 si ok
1997
-	 */
1998
-	function setDeliveryAddress($id)
1999
-	{
2000
-		$fieldname = 'fk_delivery_address';
2001
-		if ($this->element == 'delivery' || $this->element == 'shipping') $fieldname = 'fk_address';
2002
-
2003
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET ".$fieldname." = ".$id;
2004
-		$sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
2005
-
2006
-		if ($this->db->query($sql))
2007
-		{
2008
-			$this->fk_delivery_address = $id;
2009
-			return 1;
2010
-		}
2011
-		else
2012
-		{
2013
-			$this->error=$this->db->error();
2014
-			dol_syslog(get_class($this).'::setDeliveryAddress Erreur '.$sql.' - '.$this->error);
2015
-			return -1;
2016
-		}
2017
-	}
2018
-
2019
-
2020
-	/**
2021
-	 *  Change the shipping method
2022
-	 *
2023
-	 *  @param      int     $shipping_method_id     Id of shipping method
2024
-     *  @param      bool    $notrigger              false=launch triggers after, true=disable triggers
2025
-     *  @param      User	$userused               Object user
2026
-	 *
2027
-	 *  @return     int              1 if OK, 0 if KO
2028
-	 */
2029
-	function setShippingMethod($shipping_method_id, $notrigger=false, $userused=null)
2030
-	{
2031
-        global $user;
402
+    // Dates
403
+    public $date_creation;			// Date creation
404
+    public $date_validation;		// Date validation
405
+    public $date_modification;		// Date last change (tms field)
2032 406
 
2033
-        if (empty($userused)) $userused=$user;
2034 407
 
2035
-        $error = 0;
2036 408
 
2037
-		if (! $this->table_element) {
2038
-			dol_syslog(get_class($this)."::setShippingMethod was called on objet with property table_element not defined",LOG_ERR);
2039
-			return -1;
2040
-		}
409
+    // No constructor as it is an abstract class
2041 410
 
2042
-        $this->db->begin();
411
+    /**
412
+     * Check an object id/ref exists
413
+     * If you don't need/want to instantiate object and just need to know if object exists, use this method instead of fetch
414
+     *
415
+     *  @param	string	$element   	String of element ('product', 'facture', ...)
416
+     *  @param	int		$id      	Id of object
417
+     *  @param  string	$ref     	Ref of object to check
418
+     *  @param	string	$ref_ext	Ref ext of object to check
419
+     *  @return int     			<0 if KO, 0 if OK but not found, >0 if OK and exists
420
+     */
421
+    static function isExistingObject($element, $id, $ref='', $ref_ext='')
422
+    {
423
+        global $db,$conf;
424
+
425
+        $sql = "SELECT rowid, ref, ref_ext";
426
+        $sql.= " FROM ".MAIN_DB_PREFIX.$element;
427
+        $sql.= " WHERE entity IN (".getEntity($element).")" ;
428
+
429
+        if ($id > 0) $sql.= " AND rowid = ".$db->escape($id);
430
+        else if ($ref) $sql.= " AND ref = '".$db->escape($ref)."'";
431
+        else if ($ref_ext) $sql.= " AND ref_ext = '".$db->escape($ref_ext)."'";
432
+        else {
433
+            $error='ErrorWrongParameters';
434
+            dol_print_error(get_class()."::isExistingObject ".$error, LOG_ERR);
435
+            return -1;
436
+        }
437
+        if ($ref || $ref_ext) $sql.= " AND entity = ".$conf->entity;
2043 438
 
2044
-		if ($shipping_method_id<0) $shipping_method_id='NULL';
2045
-		dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')');
439
+        dol_syslog(get_class()."::isExistingObject", LOG_DEBUG);
440
+        $resql = $db->query($sql);
441
+        if ($resql)
442
+        {
443
+            $num=$db->num_rows($resql);
444
+            if ($num > 0) return 1;
445
+            else return 0;
446
+        }
447
+        return -1;
448
+    }
2046 449
 
2047
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2048
-		$sql.= " SET fk_shipping_method = ".$shipping_method_id;
2049
-		$sql.= " WHERE rowid=".$this->id;
2050
-        $resql = $this->db->query($sql);
2051
-		if (! $resql) {
2052
-			dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG);
2053
-			$this->error = $this->db->lasterror();
2054
-			$error++;
2055
-        } else {
2056
-            if (!$notrigger)
2057
-            {
2058
-                // Call trigger
2059
-                $this->context=array('shippingmethodupdate'=>1);
2060
-                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2061
-                if ($result < 0) $error++;
2062
-                // End call trigger
2063
-            }
450
+    /**
451
+     * Method to output saved errors
452
+     *
453
+     * @return	string		String with errors
454
+     */
455
+    function errorsToString()
456
+    {
457
+        return $this->error.(is_array($this->errors)?(($this->error!=''?', ':'').join(', ',$this->errors)):'');
458
+    }
459
+
460
+    /**
461
+     *	Return full name (civility+' '+name+' '+lastname)
462
+     *
463
+     *	@param	Translate	$langs			Language object for translation of civility (used only if option is 1)
464
+     *	@param	int			$option			0=No option, 1=Add civility
465
+     * 	@param	int			$nameorder		-1=Auto, 0=Lastname+Firstname, 1=Firstname+Lastname, 2=Firstname
466
+     * 	@param	int			$maxlen			Maximum length
467
+     * 	@return	string						String with full name
468
+     */
469
+    function getFullName($langs,$option=0,$nameorder=-1,$maxlen=0)
470
+    {
471
+        //print "lastname=".$this->lastname." name=".$this->name." nom=".$this->nom."<br>\n";
472
+        $lastname=$this->lastname;
473
+        $firstname=$this->firstname;
474
+        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:'')))));
475
+
476
+        $ret='';
477
+        if ($option && $this->civility_id)
478
+        {
479
+            if ($langs->transnoentitiesnoconv("Civility".$this->civility_id)!="Civility".$this->civility_id) $ret.=$langs->transnoentitiesnoconv("Civility".$this->civility_id).' ';
480
+            else $ret.=$this->civility_id.' ';
2064 481
         }
2065
-        if ($error)
482
+
483
+        $ret.=dolGetFirstLastname($firstname, $lastname, $nameorder);
484
+
485
+        return dol_trunc($ret,$maxlen);
486
+    }
487
+
488
+    /**
489
+     * 	Return full address of contact
490
+     *
491
+     * 	@param		int			$withcountry		1=Add country into address string
492
+     *  @param		string		$sep				Separator to use to build string
493
+     *  @param		int		    $withregion			1=Add region into address string
494
+     *	@return		string							Full address string
495
+     */
496
+    function getFullAddress($withcountry=0, $sep="\n", $withregion=0)
497
+    {
498
+        if ($withcountry && $this->country_id && (empty($this->country_code) || empty($this->country)))
2066 499
         {
2067
-            $this->db->rollback();
2068
-            return -1;
2069
-        } else {
2070
-            $this->shipping_method_id = ($shipping_method_id=='NULL')?null:$shipping_method_id;
2071
-            $this->db->commit();
2072
-            return 1;
500
+            require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php';
501
+            $tmparray=getCountry($this->country_id,'all');
502
+            $this->country_code=$tmparray['code'];
503
+            $this->country     =$tmparray['label'];
2073 504
         }
2074
-	}
2075
-
2076
-
2077
-	/**
2078
-	 *  Change the warehouse
2079
-	 *
2080
-	 *  @param      int     $warehouse_id     Id of warehouse
2081
-	 *  @return     int              1 if OK, 0 if KO
2082
-	 */
2083
-	function setWarehouse($warehouse_id)
2084
-	{
2085
-		if (! $this->table_element) {
2086
-			dol_syslog(get_class($this)."::setWarehouse was called on objet with property table_element not defined",LOG_ERR);
2087
-			return -1;
2088
-		}
2089
-		if ($warehouse_id<0) $warehouse_id='NULL';
2090
-		dol_syslog(get_class($this).'::setWarehouse('.$warehouse_id.')');
2091
-
2092
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2093
-		$sql.= " SET fk_warehouse = ".$warehouse_id;
2094
-		$sql.= " WHERE rowid=".$this->id;
2095
-
2096
-		if ($this->db->query($sql)) {
2097
-			$this->warehouse_id = ($warehouse_id=='NULL')?null:$warehouse_id;
2098
-			return 1;
2099
-		} else {
2100
-			dol_syslog(get_class($this).'::setWarehouse Error ', LOG_DEBUG);
2101
-			$this->error=$this->db->error();
2102
-			return 0;
2103
-		}
2104
-	}
2105
-
2106
-
2107
-	/**
2108
-	 *		Set last model used by doc generator
2109
-	 *
2110
-	 *		@param		User	$user		User object that make change
2111
-	 *		@param		string	$modelpdf	Modele name
2112
-	 *		@return		int					<0 if KO, >0 if OK
2113
-	 */
2114
-	function setDocModel($user, $modelpdf)
2115
-	{
2116
-		if (! $this->table_element)
2117
-		{
2118
-			dol_syslog(get_class($this)."::setDocModel was called on objet with property table_element not defined",LOG_ERR);
2119
-			return -1;
2120
-		}
2121
-
2122
-		$newmodelpdf=dol_trunc($modelpdf,255);
2123
-
2124
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2125
-		$sql.= " SET model_pdf = '".$this->db->escape($newmodelpdf)."'";
2126
-		$sql.= " WHERE rowid = ".$this->id;
2127
-		// if ($this->element == 'facture') $sql.= " AND fk_statut < 2";
2128
-		// if ($this->element == 'propal')  $sql.= " AND fk_statut = 0";
2129
-
2130
-		dol_syslog(get_class($this)."::setDocModel", LOG_DEBUG);
2131
-		$resql=$this->db->query($sql);
2132
-		if ($resql)
2133
-		{
2134
-			$this->modelpdf=$modelpdf;
2135
-			return 1;
2136
-		}
2137
-		else
2138
-		{
2139
-			dol_print_error($this->db);
2140
-			return 0;
2141
-		}
2142
-	}
2143
-
2144
-
2145
-	/**
2146
-	 *  Change the bank account
2147
-	 *
2148
-	 *  @param		int		$fk_account		Id of bank account
2149
-	 *  @param      bool    $notrigger      false=launch triggers after, true=disable triggers
2150
-	 *  @param      User	$userused		Object user
2151
-	 *  @return		int				1 if OK, 0 if KO
2152
-	 */
2153
-	function setBankAccount($fk_account, $notrigger=false, $userused=null)
2154
-	{
2155
-        global $user;
2156 505
 
2157
-        if (empty($userused)) $userused=$user;
506
+        if ($withregion && $this->state_id && (empty($this->state_code) || empty($this->state) || empty($this->region) || empty($this->region_cpde)))
507
+        {
508
+            require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php';
509
+            $tmparray=getState($this->state_id,'all',0,1);
510
+            $this->state_code   =$tmparray['code'];
511
+            $this->state        =$tmparray['label'];
512
+            $this->region_code  =$tmparray['region_code'];
513
+            $this->region       =$tmparray['region'];
514
+        }
2158 515
 
2159
-        $error = 0;
516
+        return dol_format_address($this, $withcountry, $sep);
517
+    }
2160 518
 
2161
-		if (! $this->table_element) {
2162
-			dol_syslog(get_class($this)."::setBankAccount was called on objet with property table_element not defined",LOG_ERR);
2163
-			return -1;
2164
-		}
2165
-        $this->db->begin();
2166 519
 
2167
-		if ($fk_account<0) $fk_account='NULL';
2168
-		dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')');
520
+    /**
521
+     * 	Return full address for banner
522
+     *
523
+     * 	@param		string		$htmlkey            HTML id to make banner content unique
524
+     *  @param      Object      $object				Object (thirdparty, thirdparty of contact for contact, null for a member)
525
+     *	@return		string							Full address string
526
+     */
527
+    function getBannerAddress($htmlkey, $object)
528
+    {
529
+        global $conf, $langs;
2169 530
 
2170
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2171
-		$sql.= " SET fk_account = ".$fk_account;
2172
-		$sql.= " WHERE rowid=".$this->id;
531
+        $countriesusingstate=array('AU','US','IN','GB','ES','UK','TR');    // See also option MAIN_FORCE_STATE_INTO_ADDRESS
2173 532
 
2174
-        $resql = $this->db->query($sql);
2175
-        if (! $resql)
533
+        $contactid=0;
534
+        $thirdpartyid=0;
535
+        if ($this->element == 'societe')
2176 536
         {
2177
-            dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error());
2178
-            $this->error = $this->db->lasterror();
2179
-            $error++;
537
+            $thirdpartyid=$this->id;
2180 538
         }
2181
-        else
539
+        if ($this->element == 'contact')
2182 540
         {
2183
-            if (!$notrigger)
541
+            $contactid=$this->id;
542
+            $thirdpartyid=$object->fk_soc;
543
+        }
544
+        if ($this->element == 'user')
545
+        {
546
+            $contactid=$this->contact_id;
547
+            $thirdpartyid=$object->fk_soc;
548
+        }
549
+
550
+        $out='<!-- BEGIN part to show address block -->';
551
+
552
+        $outdone=0;
553
+        $coords = $this->getFullAddress(1,', ',$conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT);
554
+        if ($coords)
555
+        {
556
+            if (! empty($conf->use_javascript_ajax))
2184 557
             {
2185
-                // Call trigger
2186
-                $this->context=array('bankaccountupdate'=>1);
2187
-                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2188
-                if ($result < 0) $error++;
2189
-                // End call trigger
558
+                $namecoords = $this->getFullName($langs,1).'<br>'.$coords;
559
+                // hideonsmatphone because copyToClipboard call jquery dialog that does not work with jmobile
560
+                $out.='<a href="#" class="hideonsmartphone" onclick="return copyToClipboard(\''.dol_escape_js($namecoords).'\',\''.dol_escape_js($langs->trans("HelpCopyToClipboard")).'\');">';
561
+                $out.=img_picto($langs->trans("Address"), 'object_address.png');
562
+                $out.='</a> ';
2190 563
             }
564
+            $out.=dol_print_address($coords, 'address_'.$htmlkey.'_'.$this->id, $this->element, $this->id, 1, ', '); $outdone++;
565
+            $outdone++;
2191 566
         }
2192
-        if ($error)
567
+
568
+        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
569
+                && empty($conf->global->SOCIETE_DISABLE_STATE) && $this->state)
2193 570
         {
2194
-            $this->db->rollback();
2195
-            return -1;
571
+            if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 && $this->region) {
572
+                $out.=($outdone?' - ':'').$this->region.' - '.$this->state;
573
+            }
574
+            else {
575
+                $out.=($outdone?' - ':'').$this->state;
576
+            }
577
+            $outdone++;
2196 578
         }
2197
-        else
579
+
580
+        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>':'');
581
+        if (! empty($this->phone) && empty($this->phone_pro)) {		// For objects that store pro phone into ->phone
582
+            $out.=dol_print_phone($this->phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
583
+        }
584
+        if (! empty($this->phone_pro)) {
585
+            $out.=dol_print_phone($this->phone_pro,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
586
+        }
587
+        if (! empty($this->phone_mobile)) {
588
+            $out.=dol_print_phone($this->phone_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','mobile',$langs->trans("PhoneMobile")); $outdone++;
589
+        }
590
+        if (! empty($this->phone_perso)) {
591
+            $out.=dol_print_phone($this->phone_perso,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePerso")); $outdone++;
592
+        }
593
+        if (! empty($this->office_phone)) {
594
+            $out.=dol_print_phone($this->office_phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','phone',$langs->trans("PhonePro")); $outdone++;
595
+        }
596
+        if (! empty($this->user_mobile)) {
597
+            $out.=dol_print_phone($this->user_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL','&nbsp;','mobile',$langs->trans("PhoneMobile")); $outdone++;
598
+        }
599
+        if (! empty($this->fax)) {
600
+            $out.=dol_print_phone($this->fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX','&nbsp;','fax',$langs->trans("Fax")); $outdone++;
601
+        }
602
+        if (! empty($this->office_fax)) {
603
+            $out.=dol_print_phone($this->office_fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX','&nbsp;','fax',$langs->trans("Fax")); $outdone++;
604
+        }
605
+
606
+        $out.='<div style="clear: both;"></div>';
607
+        $outdone=0;
608
+        if (! empty($this->email))
2198 609
         {
2199
-            $this->fk_account = ($fk_account=='NULL')?null:$fk_account;
2200
-            $this->db->commit();
2201
-            return 1;
610
+            $out.=dol_print_email($this->email,$this->id,$object->id,'AC_EMAIL',0,0,1);
611
+            $outdone++;
612
+        }
613
+        if (! empty($this->url))
614
+        {
615
+            $out.=dol_print_url($this->url,'_goout',0,1);
616
+            $outdone++;
2202 617
         }
618
+        $out.='<div style="clear: both;">';
619
+        if (! empty($conf->socialnetworks->enabled))
620
+        {
621
+            if ($this->skype) $out.=dol_print_socialnetworks($this->skype,$this->id,$object->id,'skype');
622
+            $outdone++;
623
+            if ($this->jabberid) $out.=dol_print_socialnetworks($this->jabberid,$this->id,$object->id,'jabber');
624
+            $outdone++;
625
+            if ($this->twitter) $out.=dol_print_socialnetworks($this->twitter,$this->id,$object->id,'twitter');
626
+            $outdone++;
627
+            if ($this->facebook) $out.=dol_print_socialnetworks($this->facebook,$this->id,$object->id,'facebook');
628
+            $outdone++;
629
+        }
630
+        $out.='</div>';
631
+
632
+        $out.='<!-- END Part to show address block -->';
633
+
634
+        return $out;
2203 635
     }
2204 636
 
637
+    /**
638
+     * Return the link of last main doc file for direct public download.
639
+     *
640
+     * @param	string	$modulepart			Module related to document
641
+     * @param	int		$initsharekey		Init the share key if it was not yet defined
642
+     * @param	int		$relativelink		0=Return full external link, 1=Return link relative to root of file
643
+     * @return	string						Link or empty string if there is no download link
644
+     */
645
+    function getLastMainDocLink($modulepart, $initsharekey=0, $relativelink=0)
646
+    {
647
+        global $user, $dolibarr_main_url_root;
2205 648
 
2206
-	// TODO: Move line related operations to CommonObjectLine?
649
+        if (empty($this->last_main_doc))
650
+        {
651
+            return '';		// No way to known which document name to use
652
+        }
2207 653
 
2208
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2209
-	/**
2210
-	 *  Save a new position (field rang) for details lines.
2211
-	 *  You can choose to set position for lines with already a position or lines without any position defined.
2212
-	 *
2213
-	 * 	@param		boolean		$renum			   True to renum all already ordered lines, false to renum only not already ordered lines.
2214
-	 * 	@param		string		$rowidorder		   ASC or DESC
2215
-	 * 	@param		boolean		$fk_parent_line    Table with fk_parent_line field or not
2216
-	 * 	@return		int                            <0 if KO, >0 if OK
2217
-	 */
2218
-	function line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
2219
-	{
2220
-        // phpcs:enable
2221
-		if (! $this->table_element_line)
2222
-		{
2223
-			dol_syslog(get_class($this)."::line_order was called on objet with property table_element_line not defined",LOG_ERR);
2224
-			return -1;
2225
-		}
2226
-		if (! $this->fk_element)
2227
-		{
2228
-			dol_syslog(get_class($this)."::line_order was called on objet with property fk_element not defined",LOG_ERR);
2229
-			return -1;
2230
-		}
2231
-
2232
-		// Count number of lines to reorder (according to choice $renum)
2233
-		$nl=0;
2234
-		$sql = 'SELECT count(rowid) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2235
-		$sql.= ' WHERE '.$this->fk_element.'='.$this->id;
2236
-		if (! $renum) $sql.= ' AND rang = 0';
2237
-		if ($renum) $sql.= ' AND rang <> 0';
2238
-
2239
-		dol_syslog(get_class($this)."::line_order", LOG_DEBUG);
2240
-		$resql = $this->db->query($sql);
2241
-		if ($resql)
2242
-		{
2243
-			$row = $this->db->fetch_row($resql);
2244
-			$nl = $row[0];
2245
-		}
2246
-		else dol_print_error($this->db);
2247
-		if ($nl > 0)
2248
-		{
2249
-			// The goal of this part is to reorder all lines, with all children lines sharing the same
2250
-			// counter that parents.
2251
-			$rows=array();
2252
-
2253
-			// We first search all lines that are parent lines (for multilevel details lines)
2254
-			$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2255
-			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2256
-			if ($fk_parent_line) $sql.= ' AND fk_parent_line IS NULL';
2257
-			$sql.= ' ORDER BY rang ASC, rowid '.$rowidorder;
2258
-
2259
-			dol_syslog(get_class($this)."::line_order search all parent lines", LOG_DEBUG);
2260
-			$resql = $this->db->query($sql);
2261
-			if ($resql)
2262
-			{
2263
-				$i=0;
2264
-				$num = $this->db->num_rows($resql);
2265
-				while ($i < $num)
2266
-				{
2267
-					$row = $this->db->fetch_row($resql);
2268
-					$rows[] = $row[0];	// Add parent line into array rows
2269
-					$childrens = $this->getChildrenOfLine($row[0]);
2270
-					if (! empty($childrens))
2271
-					{
2272
-						foreach($childrens as $child)
2273
-						{
2274
-							array_push($rows, $child);
2275
-						}
2276
-					}
2277
-					$i++;
2278
-				}
654
+        include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
655
+        $ecmfile=new EcmFiles($this->db);
656
+        $result = $ecmfile->fetch(0, '', $this->last_main_doc);
657
+        if ($result < 0)
658
+        {
659
+            $this->error = $ecmfile->error;
660
+            $this->errors = $ecmfile->errors;
661
+            return -1;
662
+        }
2279 663
 
2280
-				// Now we set a new number for each lines (parent and children with children included into parent tree)
2281
-				if (! empty($rows))
664
+        if (empty($ecmfile->id))
665
+        {
666
+            // Add entry into index
667
+            if ($initsharekey)
668
+            {
669
+                require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
670
+                // TODO We can't, we dont' have full path of file, only last_main_doc adn ->element, so we must rebuild full path first
671
+                /*
672
+				$ecmfile->filepath = $rel_dir;
673
+				$ecmfile->filename = $filename;
674
+				$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
675
+				$ecmfile->fullpath_orig = '';
676
+				$ecmfile->gen_or_uploaded = 'generated';
677
+				$ecmfile->description = '';    // indexed content
678
+				$ecmfile->keyword = '';        // keyword content
679
+				$ecmfile->share = getRandomPassword(true);
680
+				$result = $ecmfile->create($user);
681
+				if ($result < 0)
2282 682
 				{
2283
-					foreach($rows as $key => $row)
2284
-					{
2285
-						$this->updateRangOfLine($row, ($key+1));
2286
-					}
683
+					$this->error = $ecmfile->error;
684
+					$this->errors = $ecmfile->errors;
2287 685
 				}
2288
-			}
2289
-			else
2290
-			{
2291
-				dol_print_error($this->db);
2292
-			}
2293
-		}
2294
-		return 1;
2295
-	}
2296
-
2297
-	/**
2298
-	 * 	Get children of line
2299
-	 *
2300
-	 * 	@param	int		$id		Id of parent line
2301
-	 * 	@return	array			Array with list of children lines id
2302
-	 */
2303
-	function getChildrenOfLine($id)
2304
-	{
2305
-		$rows=array();
2306
-
2307
-		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2308
-		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2309
-		$sql.= ' AND fk_parent_line = '.$id;
2310
-		$sql.= ' ORDER BY rang ASC';
2311
-
2312
-		dol_syslog(get_class($this)."::getChildrenOfLine search children lines for line ".$id."", LOG_DEBUG);
2313
-		$resql = $this->db->query($sql);
2314
-		if ($resql)
2315
-		{
2316
-			$i=0;
2317
-			$num = $this->db->num_rows($resql);
2318
-			while ($i < $num)
2319
-			{
2320
-				$row = $this->db->fetch_row($resql);
2321
-				$rows[$i] = $row[0];
2322
-				$i++;
2323
-			}
2324
-		}
686
+				*/
687
+            }
688
+            else return '';
689
+        }
690
+        elseif (empty($ecmfile->share))
691
+        {
692
+            // Add entry into index
693
+            if ($initsharekey)
694
+            {
695
+                require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
696
+                $ecmfile->share = getRandomPassword(true);
697
+                $ecmfile->update($user);
698
+            }
699
+            else return '';
700
+        }
2325 701
 
2326
-		return $rows;
2327
-	}
702
+        // Define $urlwithroot
703
+        $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
704
+        $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT;		// This is to use external domain name found into config file
705
+        //$urlwithroot=DOL_MAIN_URL_ROOT;					// This is to use same domain name than current
2328 706
 
2329
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2330
-	/**
2331
-	 * 	Update a line to have a lower rank
2332
-	 *
2333
-	 * 	@param 	int			$rowid				Id of line
2334
-	 * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2335
-	 * 	@return	void
2336
-	 */
2337
-	function line_up($rowid, $fk_parent_line=true)
2338
-	{
2339
-        // phpcs:enable
2340
-		$this->line_order(false, 'ASC', $fk_parent_line);
707
+        $forcedownload=0;
2341 708
 
2342
-		// Get rang of line
2343
-		$rang = $this->getRangOfLine($rowid);
709
+        $paramlink='';
710
+        //if (! empty($modulepart)) $paramlink.=($paramlink?'&':'').'modulepart='.$modulepart;		// For sharing with hash (so public files), modulepart is not required.
711
+        //if (! empty($ecmfile->entity)) $paramlink.='&entity='.$ecmfile->entity; 					// For sharing with hash (so public files), entity is not required.
712
+        //$paramlink.=($paramlink?'&':'').'file='.urlencode($filepath);								// No need of name of file for public link, we will use the hash
713
+        if (! empty($ecmfile->share)) $paramlink.=($paramlink?'&':'').'hashp='.$ecmfile->share;			// Hash for public share
714
+        if ($forcedownload) $paramlink.=($paramlink?'&':'').'attachment=1';
2344 715
 
2345
-		// Update position of line
2346
-		$this->updateLineUp($rowid, $rang);
2347
-	}
716
+        if ($relativelink)
717
+        {
718
+            $linktoreturn='document.php'.($paramlink?'?'.$paramlink:'');
719
+        }
720
+        else
721
+        {
722
+            $linktoreturn=$urlwithroot.'/document.php'.($paramlink?'?'.$paramlink:'');
723
+        }
2348 724
 
2349
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2350
-	/**
2351
-	 * 	Update a line to have a higher rank
2352
-	 *
2353
-	 * 	@param	int			$rowid				Id of line
2354
-	 * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2355
-	 * 	@return	void
2356
-	 */
2357
-	function line_down($rowid, $fk_parent_line=true)
2358
-	{
2359
-        // phpcs:enable
2360
-		$this->line_order(false, 'ASC', $fk_parent_line);
2361
-
2362
-		// Get rang of line
2363
-		$rang = $this->getRangOfLine($rowid);
2364
-
2365
-		// Get max value for rang
2366
-		$max = $this->line_max();
2367
-
2368
-		// Update position of line
2369
-		$this->updateLineDown($rowid, $rang, $max);
2370
-	}
2371
-
2372
-	/**
2373
-	 * 	Update position of line (rang)
2374
-	 *
2375
-	 * 	@param	int		$rowid		Id of line
2376
-	 * 	@param	int		$rang		Position
2377
-	 * 	@return	void
2378
-	 */
2379
-	function updateRangOfLine($rowid,$rang)
2380
-	{
2381
-		$fieldposition = 'rang';
2382
-		if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2383
-
2384
-		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2385
-		$sql.= ' WHERE rowid = '.$rowid;
2386
-
2387
-		dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
2388
-		if (! $this->db->query($sql))
2389
-		{
2390
-			dol_print_error($this->db);
2391
-		}
2392
-	}
725
+        // Here $ecmfile->share is defined
726
+        return $linktoreturn;
727
+    }
2393 728
 
2394
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2395
-	/**
2396
-	 * 	Update position of line with ajax (rang)
2397
-	 *
2398
-	 * 	@param	array	$rows	Array of rows
2399
-	 * 	@return	void
2400
-	 */
2401
-	function line_ajaxorder($rows)
2402
-	{
2403
-        // phpcs:enable
2404
-		$num = count($rows);
2405
-		for ($i = 0 ; $i < $num ; $i++)
2406
-		{
2407
-			$this->updateRangOfLine($rows[$i], ($i+1));
2408
-		}
2409
-	}
2410
-
2411
-	/**
2412
-	 * 	Update position of line up (rang)
2413
-	 *
2414
-	 * 	@param	int		$rowid		Id of line
2415
-	 * 	@param	int		$rang		Position
2416
-	 * 	@return	void
2417
-	 */
2418
-	function updateLineUp($rowid,$rang)
2419
-	{
2420
-		if ($rang > 1)
2421
-		{
2422
-			$fieldposition = 'rang';
2423
-			if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2424
-
2425
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang ;
2426
-			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2427
-			$sql.= ' AND rang = '.($rang - 1);
2428
-			if ($this->db->query($sql) )
2429
-			{
2430
-				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang - 1);
2431
-				$sql.= ' WHERE rowid = '.$rowid;
2432
-				if (! $this->db->query($sql) )
2433
-				{
2434
-					dol_print_error($this->db);
2435
-				}
2436
-			}
2437
-			else
2438
-			{
2439
-				dol_print_error($this->db);
2440
-			}
2441
-		}
2442
-	}
2443
-
2444
-	/**
2445
-	 * 	Update position of line down (rang)
2446
-	 *
2447
-	 * 	@param	int		$rowid		Id of line
2448
-	 * 	@param	int		$rang		Position
2449
-	 * 	@param	int		$max		Max
2450
-	 * 	@return	void
2451
-	 */
2452
-	function updateLineDown($rowid,$rang,$max)
2453
-	{
2454
-		if ($rang < $max)
2455
-		{
2456
-			$fieldposition = 'rang';
2457
-			if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2458
-
2459
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2460
-			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2461
-			$sql.= ' AND rang = '.($rang+1);
2462
-			if ($this->db->query($sql) )
2463
-			{
2464
-				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang+1);
2465
-				$sql.= ' WHERE rowid = '.$rowid;
2466
-				if (! $this->db->query($sql) )
2467
-				{
2468
-					dol_print_error($this->db);
2469
-				}
2470
-			}
2471
-			else
2472
-			{
2473
-				dol_print_error($this->db);
2474
-			}
2475
-		}
2476
-	}
2477
-
2478
-	/**
2479
-	 * 	Get position of line (rang)
2480
-	 *
2481
-	 * 	@param		int		$rowid		Id of line
2482
-	 *  @return		int     			Value of rang in table of lines
2483
-	 */
2484
-	function getRangOfLine($rowid)
2485
-	{
2486
-		$sql = 'SELECT rang FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2487
-		$sql.= ' WHERE rowid ='.$rowid;
2488
-
2489
-		dol_syslog(get_class($this)."::getRangOfLine", LOG_DEBUG);
2490
-		$resql = $this->db->query($sql);
2491
-		if ($resql)
2492
-		{
2493
-			$row = $this->db->fetch_row($resql);
2494
-			return $row[0];
2495
-		}
2496
-	}
2497
-
2498
-	/**
2499
-	 * 	Get rowid of the line relative to its position
2500
-	 *
2501
-	 * 	@param		int		$rang		Rang value
2502
-	 *  @return     int     			Rowid of the line
2503
-	 */
2504
-	function getIdOfLine($rang)
2505
-	{
2506
-		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2507
-		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2508
-		$sql.= ' AND rang = '.$rang;
2509
-		$resql = $this->db->query($sql);
2510
-		if ($resql)
2511
-		{
2512
-			$row = $this->db->fetch_row($resql);
2513
-			return $row[0];
2514
-		}
2515
-	}
2516 729
 
2517 730
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2518
-	/**
2519
-	 * 	Get max value used for position of line (rang)
2520
-	 *
2521
-	 * 	@param		int		$fk_parent_line		Parent line id
2522
-	 *  @return     int  			   			Max value of rang in table of lines
2523
-	 */
2524
-	function line_max($fk_parent_line=0)
2525
-	{
731
+    /**
732
+     *  Add a link between element $this->element and a contact
733
+     *
734
+     *  @param	int		$fk_socpeople       Id of thirdparty contact (if source = 'external') or id of user (if souce = 'internal') to link
735
+     *  @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
736
+     *  @param  string	$source             external=Contact extern (llx_socpeople), internal=Contact intern (llx_user)
737
+     *  @param  int		$notrigger			Disable all triggers
738
+     *  @return int                 		<0 if KO, >0 if OK
739
+     */
740
+    function add_contact($fk_socpeople, $type_contact, $source='external',$notrigger=0)
741
+    {
2526 742
         // phpcs:enable
2527
-		// Search the last rang with fk_parent_line
2528
-		if ($fk_parent_line)
2529
-		{
2530
-			$sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2531
-			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2532
-			$sql.= ' AND fk_parent_line = '.$fk_parent_line;
2533
-
2534
-			dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2535
-			$resql = $this->db->query($sql);
2536
-			if ($resql)
2537
-			{
2538
-				$row = $this->db->fetch_row($resql);
2539
-				if (! empty($row[0]))
2540
-				{
2541
-					return $row[0];
2542
-				}
2543
-				else
2544
-				{
2545
-					return $this->getRangOfLine($fk_parent_line);
2546
-				}
2547
-			}
2548
-		}
2549
-		// If not, search the last rang of element
2550
-		else
2551
-		{
2552
-			$sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2553
-			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2554
-
2555
-			dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2556
-			$resql = $this->db->query($sql);
2557
-			if ($resql)
2558
-			{
2559
-				$row = $this->db->fetch_row($resql);
2560
-				return $row[0];
2561
-			}
2562
-		}
2563
-	}
743
+        global $user,$langs;
2564 744
 
2565
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2566
-	/**
2567
-	 *  Update external ref of element
2568
-	 *
2569
-	 *  @param      string		$ref_ext	Update field ref_ext
2570
-	 *  @return     int      		   		<0 if KO, >0 if OK
2571
-	 */
2572
-	function update_ref_ext($ref_ext)
2573
-	{
2574
-        // phpcs:enable
2575
-		if (! $this->table_element)
2576
-		{
2577
-			dol_syslog(get_class($this)."::update_ref_ext was called on objet with property table_element not defined", LOG_ERR);
2578
-			return -1;
2579
-		}
2580
-
2581
-		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2582
-		$sql.= " SET ref_ext = '".$this->db->escape($ref_ext)."'";
2583
-		$sql.= " WHERE ".(isset($this->table_rowid)?$this->table_rowid:'rowid')." = ". $this->id;
2584
-
2585
-		dol_syslog(get_class($this)."::update_ref_ext", LOG_DEBUG);
2586
-		if ($this->db->query($sql))
2587
-		{
2588
-			$this->ref_ext = $ref_ext;
2589
-			return 1;
2590
-		}
2591
-		else
2592
-		{
2593
-			$this->error=$this->db->error();
2594
-			return -1;
2595
-		}
2596
-	}
745
+
746
+        dol_syslog(get_class($this)."::add_contact $fk_socpeople, $type_contact, $source, $notrigger");
747
+
748
+        // Check parameters
749
+        if ($fk_socpeople <= 0)
750
+        {
751
+            $langs->load("errors");
752
+            $this->error=$langs->trans("ErrorWrongValueForParameterX","1");
753
+            dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
754
+            return -1;
755
+        }
756
+        if (! $type_contact)
757
+        {
758
+            $langs->load("errors");
759
+            $this->error=$langs->trans("ErrorWrongValueForParameterX","2");
760
+            dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
761
+            return -2;
762
+        }
763
+
764
+        $id_type_contact=0;
765
+        if (is_numeric($type_contact))
766
+        {
767
+            $id_type_contact=$type_contact;
768
+        }
769
+        else
770
+        {
771
+            // We look for id type_contact
772
+            $sql = "SELECT tc.rowid";
773
+            $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
774
+            $sql.= " WHERE tc.element='".$this->db->escape($this->element)."'";
775
+            $sql.= " AND tc.source='".$this->db->escape($source)."'";
776
+            $sql.= " AND tc.code='".$this->db->escape($type_contact)."' AND tc.active=1";
777
+            //print $sql;
778
+            $resql=$this->db->query($sql);
779
+            if ($resql)
780
+            {
781
+                $obj = $this->db->fetch_object($resql);
782
+                if ($obj) $id_type_contact=$obj->rowid;
783
+            }
784
+        }
785
+
786
+        if ($id_type_contact == 0)
787
+        {
788
+            $this->error='CODE_NOT_VALID_FOR_THIS_ELEMENT';
789
+            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");
790
+            return -3;
791
+        }
792
+
793
+        $datecreate = dol_now();
794
+
795
+        // Socpeople must have already been added by some trigger, then we have to check it to avoid DB_ERROR_RECORD_ALREADY_EXISTS error
796
+        $TListeContacts=$this->liste_contact(-1, $source);
797
+        $already_added=false;
798
+        if(!empty($TListeContacts)) {
799
+            foreach($TListeContacts as $array_contact) {
800
+                if($array_contact['status'] == 4 && $array_contact['id'] == $fk_socpeople && $array_contact['fk_c_type_contact'] == $id_type_contact) {
801
+                    $already_added=true;
802
+                    break;
803
+                }
804
+            }
805
+        }
806
+
807
+        if(!$already_added) {
808
+
809
+            $this->db->begin();
810
+
811
+            // Insert into database
812
+            $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_contact";
813
+            $sql.= " (element_id, fk_socpeople, datecreate, statut, fk_c_type_contact) ";
814
+            $sql.= " VALUES (".$this->id.", ".$fk_socpeople." , " ;
815
+            $sql.= "'".$this->db->idate($datecreate)."'";
816
+            $sql.= ", 4, ". $id_type_contact;
817
+            $sql.= ")";
818
+
819
+            $resql=$this->db->query($sql);
820
+            if ($resql)
821
+            {
822
+                if (! $notrigger)
823
+                {
824
+                    $result=$this->call_trigger(strtoupper($this->element).'_ADD_CONTACT', $user);
825
+                    if ($result < 0)
826
+                    {
827
+                        $this->db->rollback();
828
+                        return -1;
829
+                    }
830
+                }
831
+
832
+                $this->db->commit();
833
+                return 1;
834
+            }
835
+            else
836
+            {
837
+                if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS')
838
+                {
839
+                    $this->error=$this->db->errno();
840
+                    $this->db->rollback();
841
+                    echo 'err rollback';
842
+                    return -2;
843
+                }
844
+                else
845
+                {
846
+                    $this->error=$this->db->error();
847
+                    $this->db->rollback();
848
+                    return -1;
849
+                }
850
+            }
851
+        } else return 0;
852
+    }
2597 853
 
2598 854
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2599
-	/**
2600
-	 *  Update note of element
2601
-	 *
2602
-	 *  @param      string		$note		New value for note
2603
-	 *  @param		string		$suffix		'', '_public' or '_private'
2604
-	 *  @return     int      		   		<0 if KO, >0 if OK
2605
-	 */
2606
-	function update_note($note, $suffix='')
2607
-	{
855
+    /**
856
+     *    Copy contact from one element to current
857
+     *
858
+     *    @param    CommonObject    $objFrom    Source element
859
+     *    @param    string          $source     Nature of contact ('internal' or 'external')
860
+     *    @return   int                         >0 if OK, <0 if KO
861
+     */
862
+    function copy_linked_contact($objFrom, $source='internal')
863
+    {
2608 864
         // phpcs:enable
2609
-		global $user;
2610
-
2611
-		if (! $this->table_element)
2612
-		{
2613
-			$this->error='update_note was called on objet with property table_element not defined';
2614
-			dol_syslog(get_class($this)."::update_note was called on objet with property table_element not defined", LOG_ERR);
2615
-			return -1;
2616
-		}
2617
-		if (! in_array($suffix,array('','_public','_private')))
2618
-		{
2619
-			$this->error='update_note Parameter suffix must be empty, \'_private\' or \'_public\'';
2620
-			dol_syslog(get_class($this)."::update_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR);
2621
-			return -2;
2622
-		}
2623
-		// Special cas
2624
-		//var_dump($this->table_element);exit;
2625
-		if ($this->table_element == 'product') $suffix='';
2626
-
2627
-		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2628
-		$sql.= " SET note".$suffix." = ".(!empty($note)?("'".$this->db->escape($note)."'"):"NULL");
2629
-		$sql.= " ,".(in_array($this->table_element, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))?"fk_user_mod":"fk_user_modif")." = ".$user->id;
2630
-		$sql.= " WHERE rowid =". $this->id;
2631
-
2632
-		dol_syslog(get_class($this)."::update_note", LOG_DEBUG);
2633
-		if ($this->db->query($sql))
2634
-		{
2635
-			if ($suffix == '_public') $this->note_public = $note;
2636
-			else if ($suffix == '_private') $this->note_private = $note;
2637
-			else
2638
-			{
2639
-				$this->note = $note;      // deprecated
2640
-				$this->note_private = $note;
2641
-			}
2642
-			return 1;
2643
-		}
2644
-		else
2645
-		{
2646
-			$this->error=$this->db->lasterror();
2647
-			return -1;
2648
-		}
2649
-	}
865
+        $contacts = $objFrom->liste_contact(-1, $source);
866
+        foreach($contacts as $contact)
867
+        {
868
+            if ($this->add_contact($contact['id'], $contact['fk_c_type_contact'], $contact['source']) < 0)
869
+            {
870
+                $this->error=$this->db->lasterror();
871
+                return -1;
872
+            }
873
+        }
874
+        return 1;
875
+    }
2650 876
 
2651 877
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2652
-	/**
2653
-	 * 	Update public note (kept for backward compatibility)
2654
-	 *
2655
-	 * @param      string		$note		New value for note
2656
-	 * @return     int      		   		<0 if KO, >0 if OK
2657
-	 * @deprecated
2658
-	 * @see update_note()
2659
-	 */
2660
-	function update_note_public($note)
2661
-	{
878
+    /**
879
+     *      Update a link to contact line
880
+     *
881
+     *      @param	int		$rowid              Id of line contact-element
882
+     * 		@param	int		$statut	            New status of link
883
+     *      @param  int		$type_contact_id    Id of contact type (not modified if 0)
884
+     *      @param  int		$fk_socpeople	    Id of soc_people to update (not modified if 0)
885
+     *      @return int                 		<0 if KO, >= 0 if OK
886
+     */
887
+    function update_contact($rowid, $statut, $type_contact_id=0, $fk_socpeople=0)
888
+    {
2662 889
         // phpcs:enable
2663
-		return $this->update_note($note,'_public');
2664
-	}
890
+        // Insert into database
891
+        $sql = "UPDATE ".MAIN_DB_PREFIX."element_contact set";
892
+        $sql.= " statut = ".$statut;
893
+        if ($type_contact_id) $sql.= ", fk_c_type_contact = '".$type_contact_id ."'";
894
+        if ($fk_socpeople) $sql.= ", fk_socpeople = '".$fk_socpeople ."'";
895
+        $sql.= " where rowid = ".$rowid;
896
+        $resql=$this->db->query($sql);
897
+        if ($resql)
898
+        {
899
+            return 0;
900
+        }
901
+        else
902
+        {
903
+            $this->error=$this->db->lasterror();
904
+            return -1;
905
+        }
906
+    }
2665 907
 
2666 908
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2667
-	/**
2668
-	 *	Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
2669
-	 *  Must be called at end of methods addline or updateline.
2670
-	 *
2671
-	 *	@param	int		$exclspec          	>0 = Exclude special product (product_type=9)
2672
-	 *  @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
2673
-	 *  @param	int		$nodatabaseupdate	1=Do not update database. Update only properties of object.
2674
-	 *  @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.
2675
-	 *	@return	int    			           	<0 if KO, >0 if OK
2676
-	 */
2677
-	function update_price($exclspec=0,$roundingadjust='none',$nodatabaseupdate=0,$seller=null)
2678
-	{
909
+    /**
910
+     *    Delete a link to contact line
911
+     *
912
+     *    @param	int		$rowid			Id of contact link line to delete
913
+     *    @param	int		$notrigger		Disable all triggers
914
+     *    @return   int						>0 if OK, <0 if KO
915
+     */
916
+    function delete_contact($rowid, $notrigger=0)
917
+    {
2679 918
         // phpcs:enable
2680
-		global $conf, $hookmanager, $action;
2681
-
2682
-		// Some external module want no update price after a trigger because they have another method to calculate the total (ex: with an extrafield)
2683
-		$MODULE = "";
2684
-		if ($this->element == 'propal')
2685
-			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_PROPOSAL";
2686
-		elseif ($this->element == 'order')
2687
-			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER";
2688
-		elseif ($this->element == 'facture')
2689
-			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE";
2690
-		elseif ($this->element == 'facture_fourn')
2691
-			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE";
2692
-		elseif ($this->element == 'order_supplier')
2693
-			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER";
2694
-		elseif ($this->element == 'supplier_proposal')
2695
-			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_PROPOSAL";
2696
-
2697
-		if (! empty($MODULE)) {
2698
-			if (! empty($conf->global->$MODULE)) {
2699
-				$modsactivated = explode(',', $conf->global->$MODULE);
2700
-				foreach ($modsactivated as $mod) {
2701
-					if ($conf->$mod->enabled)
2702
-						return 1; // update was disabled by specific setup
2703
-				}
2704
-			}
2705
-		}
2706
-
2707
-		include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2708
-
2709
-		if ($roundingadjust == '-1') $roundingadjust='auto';	// For backward compatibility
2710
-
2711
-		$forcedroundingmode=$roundingadjust;
2712
-		if ($forcedroundingmode == 'auto' && isset($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)) $forcedroundingmode=$conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND;
2713
-		elseif ($forcedroundingmode == 'auto') $forcedroundingmode='0';
2714
-
2715
-		$error=0;
2716
-
2717
-		$multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1;
2718
-
2719
-		// Define constants to find lines to sum
2720
-		$fieldtva='total_tva';
2721
-		$fieldlocaltax1='total_localtax1';
2722
-		$fieldlocaltax2='total_localtax2';
2723
-		$fieldup='subprice';
2724
-		if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier')
2725
-		{
2726
-			$fieldtva='tva';
2727
-			$fieldup='pu_ht';
2728
-		}
2729
-		if ($this->element == 'expensereport')
2730
-		{
2731
-			$fieldup='value_unit';
2732
-		}
2733
-
2734
-		$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,';
2735
-		$sql.= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type';
2736
-			if ($this->table_element_line == 'facturedet') $sql.= ', situation_percent';
2737
-			$sql.= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
2738
-		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2739
-		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2740
-		if ($exclspec)
2741
-		{
2742
-			$product_field='product_type';
2743
-			if ($this->table_element_line == 'contratdet') $product_field='';    // contratdet table has no product_type field
2744
-			if ($product_field) $sql.= ' AND '.$product_field.' <> 9';
2745
-		}
2746
-		$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
2747
-
2748
-		dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2749
-		$resql = $this->db->query($sql);
2750
-		if ($resql)
2751
-		{
2752
-			$this->total_ht  = 0;
2753
-			$this->total_tva = 0;
2754
-			$this->total_localtax1 = 0;
2755
-			$this->total_localtax2 = 0;
2756
-			$this->total_ttc = 0;
2757
-			$total_ht_by_vats  = array();
2758
-			$total_tva_by_vats = array();
2759
-			$total_ttc_by_vats = array();
2760
-			$this->multicurrency_total_ht	= 0;
2761
-			$this->multicurrency_total_tva	= 0;
2762
-			$this->multicurrency_total_ttc	= 0;
2763
-
2764
-			$num = $this->db->num_rows($resql);
2765
-			$i = 0;
2766
-			while ($i < $num)
2767
-			{
2768
-				$obj = $this->db->fetch_object($resql);
2769
-
2770
-				// Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none'
2771
-				$parameters=array('fk_element' => $obj->rowid);
2772
-				$reshook = $hookmanager->executeHooks('changeRoundingMode', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2773
-
2774
-				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'
2775
-				{
2776
-					$localtax_array=array($obj->localtax1_type,$obj->localtax1_tx,$obj->localtax2_type,$obj->localtax2_tx);
2777
-					$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);
2778
-					$diff=price2num($tmpcal[1] - $obj->total_tva, 'MT', 1);
2779
-					if ($diff)
2780
-					{
2781
-						$sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".$tmpcal[1].", total_ttc = ".$tmpcal[2]." WHERE rowid = ".$obj->rowid;
2782
-						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);
2783
-								$resqlfix=$this->db->query($sqlfix);
2784
-								if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2785
-								$obj->total_tva = $tmpcal[1];
2786
-								$obj->total_ttc = $tmpcal[2];
2787
-						//
2788
-					}
2789
-				}
919
+        global $user;
2790 920
 
2791
-				$this->total_ht        += $obj->total_ht;		// The field visible at end of line detail
2792
-				$this->total_tva       += $obj->total_tva;
2793
-				$this->total_localtax1 += $obj->total_localtax1;
2794
-				$this->total_localtax2 += $obj->total_localtax2;
2795
-				$this->total_ttc       += $obj->total_ttc;
2796
-				$this->multicurrency_total_ht        += $obj->multicurrency_total_ht;		// The field visible at end of line detail
2797
-				$this->multicurrency_total_tva       += $obj->multicurrency_total_tva;
2798
-				$this->multicurrency_total_ttc       += $obj->multicurrency_total_ttc;
2799
-
2800
-				if (! isset($total_ht_by_vats[$obj->vatrate]))  $total_ht_by_vats[$obj->vatrate]=0;
2801
-				if (! isset($total_tva_by_vats[$obj->vatrate])) $total_tva_by_vats[$obj->vatrate]=0;
2802
-				if (! isset($total_ttc_by_vats[$obj->vatrate])) $total_ttc_by_vats[$obj->vatrate]=0;
2803
-				$total_ht_by_vats[$obj->vatrate]  += $obj->total_ht;
2804
-				$total_tva_by_vats[$obj->vatrate] += $obj->total_tva;
2805
-				$total_ttc_by_vats[$obj->vatrate] += $obj->total_ttc;
2806
-
2807
-				if ($forcedroundingmode == '1')	// Check if we need adjustement onto line for vat. TODO This works on the company currency but not on multicurrency
2808
-				{
2809
-					$tmpvat=price2num($total_ht_by_vats[$obj->vatrate] * $obj->vatrate / 100, 'MT', 1);
2810
-					$diff=price2num($total_tva_by_vats[$obj->vatrate]-$tmpvat, 'MT', 1);
2811
-					//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";
2812
-					if ($diff)
2813
-					{
2814
-						if (abs($diff) > 0.1) { dol_syslog('A rounding difference was detected into TOTAL but is too high to be corrected', LOG_WARNING); exit; }
2815
-						$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;
2816
-						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);
2817
-								$resqlfix=$this->db->query($sqlfix);
2818
-								if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2819
-								$this->total_tva -= $diff;
2820
-								$this->total_ttc -= $diff;
2821
-								$total_tva_by_vats[$obj->vatrate] -= $diff;
2822
-								$total_ttc_by_vats[$obj->vatrate] -= $diff;
2823
-					}
2824
-				}
2825 921
 
2826
-				$i++;
2827
-			}
922
+        $this->db->begin();
2828 923
 
2829
-			// Add revenue stamp to total
2830
-			$this->total_ttc       			+= isset($this->revenuestamp)?$this->revenuestamp:0;
2831
-			$this->multicurrency_total_ttc  += isset($this->revenuestamp)?($this->revenuestamp * $multicurrency_tx):0;
924
+        $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
925
+        $sql.= " WHERE rowid =".$rowid;
2832 926
 
2833
-			// Situations totals
2834
-			if ($this->situation_cycle_ref && $this->situation_counter > 1 && method_exists($this, 'get_prev_sits') && $this->type != $this::TYPE_CREDIT_NOTE )
2835
-			{
2836
-				$prev_sits = $this->get_prev_sits();
2837
-
2838
-				foreach ($prev_sits as $sit) {				// $sit is an object Facture loaded with a fetch.
2839
-					$this->total_ht -= $sit->total_ht;
2840
-					$this->total_tva -= $sit->total_tva;
2841
-					$this->total_localtax1 -= $sit->total_localtax1;
2842
-					$this->total_localtax2 -= $sit->total_localtax2;
2843
-					$this->total_ttc -= $sit->total_ttc;
2844
-					$this->multicurrency_total_ht -= $sit->multicurrency_total_ht;
2845
-					$this->multicurrency_total_tva -= $sit->multicurrency_total_tva;
2846
-					$this->multicurrency_total_ttc -= $sit->multicurrency_total_ttc;
2847
-				}
2848
-			}
2849
-
2850
-			$this->db->free($resql);
2851
-
2852
-			// Now update global field total_ht, total_ttc and tva
2853
-			$fieldht='total_ht';
2854
-			$fieldtva='tva';
2855
-			$fieldlocaltax1='localtax1';
2856
-			$fieldlocaltax2='localtax2';
2857
-			$fieldttc='total_ttc';
2858
-			// Specific code for backward compatibility with old field names
2859
-			if ($this->element == 'facture' || $this->element == 'facturerec')             $fieldht='total';
2860
-			if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva='total_tva';
2861
-			if ($this->element == 'propal')                                                $fieldttc='total';
2862
-			if ($this->element == 'expensereport')                                         $fieldtva='total_tva';
2863
-			if ($this->element == 'supplier_proposal')                                     $fieldttc='total';
2864
-
2865
-			if (empty($nodatabaseupdate))
2866
-			{
2867
-				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET';
2868
-				$sql .= " ".$fieldht."='".price2num($this->total_ht)."',";
2869
-				$sql .= " ".$fieldtva."='".price2num($this->total_tva)."',";
2870
-				$sql .= " ".$fieldlocaltax1."='".price2num($this->total_localtax1)."',";
2871
-				$sql .= " ".$fieldlocaltax2."='".price2num($this->total_localtax2)."',";
2872
-				$sql .= " ".$fieldttc."='".price2num($this->total_ttc)."'";
2873
-						$sql .= ", multicurrency_total_ht='".price2num($this->multicurrency_total_ht, 'MT', 1)."'";
2874
-						$sql .= ", multicurrency_total_tva='".price2num($this->multicurrency_total_tva, 'MT', 1)."'";
2875
-						$sql .= ", multicurrency_total_ttc='".price2num($this->multicurrency_total_ttc, 'MT', 1)."'";
2876
-				$sql .= ' WHERE rowid = '.$this->id;
2877
-
2878
-
2879
-				dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2880
-				$resql=$this->db->query($sql);
2881
-				if (! $resql)
2882
-				{
2883
-					$error++;
2884
-					$this->error=$this->db->lasterror();
2885
-					$this->errors[]=$this->db->lasterror();
2886
-				}
2887
-			}
927
+        dol_syslog(get_class($this)."::delete_contact", LOG_DEBUG);
928
+        if ($this->db->query($sql))
929
+        {
930
+            if (! $notrigger)
931
+            {
932
+                $result=$this->call_trigger(strtoupper($this->element).'_DELETE_CONTACT', $user);
933
+                if ($result < 0) { $this->db->rollback(); return -1; }
934
+            }
2888 935
 
2889
-			if (! $error)
2890
-			{
2891
-				return 1;
2892
-			}
2893
-			else
2894
-			{
2895
-				return -1;
2896
-			}
2897
-		}
2898
-		else
2899
-		{
2900
-			dol_print_error($this->db,'Bad request in update_price');
2901
-			return -1;
2902
-		}
2903
-	}
936
+            $this->db->commit();
937
+            return 1;
938
+        }
939
+        else
940
+        {
941
+            $this->error=$this->db->lasterror();
942
+            $this->db->rollback();
943
+            return -1;
944
+        }
945
+    }
2904 946
 
2905 947
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2906
-	/**
2907
-	 *	Add objects linked in llx_element_element.
2908
-	 *
2909
-	 *	@param		string	$origin		Linked element type
2910
-	 *	@param		int		$origin_id	Linked element id
2911
-	 *	@return		int					<=0 if KO, >0 if OK
2912
-	 *	@see		fetchObjectLinked, updateObjectLinked, deleteObjectLinked
2913
-	 */
2914
-	function add_object_linked($origin=null, $origin_id=null)
2915
-	{
948
+    /**
949
+     *    Delete all links between an object $this and all its contacts
950
+     *
951
+     *	  @param	string	$source		'' or 'internal' or 'external'
952
+     *	  @param	string	$code		Type of contact (code or id)
953
+     *    @return   int					>0 if OK, <0 if KO
954
+     */
955
+    function delete_linked_contact($source='',$code='')
956
+    {
2916 957
         // phpcs:enable
2917
-		$origin = (! empty($origin) ? $origin : $this->origin);
2918
-		$origin_id = (! empty($origin_id) ? $origin_id : $this->origin_id);
2919
-
2920
-		// Special case
2921
-		if ($origin == 'order') $origin='commande';
2922
-		if ($origin == 'invoice') $origin='facture';
2923
-		if ($origin == 'invoice_template') $origin='facturerec';
2924
-    	if ($origin == 'supplierorder') $origin='order_supplier';
2925
-		$this->db->begin();
2926
-
2927
-		$sql = "INSERT INTO ".MAIN_DB_PREFIX."element_element (";
2928
-		$sql.= "fk_source";
2929
-		$sql.= ", sourcetype";
2930
-		$sql.= ", fk_target";
2931
-		$sql.= ", targettype";
2932
-		$sql.= ") VALUES (";
2933
-		$sql.= $origin_id;
2934
-		$sql.= ", '".$this->db->escape($origin)."'";
2935
-		$sql.= ", ".$this->id;
2936
-		$sql.= ", '".$this->db->escape($this->element)."'";
2937
-		$sql.= ")";
2938
-
2939
-		dol_syslog(get_class($this)."::add_object_linked", LOG_DEBUG);
2940
-		if ($this->db->query($sql))
2941
-	  	{
2942
-	  		$this->db->commit();
2943
-	  		return 1;
2944
-	  	}
2945
-	  	else
2946
-	  	{
2947
-	  		$this->error=$this->db->lasterror();
2948
-	  		$this->db->rollback();
2949
-	  		return 0;
2950
-	  	}
2951
-	}
2952
-
2953
-	/**
2954
-	 *	Fetch array of objects linked to current object (object of enabled modules only). Links are loaded into
2955
-	 *		this->linkedObjectsIds array and
2956
-	 *		this->linkedObjects array if $loadalsoobjects = 1
2957
-	 *  Possible usage for parameters:
2958
-	 *  - all parameters empty -> we look all link to current object (current object can be source or target)
2959
-	 *  - source id+type -> will get target list linked to source
2960
-	 *  - target id+type -> will get source list linked to target
2961
-	 *  - source id+type + target type -> will get target list of the type
2962
-	 *  - target id+type + target source -> will get source list of the type
2963
-	 *
2964
-	 *	@param	int		$sourceid			Object source id (if not defined, id of object)
2965
-	 *	@param  string	$sourcetype			Object source type (if not defined, element name of object)
2966
-	 *	@param  int		$targetid			Object target id (if not defined, id of object)
2967
-	 *	@param  string	$targettype			Object target type (if not defined, elemennt name of object)
2968
-	 *	@param  string	$clause				'OR' or 'AND' clause used when both source id and target id are provided
2969
-	 *  @param  int		$alsosametype		0=Return only links to object that differs from source type. 1=Include also link to objects of same type.
2970
-	 *  @param  string	$orderby			SQL 'ORDER BY' clause
2971
-	 *  @param	int		$loadalsoobjects	Load also array this->linkedObjects (Use 0 to increase performances)
2972
-	 *	@return int							<0 if KO, >0 if OK
2973
-	 *  @see	add_object_linked, updateObjectLinked, deleteObjectLinked
2974
-	 */
2975
-	function fetchObjectLinked($sourceid=null,$sourcetype='',$targetid=null,$targettype='',$clause='OR',$alsosametype=1,$orderby='sourcetype',$loadalsoobjects=1)
2976
-	{
2977
-		global $conf;
2978
-
2979
-		$this->linkedObjectsIds=array();
2980
-		$this->linkedObjects=array();
2981
-
2982
-		$justsource=false;
2983
-		$justtarget=false;
2984
-		$withtargettype=false;
2985
-		$withsourcetype=false;
2986
-
2987
-		if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid))
2988
-		{
2989
-			$justsource=true;  // the source (id and type) is a search criteria
2990
-			if (! empty($targettype)) $withtargettype=true;
2991
-		}
2992
-		if (! empty($targetid) && ! empty($targettype) && empty($sourceid))
2993
-		{
2994
-			$justtarget=true;  // the target (id and type) is a search criteria
2995
-			if (! empty($sourcetype)) $withsourcetype=true;
2996
-		}
2997
-
2998
-		$sourceid = (! empty($sourceid) ? $sourceid : $this->id);
2999
-		$targetid = (! empty($targetid) ? $targetid : $this->id);
3000
-		$sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
3001
-		$targettype = (! empty($targettype) ? $targettype : $this->element);
3002
-
3003
-		/*if (empty($sourceid) && empty($targetid))
3004
-		 {
3005
-		 dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR);
3006
-		 return -1;
3007
-		 }*/
958
+        $temp = array();
959
+        $typeContact = $this->liste_type_contact($source,'',0,0,$code);
3008 960
 
3009
-		// Links between objects are stored in table element_element
3010
-		$sql = 'SELECT rowid, fk_source, sourcetype, fk_target, targettype';
3011
-		$sql.= ' FROM '.MAIN_DB_PREFIX.'element_element';
3012
-		$sql.= " WHERE ";
3013
-		if ($justsource || $justtarget)
3014
-		{
3015
-			if ($justsource)
3016
-			{
3017
-				$sql.= "fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."'";
3018
-				if ($withtargettype) $sql.= " AND targettype = '".$targettype."'";
3019
-			}
3020
-			else if ($justtarget)
3021
-			{
3022
-				$sql.= "fk_target = ".$targetid." AND targettype = '".$targettype."'";
3023
-				if ($withsourcetype) $sql.= " AND sourcetype = '".$sourcetype."'";
3024
-			}
3025
-		}
3026
-		else
3027
-		{
3028
-			$sql.= "(fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."')";
3029
-			$sql.= " ".$clause." (fk_target = ".$targetid." AND targettype = '".$targettype."')";
3030
-		}
3031
-		$sql .= ' ORDER BY '.$orderby;
3032
-
3033
-		dol_syslog(get_class($this)."::fetchObjectLink", LOG_DEBUG);
3034
-		$resql = $this->db->query($sql);
3035
-		if ($resql)
3036
-		{
3037
-			$num = $this->db->num_rows($resql);
3038
-			$i = 0;
3039
-			while ($i < $num)
3040
-			{
3041
-				$obj = $this->db->fetch_object($resql);
3042
-				if ($justsource || $justtarget)
3043
-				{
3044
-					if ($justsource)
3045
-					{
3046
-						$this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
3047
-					}
3048
-					else if ($justtarget)
3049
-					{
3050
-						$this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
3051
-					}
3052
-				}
3053
-				else
3054
-				{
3055
-					if ($obj->fk_source == $sourceid && $obj->sourcetype == $sourcetype)
3056
-					{
3057
-						$this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
3058
-					}
3059
-					if ($obj->fk_target == $targetid && $obj->targettype == $targettype)
3060
-					{
3061
-						$this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
3062
-					}
3063
-				}
3064
-				$i++;
3065
-			}
961
+        foreach($typeContact as $key => $value)
962
+        {
963
+            array_push($temp,$key);
964
+        }
965
+        $listId = implode(",", $temp);
3066 966
 
3067
-			if (! empty($this->linkedObjectsIds))
3068
-			{
3069
-				$tmparray = $this->linkedObjectsIds;
3070
-				foreach($tmparray as $objecttype => $objectids)       // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...)
3071
-				{
3072
-					// Parse element/subelement (ex: project_task, cabinetmed_consultation, ...)
3073
-					$module = $element = $subelement = $objecttype;
3074
-					if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier'
3075
-						&& preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
3076
-					{
3077
-						$module = $element = $regs[1];
3078
-						$subelement = $regs[2];
3079
-					}
3080
-
3081
-					$classpath = $element.'/class';
3082
-					// To work with non standard classpath or module name
3083
-					if ($objecttype == 'facture')			{
3084
-						$classpath = 'compta/facture/class';
3085
-					}
3086
-					else if ($objecttype == 'facturerec')			{
3087
-						$classpath = 'compta/facture/class'; $module = 'facture';
3088
-					}
3089
-					else if ($objecttype == 'propal')			{
3090
-						$classpath = 'comm/propal/class';
3091
-					}
3092
-					else if ($objecttype == 'supplier_proposal')			{
3093
-						$classpath = 'supplier_proposal/class';
3094
-					}
3095
-					else if ($objecttype == 'shipping')			{
3096
-						$classpath = 'expedition/class'; $subelement = 'expedition'; $module = 'expedition_bon';
3097
-					}
3098
-					else if ($objecttype == 'delivery')			{
3099
-						$classpath = 'livraison/class'; $subelement = 'livraison'; $module = 'livraison_bon';
3100
-					}
3101
-					else if ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier')	{
3102
-						$classpath = 'fourn/class'; $module = 'fournisseur';
3103
-					}
3104
-					else if ($objecttype == 'fichinter')			{
3105
-						$classpath = 'fichinter/class'; $subelement = 'fichinter'; $module = 'ficheinter';
3106
-					}
3107
-					else if ($objecttype == 'subscription')			{
3108
-						$classpath = 'adherents/class'; $module = 'adherent';
3109
-					}
3110
-
3111
-					// Set classfile
3112
-					$classfile = strtolower($subelement); $classname = ucfirst($subelement);
3113
-
3114
-					if ($objecttype == 'order') {
3115
-						$classfile = 'commande'; $classname = 'Commande';
3116
-					}
3117
-					else if ($objecttype == 'invoice_supplier') {
3118
-						$classfile = 'fournisseur.facture'; $classname = 'FactureFournisseur';
3119
-					}
3120
-					else if ($objecttype == 'order_supplier')   {
3121
-						$classfile = 'fournisseur.commande'; $classname = 'CommandeFournisseur';
3122
-					}
3123
-					else if ($objecttype == 'supplier_proposal')   {
3124
-						$classfile = 'supplier_proposal'; $classname = 'SupplierProposal';
3125
-					}
3126
-					else if ($objecttype == 'facturerec')   {
3127
-						$classfile = 'facture-rec'; $classname = 'FactureRec';
3128
-					}
3129
-					else if ($objecttype == 'subscription')   {
3130
-						$classfile = 'subscription'; $classname = 'Subscription';
3131
-					}
3132
-
3133
-					// Here $module, $classfile and $classname are set
3134
-					if ($conf->$module->enabled && (($element != $this->element) || $alsosametype))
3135
-					{
3136
-						if ($loadalsoobjects)
3137
-						{
3138
-							dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
3139
-							//print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname);
3140
-							if (class_exists($classname))
3141
-							{
3142
-								foreach($objectids as $i => $objectid)	// $i is rowid into llx_element_element
3143
-								{
3144
-									$object = new $classname($this->db);
3145
-									$ret = $object->fetch($objectid);
3146
-									if ($ret >= 0)
3147
-									{
3148
-										$this->linkedObjects[$objecttype][$i] = $object;
3149
-									}
3150
-								}
3151
-							}
3152
-						}
3153
-					}
3154
-					else
3155
-					{
3156
-						unset($this->linkedObjectsIds[$objecttype]);
3157
-					}
3158
-				}
3159
-			}
3160
-			return 1;
3161
-		}
3162
-		else
3163
-		{
3164
-			dol_print_error($this->db);
3165
-			return -1;
3166
-		}
3167
-	}
3168
-
3169
-	/**
3170
-	 *	Update object linked of a current object
3171
-	 *
3172
-	 *	@param	int		$sourceid		Object source id
3173
-	 *	@param  string	$sourcetype		Object source type
3174
-	 *	@param  int		$targetid		Object target id
3175
-	 *	@param  string	$targettype		Object target type
3176
-	 *	@return							int	>0 if OK, <0 if KO
3177
-	 *	@see	add_object_linked, fetObjectLinked, deleteObjectLinked
3178
-	 */
3179
-	function updateObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='')
3180
-	{
3181
-		$updatesource=false;
3182
-		$updatetarget=false;
3183
-
3184
-		if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $updatesource=true;
3185
-		else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $updatetarget=true;
3186
-
3187
-		$sql = "UPDATE ".MAIN_DB_PREFIX."element_element SET ";
3188
-		if ($updatesource)
3189
-		{
3190
-			$sql.= "fk_source = ".$sourceid;
3191
-			$sql.= ", sourcetype = '".$this->db->escape($sourcetype)."'";
3192
-			$sql.= " WHERE fk_target = ".$this->id;
3193
-			$sql.= " AND targettype = '".$this->db->escape($this->element)."'";
3194
-		}
3195
-		else if ($updatetarget)
3196
-		{
3197
-			$sql.= "fk_target = ".$targetid;
3198
-			$sql.= ", targettype = '".$this->db->escape($targettype)."'";
3199
-			$sql.= " WHERE fk_source = ".$this->id;
3200
-			$sql.= " AND sourcetype = '".$this->db->escape($this->element)."'";
3201
-		}
3202
-
3203
-		dol_syslog(get_class($this)."::updateObjectLinked", LOG_DEBUG);
3204
-		if ($this->db->query($sql))
3205
-		{
3206
-			return 1;
3207
-		}
3208
-		else
3209
-		{
3210
-			$this->error=$this->db->lasterror();
3211
-			return -1;
3212
-		}
3213
-	}
3214
-
3215
-	/**
3216
-	 *	Delete all links between an object $this
3217
-	 *
3218
-	 *	@param	int		$sourceid		Object source id
3219
-	 *	@param  string	$sourcetype		Object source type
3220
-	 *	@param  int		$targetid		Object target id
3221
-	 *	@param  string	$targettype		Object target type
3222
-	 *  @param	int		$rowid			Row id of line to delete. If defined, other parameters are not used.
3223
-	 *	@return     					int	>0 if OK, <0 if KO
3224
-	 *	@see	add_object_linked, updateObjectLinked, fetchObjectLinked
3225
-	 */
3226
-	function deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
3227
-	{
3228
-		$deletesource=false;
3229
-		$deletetarget=false;
3230
-
3231
-		if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $deletesource=true;
3232
-		else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $deletetarget=true;
3233
-
3234
-		$sourceid = (! empty($sourceid) ? $sourceid : $this->id);
3235
-		$sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
3236
-		$targetid = (! empty($targetid) ? $targetid : $this->id);
3237
-		$targettype = (! empty($targettype) ? $targettype : $this->element);
3238
-
3239
-		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_element";
3240
-		$sql.= " WHERE";
3241
-		if ($rowid > 0)
3242
-		{
3243
-			$sql.=" rowid = ".$rowid;
3244
-		}
3245
-		else
3246
-		{
3247
-			if ($deletesource)
3248
-			{
3249
-				$sql.= " fk_source = ".$sourceid." AND sourcetype = '".$this->db->escape($sourcetype)."'";
3250
-				$sql.= " AND fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."'";
3251
-			}
3252
-			else if ($deletetarget)
3253
-			{
3254
-				$sql.= " fk_target = ".$targetid." AND targettype = '".$this->db->escape($targettype)."'";
3255
-				$sql.= " AND fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."'";
3256
-			}
3257
-			else
3258
-			{
3259
-				$sql.= " (fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."')";
3260
-				$sql.= " OR";
3261
-				$sql.= " (fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."')";
3262
-			}
3263
-		}
3264
-
3265
-		dol_syslog(get_class($this)."::deleteObjectLinked", LOG_DEBUG);
3266
-		if ($this->db->query($sql))
3267
-		{
3268
-			return 1;
3269
-		}
3270
-		else
3271
-		{
3272
-			$this->error=$this->db->lasterror();
3273
-			$this->errors[]=$this->error;
3274
-			return -1;
3275
-		}
3276
-	}
3277
-
3278
-	/**
3279
-	 *      Set status of an object
3280
-	 *
3281
-	 *      @param	int		$status			Status to set
3282
-	 *      @param	int		$elementId		Id of element to force (use this->id by default)
3283
-	 *      @param	string	$elementType	Type of element to force (use this->table_element by default)
3284
-	 *      @param	string	$trigkey		Trigger key to use for trigger
3285
-	 *      @return int						<0 if KO, >0 if OK
3286
-	 */
3287
-	function setStatut($status, $elementId=null, $elementType='', $trigkey='')
3288
-	{
3289
-		global $user,$langs,$conf;
3290
-
3291
-		$savElementId=$elementId;  // To be used later to know if we were using the method using the id of this or not.
3292
-
3293
-		$elementId = (!empty($elementId)?$elementId:$this->id);
3294
-		$elementTable = (!empty($elementType)?$elementType:$this->table_element);
3295
-
3296
-		$this->db->begin();
3297
-
3298
-		$fieldstatus="fk_statut";
3299
-		if ($elementTable == 'facture_rec') $fieldstatus="suspended";
3300
-		if ($elementTable == 'mailing') $fieldstatus="statut";
3301
-		if ($elementTable == 'cronjob') $fieldstatus="status";
3302
-		if ($elementTable == 'user') $fieldstatus="statut";
3303
-		if ($elementTable == 'expensereport') $fieldstatus="fk_statut";
3304
-		if ($elementTable == 'commande_fournisseur_dispatch') $fieldstatus="status";
3305
-
3306
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$elementTable;
3307
-		$sql.= " SET ".$fieldstatus." = ".$status;
3308
-		// If status = 1 = validated, update also fk_user_valid
3309
-		if ($status == 1 && $elementTable == 'expensereport') $sql.=", fk_user_valid = ".$user->id;
3310
-		$sql.= " WHERE rowid=".$elementId;
3311
-
3312
-		dol_syslog(get_class($this)."::setStatut", LOG_DEBUG);
3313
-		if ($this->db->query($sql))
3314
-		{
3315
-			$error = 0;
3316
-
3317
-			// Try autoset of trigkey
3318
-			if (empty($trigkey))
3319
-			{
3320
-				if ($this->element == 'supplier_proposal' && $status == 2) $trigkey='SUPPLIER_PROPOSAL_SIGN';   // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class
3321
-				if ($this->element == 'supplier_proposal' && $status == 3) $trigkey='SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class
3322
-				if ($this->element == 'supplier_proposal' && $status == 4) $trigkey='SUPPLIER_PROPOSAL_CLOSE';  // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class
3323
-				if ($this->element == 'fichinter' && $status == 3) $trigkey='FICHINTER_CLASSIFY_DONE';
3324
-				if ($this->element == 'fichinter' && $status == 2) $trigkey='FICHINTER_CLASSIFY_BILLED';
3325
-				if ($this->element == 'fichinter' && $status == 1) $trigkey='FICHINTER_CLASSIFY_UNBILLED';
3326
-			}
3327
-
3328
-			if ($trigkey)
3329
-			{
3330
-				// Appel des triggers
3331
-				include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
3332
-				$interface=new Interfaces($this->db);
3333
-				$result=$interface->run_triggers($trigkey,$this,$user,$langs,$conf);
3334
-				if ($result < 0) {
3335
-					$error++; $this->errors=$interface->errors;
3336
-				}
3337
-				// Fin appel triggers
3338
-			}
967
+        $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
968
+        $sql.= " WHERE element_id = ".$this->id;
969
+        if ($listId)
970
+            $sql.= " AND fk_c_type_contact IN (".$listId.")";
3339 971
 
3340
-			if (! $error)
3341
-			{
3342
-				$this->db->commit();
972
+        dol_syslog(get_class($this)."::delete_linked_contact", LOG_DEBUG);
973
+        if ($this->db->query($sql))
974
+        {
975
+            return 1;
976
+        }
977
+        else
978
+        {
979
+            $this->error=$this->db->lasterror();
980
+            return -1;
981
+        }
982
+    }
3343 983
 
3344
-				if (empty($savElementId))    // If the element we update was $this (so $elementId is null)
3345
-				{
3346
-					$this->statut = $status;
3347
-					$this->status = $status;
3348
-				}
984
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
985
+    /**
986
+     *    Get array of all contacts for an object
987
+     *
988
+     *    @param	int			$statut		Status of links to get (-1=all)
989
+     *    @param	string		$source		Source of contact: external or thirdparty (llx_socpeople) or internal (llx_user)
990
+     *    @param	int         $list       0:Return array contains all properties, 1:Return array contains just id
991
+     *    @param    string      $code       Filter on this code of contact type ('SHIPPING', 'BILLING', ...)
992
+     *    @return	array|int		        Array of contacts, -1 if error
993
+     */
994
+    function liste_contact($statut=-1,$source='external',$list=0,$code='')
995
+    {
996
+        // phpcs:enable
997
+        global $langs;
998
+
999
+        $tab=array();
1000
+
1001
+        $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
1002
+        if ($source == 'internal') $sql.=", '-1' as socid, t.statut as statuscontact, t.login, t.photo";
1003
+        if ($source == 'external' || $source == 'thirdparty') $sql.=", t.fk_soc as socid, t.statut as statuscontact";
1004
+        $sql.= ", t.civility as civility, t.lastname as lastname, t.firstname, t.email";
1005
+        $sql.= ", tc.source, tc.element, tc.code, tc.libelle";
1006
+        $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact tc";
1007
+        $sql.= ", ".MAIN_DB_PREFIX."element_contact ec";
1008
+        if ($source == 'internal') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid";
1009
+        if ($source == 'external'|| $source == 'thirdparty') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid";
1010
+        $sql.= " WHERE ec.element_id =".$this->id;
1011
+        $sql.= " AND ec.fk_c_type_contact=tc.rowid";
1012
+        $sql.= " AND tc.element='".$this->db->escape($this->element)."'";
1013
+        if ($code) $sql.= " AND tc.code = '".$this->db->escape($code)."'";
1014
+        if ($source == 'internal') $sql.= " AND tc.source = 'internal'";
1015
+        if ($source == 'external' || $source == 'thirdparty') $sql.= " AND tc.source = 'external'";
1016
+        $sql.= " AND tc.active=1";
1017
+        if ($statut >= 0) $sql.= " AND ec.statut = '".$statut."'";
1018
+        $sql.=" ORDER BY t.lastname ASC";
1019
+
1020
+        dol_syslog(get_class($this)."::liste_contact", LOG_DEBUG);
1021
+        $resql=$this->db->query($sql);
1022
+        if ($resql)
1023
+        {
1024
+            $num=$this->db->num_rows($resql);
1025
+            $i=0;
1026
+            while ($i < $num)
1027
+            {
1028
+                $obj = $this->db->fetch_object($resql);
1029
+
1030
+                if (! $list)
1031
+                {
1032
+                    $transkey="TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
1033
+                    $libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
1034
+                    $tab[$i]=array('source'=>$obj->source,'socid'=>$obj->socid,'id'=>$obj->id,
1035
+                                    'nom'=>$obj->lastname,      // For backward compatibility
1036
+                                    'civility'=>$obj->civility, 'lastname'=>$obj->lastname, 'firstname'=>$obj->firstname, 'email'=>$obj->email, 'login'=>$obj->login, 'photo'=>$obj->photo, 'statuscontact'=>$obj->statuscontact,
1037
+                                    'rowid'=>$obj->rowid, 'code'=>$obj->code, 'libelle'=>$libelle_type, 'status'=>$obj->statuslink, 'fk_c_type_contact'=>$obj->fk_c_type_contact);
1038
+                }
1039
+                else
1040
+                {
1041
+                    $tab[$i]=$obj->id;
1042
+                }
1043
+
1044
+                $i++;
1045
+            }
3349 1046
 
3350
-				return 1;
3351
-			}
3352
-			else
3353
-			{
3354
-				$this->db->rollback();
3355
-				dol_syslog(get_class($this)."::setStatus ".$this->error,LOG_ERR);
3356
-				return -1;
3357
-			}
3358
-		}
3359
-		else
3360
-		{
3361
-			$this->error=$this->db->lasterror();
3362
-			$this->db->rollback();
3363
-			return -1;
3364
-		}
3365
-	}
3366
-
3367
-
3368
-	/**
3369
-	 *  Load type of canvas of an object if it exists
3370
-	 *
3371
-	 *  @param      int		$id     Record id
3372
-	 *  @param      string	$ref    Record ref
3373
-	 *  @return		int				<0 if KO, 0 if nothing done, >0 if OK
3374
-	 */
3375
-	function getCanvas($id=0,$ref='')
3376
-	{
3377
-		global $conf;
3378
-
3379
-		if (empty($id) && empty($ref)) return 0;
3380
-		if (! empty($conf->global->MAIN_DISABLE_CANVAS)) return 0;    // To increase speed. Not enabled by default.
3381
-
3382
-		// Clean parameters
3383
-		$ref = trim($ref);
3384
-
3385
-		$sql = "SELECT rowid, canvas";
3386
-		$sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element;
3387
-		$sql.= " WHERE entity IN (".getEntity($this->element).")";
3388
-		if (! empty($id))  $sql.= " AND rowid = ".$id;
3389
-		if (! empty($ref)) $sql.= " AND ref = '".$this->db->escape($ref)."'";
3390
-
3391
-		$resql = $this->db->query($sql);
3392
-		if ($resql)
3393
-		{
3394
-			$obj = $this->db->fetch_object($resql);
3395
-			if ($obj)
3396
-			{
3397
-				$this->canvas   = $obj->canvas;
3398
-				return 1;
3399
-			}
3400
-			else return 0;
3401
-		}
3402
-		else
3403
-		{
3404
-			dol_print_error($this->db);
3405
-			return -1;
3406
-		}
3407
-	}
3408
-
3409
-
3410
-	/**
3411
-	 * 	Get special code of a line
3412
-	 *
3413
-	 * 	@param	int		$lineid		Id of line
3414
-	 * 	@return	int					Special code
3415
-	 */
3416
-	function getSpecialCode($lineid)
3417
-	{
3418
-		$sql = 'SELECT special_code FROM '.MAIN_DB_PREFIX.$this->table_element_line;
3419
-		$sql.= ' WHERE rowid = '.$lineid;
3420
-		$resql = $this->db->query($sql);
3421
-		if ($resql)
3422
-		{
3423
-			$row = $this->db->fetch_row($resql);
3424
-			return $row[0];
3425
-		}
3426
-	}
3427
-
3428
-	/**
3429
-	 *  Function to check if an object is used by others.
3430
-	 *  Check is done into this->childtables. There is no check into llx_element_element.
3431
-	 *
3432
-	 *  @param	int		$id			Force id of object
3433
-	 *  @return	int					<0 if KO, 0 if not used, >0 if already used
3434
-	 */
3435
-	function isObjectUsed($id=0)
3436
-	{
3437
-		global $langs;
3438
-
3439
-		if (empty($id)) $id=$this->id;
3440
-
3441
-		// Check parameters
3442
-		if (! isset($this->childtables) || ! is_array($this->childtables) || count($this->childtables) == 0)
3443
-		{
3444
-			dol_print_error('Called isObjectUsed on a class with property this->childtables not defined');
3445
-			return -1;
3446
-		}
3447
-
3448
-		$arraytoscan = $this->childtables;
3449
-		// For backward compatibility, we check if array is old format array('table1', 'table2', ...)
3450
-		$tmparray=array_keys($this->childtables);
3451
-		if (is_numeric($tmparray[0]))
3452
-		{
3453
-			$arraytoscan = array_flip($this->childtables);
3454
-		}
3455
-
3456
-		// Test if child exists
3457
-		$haschild=0;
3458
-		foreach($arraytoscan as $table => $elementname)
3459
-		{
3460
-			//print $id.'-'.$table.'-'.$elementname.'<br>';
3461
-			// Check if third party can be deleted
3462
-			$sql = "SELECT COUNT(*) as nb from ".MAIN_DB_PREFIX.$table;
3463
-			$sql.= " WHERE ".$this->fk_element." = ".$id;
3464
-			$resql=$this->db->query($sql);
3465
-			if ($resql)
3466
-			{
3467
-				$obj=$this->db->fetch_object($resql);
3468
-				if ($obj->nb > 0)
3469
-				{
3470
-					$langs->load("errors");
3471
-					//print 'Found into table '.$table.', type '.$langs->transnoentitiesnoconv($elementname).', haschild='.$haschild;
3472
-					$haschild += $obj->nb;
3473
-					if (is_numeric($elementname))	// old usage
3474
-					{
3475
-						$this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $table);
3476
-					}
3477
-					else	// new usage: $elementname=Translation key
3478
-					{
3479
-						$this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $langs->transnoentitiesnoconv($elementname));
3480
-					}
3481
-					break;    // We found at least one, we stop here
3482
-				}
3483
-			}
3484
-			else
3485
-			{
3486
-				$this->errors[]=$this->db->lasterror();
3487
-				return -1;
3488
-			}
3489
-		}
3490
-		if ($haschild > 0)
3491
-		{
3492
-			$this->errors[]="ErrorRecordHasChildren";
3493
-			return $haschild;
3494
-		}
3495
-		else return 0;
3496
-	}
3497
-
3498
-	/**
3499
-	 *  Function to say how many lines object contains
3500
-	 *
3501
-	 *	@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
3502
-	 *  @return	int						<0 if KO, 0 if no predefined products, nb of lines with predefined products if found
3503
-	 */
3504
-	function hasProductsOrServices($predefined=-1)
3505
-	{
3506
-		$nb=0;
3507
-
3508
-		foreach($this->lines as $key => $val)
3509
-		{
3510
-			$qualified=0;
3511
-			if ($predefined == -1) $qualified=1;
3512
-			if ($predefined == 1 && $val->fk_product > 0) $qualified=1;
3513
-			if ($predefined == 0 && $val->fk_product <= 0) $qualified=1;
3514
-			if ($predefined == 2 && $val->fk_product > 0 && $val->product_type==0) $qualified=1;
3515
-			if ($predefined == 3 && $val->fk_product > 0 && $val->product_type==1) $qualified=1;
3516
-			if ($qualified) $nb++;
3517
-		}
3518
-		dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies');
3519
-		return $nb;
3520
-	}
3521
-
3522
-	/**
3523
-	 * Function that returns the total amount HT of discounts applied for all lines.
3524
-	 *
3525
-	 * @return 	float
3526
-	 */
3527
-	function getTotalDiscount()
3528
-	{
3529
-		$total_discount=0.00;
3530
-
3531
-		$sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht";
3532
-		$sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element."det";
3533
-		$sql.= " WHERE ".$this->fk_element." = ".$this->id;
3534
-
3535
-		dol_syslog(get_class($this).'::getTotalDiscount', LOG_DEBUG);
3536
-		$resql = $this->db->query($sql);
3537
-		if ($resql)
3538
-		{
3539
-			$num=$this->db->num_rows($resql);
3540
-			$i=0;
3541
-			while ($i < $num)
3542
-			{
3543
-				$obj = $this->db->fetch_object($resql);
3544
-
3545
-				$pu_ht = $obj->pu_ht;
3546
-				$qty= $obj->qty;
3547
-				$total_ht = $obj->total_ht;
3548
-
3549
-				$total_discount_line = floatval(price2num(($pu_ht * $qty) - $total_ht, 'MT'));
3550
-				$total_discount += $total_discount_line;
3551
-
3552
-				$i++;
3553
-			}
3554
-		}
3555
-
3556
-		//print $total_discount; exit;
3557
-		return price2num($total_discount);
3558
-	}
3559
-
3560
-
3561
-	/**
3562
-	 * Return into unit=0, the calculated total of weight and volume of all lines * qty
3563
-	 * Calculate by adding weight and volume of each product line, so properties ->volume/volume_units/weight/weight_units must be loaded on line.
3564
-	 *
3565
-	 * @return  array                           array('weight'=>...,'volume'=>...)
3566
-	 */
3567
-	function getTotalWeightVolume()
3568
-	{
3569
-		$totalWeight = 0;
3570
-		$totalVolume = 0;
3571
-		// defined for shipment only
3572
-		$totalOrdered = '';
3573
-		// defined for shipment only
3574
-		$totalToShip = '';
3575
-
3576
-		foreach ($this->lines as $line)
3577
-		{
3578
-			if (isset($line->qty_asked))
3579
-			{
3580
-				if (empty($totalOrdered)) $totalOrdered=0;  // Avoid warning because $totalOrdered is ''
3581
-				$totalOrdered+=$line->qty_asked;    // defined for shipment only
3582
-			}
3583
-			if (isset($line->qty_shipped))
3584
-			{
3585
-				if (empty($totalToShip)) $totalToShip=0;    // Avoid warning because $totalToShip is ''
3586
-				$totalToShip+=$line->qty_shipped;   // defined for shipment only
3587
-            }else if ($line->element == 'commandefournisseurdispatch' && isset($line->qty))
1047
+            return $tab;
1048
+        }
1049
+        else
1050
+        {
1051
+            $this->error=$this->db->lasterror();
1052
+            dol_print_error($this->db);
1053
+            return -1;
1054
+        }
1055
+    }
1056
+
1057
+
1058
+    /**
1059
+     * 		Update status of a contact linked to object
1060
+     *
1061
+     * 		@param	int		$rowid		Id of link between object and contact
1062
+     * 		@return	int					<0 if KO, >=0 if OK
1063
+     */
1064
+    function swapContactStatus($rowid)
1065
+    {
1066
+        $sql = "SELECT ec.datecreate, ec.statut, ec.fk_socpeople, ec.fk_c_type_contact,";
1067
+        $sql.= " tc.code, tc.libelle";
1068
+        //$sql.= ", s.fk_soc";
1069
+        $sql.= " FROM (".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as tc)";
1070
+        //$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
1071
+        $sql.= " WHERE ec.rowid =".$rowid;
1072
+        $sql.= " AND ec.fk_c_type_contact=tc.rowid";
1073
+        $sql.= " AND tc.element = '".$this->db->escape($this->element)."'";
1074
+
1075
+        dol_syslog(get_class($this)."::swapContactStatus", LOG_DEBUG);
1076
+        $resql=$this->db->query($sql);
1077
+        if ($resql)
1078
+        {
1079
+            $obj = $this->db->fetch_object($resql);
1080
+            $newstatut = ($obj->statut == 4) ? 5 : 4;
1081
+            $result = $this->update_contact($rowid, $newstatut);
1082
+            $this->db->free($resql);
1083
+            return $result;
1084
+        }
1085
+        else
1086
+        {
1087
+            $this->error=$this->db->error();
1088
+            dol_print_error($this->db);
1089
+            return -1;
1090
+        }
1091
+    }
1092
+
1093
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1094
+    /**
1095
+     *      Return array with list of possible values for type of contacts
1096
+     *
1097
+     *      @param	string	$source     'internal', 'external' or 'all'
1098
+     *      @param	string	$order		Sort order by : 'position', 'code', 'rowid'...
1099
+     *      @param  int		$option     0=Return array id->label, 1=Return array code->label
1100
+     *      @param  int		$activeonly 0=all status of contact, 1=only the active
1101
+     *		@param	string	$code		Type of contact (Example: 'CUSTOMER', 'SERVICE')
1102
+     *      @return array       		Array list of type of contacts (id->label if option=0, code->label if option=1)
1103
+     */
1104
+    function liste_type_contact($source='internal', $order='position', $option=0, $activeonly=0, $code='')
1105
+    {
1106
+        // phpcs:enable
1107
+        global $langs;
1108
+
1109
+        if (empty($order)) $order='position';
1110
+        if ($order == 'position') $order.=',code';
1111
+
1112
+        $tab = array();
1113
+        $sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position";
1114
+        $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
1115
+        $sql.= " WHERE tc.element='".$this->db->escape($this->element)."'";
1116
+        if ($activeonly == 1) $sql.= " AND tc.active=1"; // only the active types
1117
+        if (! empty($source) && $source != 'all') $sql.= " AND tc.source='".$this->db->escape($source)."'";
1118
+        if (! empty($code)) $sql.= " AND tc.code='".$this->db->escape($code)."'";
1119
+        $sql.= $this->db->order($order,'ASC');
1120
+
1121
+        //print "sql=".$sql;
1122
+        $resql=$this->db->query($sql);
1123
+        if ($resql)
1124
+        {
1125
+            $num=$this->db->num_rows($resql);
1126
+            $i=0;
1127
+            while ($i < $num)
3588 1128
             {
3589
-                if (empty($totalToShip)) $totalToShip=0;
3590
-                $totalToShip+=$line->qty;   // defined for reception only
3591
-			}
3592
-
3593
-			// Define qty, weight, volume, weight_units, volume_units
3594
-			if ($this->element == 'shipping') {
3595
-				// for shipments
3596
-				$qty = $line->qty_shipped ? $line->qty_shipped : 0;
3597
-			}
3598
-			else {
3599
-				$qty = $line->qty ? $line->qty : 0;
3600
-			}
3601
-
3602
-			$weight = $line->weight ? $line->weight : 0;
3603
-            ($weight==0 && !empty($line->product->weight))? $weight=$line->product->weight: 0;
3604
-			$volume = $line->volume ? $line->volume : 0;
3605
-			($volume==0 && !empty($line->product->volume))? $volume=$line->product->volume: 0;
1129
+                $obj = $this->db->fetch_object($resql);
3606 1130
 
3607
-			$weight_units=$line->weight_units;
3608
-			($weight_units==0 && !empty($line->product->weight_units))? $weight_units=$line->product->weight_units: 0;
3609
-			$volume_units=$line->volume_units;
3610
-			($volume_units==0 && !empty($line->product->volume_units))? $volume_units=$line->product->volume_units: 0;
1131
+                $transkey="TypeContact_".$this->element."_".$source."_".$obj->code;
1132
+                $libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
1133
+                if (empty($option)) $tab[$obj->rowid]=$libelle_type;
1134
+                else $tab[$obj->code]=$libelle_type;
1135
+                $i++;
1136
+            }
1137
+            return $tab;
1138
+        }
1139
+        else
1140
+        {
1141
+            $this->error=$this->db->lasterror();
1142
+            //dol_print_error($this->db);
1143
+            return null;
1144
+        }
1145
+    }
3611 1146
 
3612
-			$weightUnit=0;
3613
-			$volumeUnit=0;
3614
-			if (! empty($weight_units)) $weightUnit = $weight_units;
3615
-			if (! empty($volume_units)) $volumeUnit = $volume_units;
1147
+    /**
1148
+     *      Return id of contacts for a source and a contact code.
1149
+     *      Example: contact client de facturation ('external', 'BILLING')
1150
+     *      Example: contact client de livraison ('external', 'SHIPPING')
1151
+     *      Example: contact interne suivi paiement ('internal', 'SALESREPFOLL')
1152
+     *
1153
+     *		@param	string	$source		'external' or 'internal'
1154
+     *		@param	string	$code		'BILLING', 'SHIPPING', 'SALESREPFOLL', ...
1155
+     *		@param	int		$status		limited to a certain status
1156
+     *      @return array       		List of id for such contacts
1157
+     */
1158
+    function getIdContact($source,$code,$status=0)
1159
+    {
1160
+        global $conf;
3616 1161
 
3617
-			if (empty($totalWeight)) $totalWeight=0;  // Avoid warning because $totalWeight is ''
3618
-			if (empty($totalVolume)) $totalVolume=0;  // Avoid warning because $totalVolume is ''
1162
+        $result=array();
1163
+        $i=0;
1164
+        //cas particulier pour les expeditions
1165
+        if($this->element=='shipping' && $this->origin_id != 0) {
1166
+            $id=$this->origin_id;
1167
+            $element='commande';
1168
+        } else if($this->element=='reception' && $this->origin_id != 0) {
1169
+            $id=$this->origin_id;
1170
+            $element='order_supplier';
1171
+        } else {
1172
+            $id=$this->id;
1173
+            $element=$this->element;
1174
+        }
3619 1175
 
3620
-			//var_dump($line->volume_units);
3621
-			if ($weight_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3622
-			{
3623
-				$trueWeightUnit=pow(10, $weightUnit);
3624
-				$totalWeight += $weight * $qty * $trueWeightUnit;
3625
-			}
3626
-			else {
3627
-		if ($weight_units == 99) {
3628
-			// conversion 1 Pound = 0.45359237 KG
3629
-			$trueWeightUnit = 0.45359237;
3630
-			$totalWeight += $weight * $qty * $trueWeightUnit;
3631
-		} elseif ($weight_units == 98) {
3632
-			// conversion 1 Ounce = 0.0283495 KG
3633
-			$trueWeightUnit = 0.0283495;
3634
-			$totalWeight += $weight * $qty * $trueWeightUnit;
3635
-		}
3636
-		else
3637
-					$totalWeight += $weight * $qty;   // This may be wrong if we mix different units
3638
-			}
3639
-			if ($volume_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3640
-			{
3641
-				//print $line->volume."x".$line->volume_units."x".($line->volume_units < 50)."x".$volumeUnit;
3642
-				$trueVolumeUnit=pow(10, $volumeUnit);
3643
-				//print $line->volume;
3644
-				$totalVolume += $volume * $qty * $trueVolumeUnit;
3645
-			}
3646
-			else
3647
-			{
3648
-				$totalVolume += $volume * $qty;   // This may be wrong if we mix different units
3649
-			}
3650
-		}
3651
-
3652
-		return array('weight'=>$totalWeight, 'volume'=>$totalVolume, 'ordered'=>$totalOrdered, 'toship'=>$totalToShip);
3653
-	}
3654
-
3655
-
3656
-	/**
3657
-	 *	Set extra parameters
3658
-	 *
3659
-	 *	@return	int      <0 if KO, >0 if OK
3660
-	 */
3661
-	function setExtraParameters()
3662
-	{
3663
-		$this->db->begin();
3664
-
3665
-		$extraparams = (! empty($this->extraparams) ? json_encode($this->extraparams) : null);
3666
-
3667
-		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3668
-		$sql.= " SET extraparams = ".(! empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null");
3669
-		$sql.= " WHERE rowid = ".$this->id;
3670
-
3671
-		dol_syslog(get_class($this)."::setExtraParameters", LOG_DEBUG);
3672
-		$resql = $this->db->query($sql);
3673
-		if (! $resql)
3674
-		{
3675
-			$this->error=$this->db->lasterror();
3676
-			$this->db->rollback();
3677
-			return -1;
3678
-		}
3679
-		else
3680
-		{
3681
-			$this->db->commit();
3682
-			return 1;
3683
-		}
3684
-	}
1176
+        $sql = "SELECT ec.fk_socpeople";
1177
+        $sql.= " FROM ".MAIN_DB_PREFIX."element_contact as ec,";
1178
+        if ($source == 'internal') $sql.= " ".MAIN_DB_PREFIX."user as c,";
1179
+        if ($source == 'external') $sql.= " ".MAIN_DB_PREFIX."socpeople as c,";
1180
+        $sql.= " ".MAIN_DB_PREFIX."c_type_contact as tc";
1181
+        $sql.= " WHERE ec.element_id = ".$id;
1182
+        $sql.= " AND ec.fk_socpeople = c.rowid";
1183
+        if ($source == 'internal') $sql.= " AND c.entity IN (".getEntity('user').")";
1184
+        if ($source == 'external') $sql.= " AND c.entity IN (".getEntity('societe').")";
1185
+        $sql.= " AND ec.fk_c_type_contact = tc.rowid";
1186
+        $sql.= " AND tc.element = '".$element."'";
1187
+        $sql.= " AND tc.source = '".$source."'";
1188
+        $sql.= " AND tc.code = '".$code."'";
1189
+        $sql.= " AND tc.active = 1";
1190
+        if ($status) $sql.= " AND ec.statut = ".$status;
1191
+
1192
+        dol_syslog(get_class($this)."::getIdContact", LOG_DEBUG);
1193
+        $resql=$this->db->query($sql);
1194
+        if ($resql)
1195
+        {
1196
+            while ($obj = $this->db->fetch_object($resql))
1197
+            {
1198
+                $result[$i]=$obj->fk_socpeople;
1199
+                $i++;
1200
+            }
1201
+        }
1202
+        else
1203
+        {
1204
+            $this->error=$this->db->error();
1205
+            return null;
1206
+        }
3685 1207
 
1208
+        return $result;
1209
+    }
3686 1210
 
3687 1211
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3688
-	/**
3689
-	 *    Return incoterms informations
3690
-	 *    TODO Use a cache for label get
3691
-	 *
3692
-	 *    @return	string	incoterms info
3693
-	 */
3694
-	function display_incoterms()
3695
-	{
1212
+    /**
1213
+     *		Load object contact with id=$this->contactid into $this->contact
1214
+     *
1215
+     *		@param	int		$contactid      Id du contact. Use this->contactid if empty.
1216
+     *		@return	int						<0 if KO, >0 if OK
1217
+     */
1218
+    function fetch_contact($contactid=null)
1219
+    {
3696 1220
         // phpcs:enable
3697
-		$out = '';
3698
-		$this->libelle_incoterms = '';
3699
-		if (!empty($this->fk_incoterms))
3700
-		{
3701
-			$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3702
-			$result = $this->db->query($sql);
3703
-			if ($result)
3704
-			{
3705
-				$res = $this->db->fetch_object($result);
3706
-				$out .= $res->code;
3707
-			}
3708
-		}
3709
-
3710
-		$out .= (($res->code && $this->location_incoterms)?' - ':'').$this->location_incoterms;
3711
-
3712
-		return $out;
3713
-	}
3714
-
3715
-	/**
3716
-	 *    Return incoterms informations for pdf display
3717
-	 *
3718
-	 *    @return	string		incoterms info
3719
-	 */
3720
-	function getIncotermsForPDF()
3721
-	{
3722
-		$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3723
-		$resql = $this->db->query($sql);
3724
-		if ($resql)
3725
-		{
3726
-			$num = $this->db->num_rows($resql);
3727
-			if ($num > 0)
3728
-			{
3729
-				$res = $this->db->fetch_object($resql);
3730
-				return 'Incoterm : '.$res->code.' - '.$this->location_incoterms;
3731
-			}
3732
-			else
3733
-			{
3734
-				return '';
3735
-			}
3736
-		}
3737
-		else
3738
-		{
3739
-			$this->errors[] = $this->db->lasterror();
3740
-			return false;
3741
-		}
3742
-	}
3743
-
3744
-	/**
3745
-	 *    Define incoterms values of current object
3746
-	 *
3747
-	 *    @param	int		$id_incoterm     Id of incoterm to set or '' to remove
3748
-	 * 	  @param 	string  $location		 location of incoterm
3749
-	 *    @return	int     		<0 if KO, >0 if OK
3750
-	 */
3751
-	function setIncoterms($id_incoterm, $location)
3752
-	{
3753
-		if ($this->id && $this->table_element)
3754
-		{
3755
-			$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3756
-			$sql.= " SET fk_incoterms = ".($id_incoterm > 0 ? $id_incoterm : "null");
3757
-			$sql.= ", location_incoterms = ".($id_incoterm > 0 ? "'".$this->db->escape($location)."'" : "null");
3758
-			$sql.= " WHERE rowid = " . $this->id;
3759
-			dol_syslog(get_class($this).'::setIncoterms', LOG_DEBUG);
3760
-			$resql=$this->db->query($sql);
3761
-			if ($resql)
3762
-			{
3763
-				$this->fk_incoterms = $id_incoterm;
3764
-				$this->location_incoterms = $location;
1221
+        if (empty($contactid)) $contactid=$this->contactid;
3765 1222
 
3766
-				$sql = 'SELECT libelle FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3767
-				$res = $this->db->query($sql);
3768
-				if ($res)
3769
-				{
3770
-					$obj = $this->db->fetch_object($res);
3771
-					$this->libelle_incoterms = $obj->libelle;
3772
-				}
3773
-				return 1;
3774
-			}
3775
-			else
3776
-			{
3777
-				$this->errors[] = $this->db->lasterror();
3778
-				return -1;
3779
-			}
3780
-		}
3781
-		else return -1;
3782
-	}
3783
-
3784
-
3785
-	// --------------------
3786
-	// TODO: All functions here must be redesigned and moved as they are not business functions but output functions
3787
-	// --------------------
3788
-
3789
-	/* This is to show add lines */
3790
-
3791
-	/**
3792
-	 *	Show add free and predefined products/services form
3793
-	 *
3794
-	 *  @param	int		        $dateSelector       1=Show also date range input fields
3795
-	 *  @param	Societe			$seller				Object thirdparty who sell
3796
-	 *  @param	Societe			$buyer				Object thirdparty who buy
3797
-	 *	@return	void
3798
-	 */
3799
-	function formAddObjectLine($dateSelector, $seller, $buyer)
3800
-	{
3801
-		global $conf,$user,$langs,$object,$hookmanager;
3802
-		global $form,$bcnd,$var;
3803
-
3804
-		// Line extrafield
3805
-		require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3806
-		$extrafieldsline = new ExtraFields($this->db);
3807
-		$extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3808
-
3809
-		// Output template part (modules that overwrite templates must declare this into descriptor)
3810
-		// Use global variables + $dateSelector + $seller and $buyer
3811
-		$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
3812
-		foreach($dirtpls as $reldir)
3813
-		{
3814
-			$tpl = dol_buildpath($reldir.'/objectline_create.tpl.php');
3815
-			if (empty($conf->file->strict_mode)) {
3816
-				$res=@include $tpl;
3817
-			} else {
3818
-				$res=include $tpl; // for debug
3819
-			}
3820
-			if ($res) break;
3821
-		}
3822
-	}
3823
-
3824
-
3825
-
3826
-	/* This is to show array of line of details */
3827
-
3828
-
3829
-	/**
3830
-	 *	Return HTML table for object lines
3831
-	 *	TODO Move this into an output class file (htmlline.class.php)
3832
-	 *	If lines are into a template, title must also be into a template
3833
-	 *	But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
3834
-	 *
3835
-	 *	@param	string		$action				Action code
3836
-	 *	@param  string		$seller            	Object of seller third party
3837
-	 *	@param  string  	$buyer             	Object of buyer third party
3838
-	 *	@param	int			$selected		   	Object line selected
3839
-	 *	@param  int	    	$dateSelector      	1=Show also date range input fields
3840
-	 *	@return	void
3841
-	 */
3842
-	function printObjectLines($action, $seller, $buyer, $selected=0, $dateSelector=0)
3843
-	{
3844
-		global $conf, $hookmanager, $langs, $user;
3845
-		// TODO We should not use global var for this !
3846
-		global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax;
3847
-
3848
-		// Define usemargins
3849
-		$usemargins=0;
3850
-		if (! empty($conf->margin->enabled) && ! empty($this->element) && in_array($this->element,array('facture','propal','commande'))) $usemargins=1;
3851
-
3852
-		$num = count($this->lines);
3853
-
3854
-		// Line extrafield
3855
-		require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3856
-		$extrafieldsline = new ExtraFields($this->db);
3857
-		$extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3858
-
3859
-		$parameters = array('num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3860
-		$reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3861
-		if (empty($reshook))
3862
-		{
3863
-			// Title line
3864
-		    print "<thead>\n";
3865
-
3866
-			print '<tr class="liste_titre nodrag nodrop">';
3867
-
3868
-			// Adds a line numbering column
3869
-			if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) print '<td class="linecolnum" align="center" width="5">&nbsp;</td>';
3870
-
3871
-			// Description
3872
-			print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
3873
-
3874
-			if ($this->element == 'supplier_proposal' || $this->element == 'order_supplier' || $this->element == 'invoice_supplier')
3875
-			{
3876
-				print '<td class="linerefsupplier"><span id="title_fourn_ref">'.$langs->trans("SupplierRef").'</span></td>';
3877
-			}
1223
+        if (empty($contactid)) return 0;
3878 1224
 
3879
-			// VAT
3880
-			print '<td class="linecolvat" align="right" width="80">'.$langs->trans('VAT').'</td>';
1225
+        require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1226
+        $contact = new Contact($this->db);
1227
+        $result=$contact->fetch($contactid);
1228
+        $this->contact = $contact;
1229
+        return $result;
1230
+    }
3881 1231
 
3882
-			// Price HT
3883
-			print '<td class="linecoluht" align="right" width="80">'.$langs->trans('PriceUHT').'</td>';
1232
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1233
+    /**
1234
+     *    	Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty
1235
+     *
1236
+     *		@param		int		$force_thirdparty_id	Force thirdparty id
1237
+     *		@return		int								<0 if KO, >0 if OK
1238
+     */
1239
+    function fetch_thirdparty($force_thirdparty_id=0)
1240
+    {
1241
+        // phpcs:enable
1242
+        global $conf;
3884 1243
 
3885
-			// Multicurrency
3886
-			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>';
1244
+        if (empty($this->socid) && empty($this->fk_soc) && empty($this->fk_thirdparty) && empty($force_thirdparty_id))
1245
+            return 0;
3887 1246
 
3888
-			if ($inputalsopricewithtax) print '<td align="right" width="80">'.$langs->trans('PriceUTTC').'</td>';
1247
+        require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3889 1248
 
3890
-			// Qty
3891
-			print '<td class="linecolqty" align="right">'.$langs->trans('Qty').'</td>';
1249
+        $idtofetch = isset($this->socid) ? $this->socid : (isset($this->fk_soc) ? $this->fk_soc : $this->fk_thirdparty);
1250
+        if ($force_thirdparty_id)
1251
+            $idtofetch = $force_thirdparty_id;
3892 1252
 
3893
-			if($conf->global->PRODUCT_USE_UNITS)
3894
-			{
3895
-				print '<td class="linecoluseunit" align="left">'.$langs->trans('Unit').'</td>';
3896
-			}
1253
+        if ($idtofetch) {
1254
+            $thirdparty = new Societe($this->db);
1255
+            $result = $thirdparty->fetch($idtofetch);
1256
+            $this->thirdparty = $thirdparty;
3897 1257
 
3898
-			// Reduction short
3899
-			print '<td class="linecoldiscount" align="right">'.$langs->trans('ReductionShort').'</td>';
1258
+            // Use first price level if level not defined for third party
1259
+            if (!empty($conf->global->PRODUIT_MULTIPRICES) && empty($this->thirdparty->price_level)) {
1260
+                $this->thirdparty->price_level = 1;
1261
+            }
3900 1262
 
3901
-			if ($this->situation_cycle_ref) {
3902
-				print '<td class="linecolcycleref" align="right">' . $langs->trans('Progress') . '</td>';
3903
-			}
1263
+            return $result;
1264
+        } else
1265
+            return -1;
1266
+    }
3904 1267
 
3905
-			if ($usemargins && ! empty($conf->margin->enabled) && empty($user->societe_id))
3906
-			{
3907
-				if (!empty($user->rights->margins->creer))
3908
-				{
3909
-					if ($conf->global->MARGIN_TYPE == "1")
3910
-						print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('BuyingPrice').'</td>';
3911
-					else
3912
-						print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('CostPrice').'</td>';
3913
-				}
3914 1268
 
3915
-				if (! empty($conf->global->DISPLAY_MARGIN_RATES) && $user->rights->margins->liretous)
3916
-					print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarginRate').'</td>';
3917
-				if (! empty($conf->global->DISPLAY_MARK_RATES) && $user->rights->margins->liretous)
3918
-					print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarkRate').'</td>';
3919
-			}
1269
+    /**
1270
+     * Looks for an object with ref matching the wildcard provided
1271
+     * It does only work when $this->table_ref_field is set
1272
+     *
1273
+     * @param string $ref Wildcard
1274
+     * @return int >1 = OK, 0 = Not found or table_ref_field not defined, <0 = KO
1275
+     */
1276
+    public function fetchOneLike($ref)
1277
+    {
1278
+        if (!$this->table_ref_field) {
1279
+            return 0;
1280
+        }
3920 1281
 
3921
-			// Total HT
3922
-			print '<td class="linecolht" align="right">'.$langs->trans('TotalHTShort').'</td>';
1282
+        $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE '.$this->table_ref_field.' LIKE "'.$this->db->escape($ref).'" LIMIT 1';
3923 1283
 
3924
-			// Multicurrency
3925
-			if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) print '<td class="linecoltotalht_currency" align="right">'.$langs->trans('TotalHTShortCurrency', $this->multicurrency_code).'</td>';
1284
+        $query = $this->db->query($sql);
3926 1285
 
3927
-			if ($outputalsopricetotalwithtax) print '<td align="right" width="80">'.$langs->trans('TotalTTCShort').'</td>';
1286
+        if (!$this->db->num_rows($query)) {
1287
+            return 0;
1288
+        }
3928 1289
 
3929
-			print '<td class="linecoledit"></td>';  // No width to allow autodim
1290
+        $result = $this->db->fetch_object($query);
3930 1291
 
3931
-			print '<td class="linecoldelete" width="10"></td>';
1292
+        return $this->fetch($result->rowid);
1293
+    }
3932 1294
 
3933
-			print '<td class="linecolmove" width="10"></td>';
1295
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1296
+    /**
1297
+     *	Load data for barcode into properties ->barcode_type*
1298
+     *	Properties ->barcode_type that is id of barcode. Type is used to find other properties, but
1299
+     *  if it is not defined, ->element must be defined to know default barcode type.
1300
+     *
1301
+     *	@return		int			<0 if KO, 0 if can't guess type of barcode (ISBN, EAN13...), >0 if OK (all barcode properties loaded)
1302
+     */
1303
+    function fetch_barcode()
1304
+    {
1305
+        // phpcs:enable
1306
+        global $conf;
3934 1307
 
3935
-			if($action == 'selectlines')
3936
-			{
3937
-			    print '<td class="linecolcheckall" align="center">';
3938
-			    print '<input type="checkbox" class="linecheckboxtoggle" />';
3939
-			    print '<script type="text/javascript">$(document).ready(function() {$(".linecheckboxtoggle").click(function() {var checkBoxes = $(".linecheckbox");checkBoxes.prop("checked", this.checked);})});</script>';
3940
-			    print '</td>';
3941
-			}
3942
-
3943
-			print "</tr>\n";
3944
-			print "</thead>\n";
3945
-		}
3946
-
3947
-		$var = true;
3948
-		$i	 = 0;
3949
-
3950
-		print "<tbody>\n";
3951
-		foreach ($this->lines as $line)
3952
-		{
3953
-			//Line extrafield
3954
-			$line->fetch_optionals();
3955
-
3956
-			//if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
3957
-			if (is_object($hookmanager))   // Old code is commented on preceding line.
3958
-			{
3959
-				if (empty($line->fk_parent_line))
3960
-				{
3961
-					$parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3962
-					$reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3963
-				}
3964
-				else
3965
-				{
3966
-					$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);
3967
-					$reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3968
-				}
3969
-			}
3970
-			if (empty($reshook))
3971
-			{
3972
-				$this->printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected,$extrafieldsline);
3973
-			}
3974
-
3975
-			$i++;
3976
-		}
3977
-		print "</tbody>\n";
3978
-	}
3979
-
3980
-	/**
3981
-	 *	Return HTML content of a detail line
3982
-	 *	TODO Move this into an output class file (htmlline.class.php)
3983
-	 *
3984
-	 *	@param	string		$action				GET/POST action
3985
-	 *	@param CommonObjectLine $line		       	Selected object line to output
3986
-	 *	@param  string	    $var               	Is it a an odd line (true)
3987
-	 *	@param  int		    $num               	Number of line (0)
3988
-	 *	@param  int		    $i					I
3989
-	 *	@param  int		    $dateSelector      	1=Show also date range input fields
3990
-	 *	@param  string	    $seller            	Object of seller third party
3991
-	 *	@param  string	    $buyer             	Object of buyer third party
3992
-	 *	@param	int			$selected		   	Object line selected
3993
-	 *  @param  int			$extrafieldsline	Object of extrafield line attribute
3994
-	 *	@return	void
3995
-	 */
3996
-	function printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected=0,$extrafieldsline=0)
3997
-	{
3998
-		global $conf,$langs,$user,$object,$hookmanager;
3999
-		global $form,$bc,$bcdd;
4000
-		global $object_rights, $disableedit, $disablemove, $disableremove;   // TODO We should not use global var for this !
4001
-
4002
-		$object_rights = $this->getRights();
4003
-
4004
-		$element=$this->element;
4005
-
4006
-		$text=''; $description=''; $type=0;
4007
-
4008
-		// Show product and description
4009
-		$type=(! empty($line->product_type)?$line->product_type:$line->fk_product_type);
4010
-		// Try to enhance type detection using date_start and date_end for free lines where type was not saved.
4011
-		if (! empty($line->date_start)) $type=1; // deprecated
4012
-		if (! empty($line->date_end)) $type=1; // deprecated
4013
-
4014
-		// Ligne en mode visu
4015
-		if ($action != 'editline' || $selected != $line->id)
4016
-		{
4017
-			// Product
4018
-			if ($line->fk_product > 0)
4019
-			{
4020
-				$product_static = new Product($this->db);
4021
-				$product_static->fetch($line->fk_product);
1308
+        dol_syslog(get_class($this).'::fetch_barcode this->element='.$this->element.' this->barcode_type='.$this->barcode_type);
4022 1309
 
4023
-				$product_static->ref = $line->ref; //can change ref in hook
4024
-				$product_static->label = $line->label; //can change label in hook
4025
-				$text=$product_static->getNomUrl(1);
1310
+        $idtype=$this->barcode_type;
1311
+        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
1312
+        {
1313
+            if ($this->element == 'product')      $idtype = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
1314
+            else if ($this->element == 'societe') $idtype = $conf->global->GENBARCODE_BARCODETYPE_THIRDPARTY;
1315
+            else dol_syslog('Call fetch_barcode with barcode_type not defined and cant be guessed', LOG_WARNING);
1316
+        }
4026 1317
 
4027
-				// Define output language and label
4028
-				if (! empty($conf->global->MAIN_MULTILANGS))
4029
-				{
4030
-					if (! is_object($this->thirdparty))
4031
-					{
4032
-						dol_print_error('','Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before');
4033
-						return;
4034
-					}
4035
-
4036
-					$prod = new Product($this->db);
4037
-					$prod->fetch($line->fk_product);
4038
-
4039
-					$outputlangs = $langs;
4040
-					$newlang='';
4041
-					if (empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09');
4042
-					if (! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && empty($newlang)) $newlang=$this->thirdparty->default_lang;		// For language to language of customer
4043
-					if (! empty($newlang))
4044
-					{
4045
-						$outputlangs = new Translate("",$conf);
4046
-						$outputlangs->setDefaultLang($newlang);
4047
-					}
4048
-
4049
-					$label = (! empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $line->product_label;
4050
-				}
4051
-				else
4052
-				{
4053
-					$label = $line->product_label;
4054
-				}
1318
+        if ($idtype > 0)
1319
+        {
1320
+            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
1321
+            {
1322
+                $sql = "SELECT rowid, code, libelle as label, coder";
1323
+                $sql.= " FROM ".MAIN_DB_PREFIX."c_barcode_type";
1324
+                $sql.= " WHERE rowid = ".$idtype;
1325
+                dol_syslog(get_class($this).'::fetch_barcode', LOG_DEBUG);
1326
+                $resql = $this->db->query($sql);
1327
+                if ($resql)
1328
+                {
1329
+                    $obj = $this->db->fetch_object($resql);
1330
+                    $this->barcode_type       = $obj->rowid;
1331
+                    $this->barcode_type_code  = $obj->code;
1332
+                    $this->barcode_type_label = $obj->label;
1333
+                    $this->barcode_type_coder = $obj->coder;
1334
+                    return 1;
1335
+                }
1336
+                else
1337
+                {
1338
+                    dol_print_error($this->db);
1339
+                    return -1;
1340
+                }
1341
+            }
1342
+        }
1343
+        return 0;
1344
+    }
4055 1345
 
4056
-				$text.= ' - '.(! empty($line->label)?$line->label:$label);
4057
-				$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.
4058
-			}
1346
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1347
+    /**
1348
+     *		Load the project with id $this->fk_project into this->project
1349
+     *
1350
+     *		@return		int			<0 if KO, >=0 if OK
1351
+     */
1352
+    function fetch_projet()
1353
+    {
1354
+        // phpcs:enable
1355
+        include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
4059 1356
 
4060
-			$line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
1357
+        if (empty($this->fk_project) && ! empty($this->fk_projet)) $this->fk_project = $this->fk_projet;	// For backward compatibility
1358
+        if (empty($this->fk_project)) return 0;
4061 1359
 
4062
-			// Output template part (modules that overwrite templates must declare this into descriptor)
4063
-			// Use global variables + $dateSelector + $seller and $buyer
4064
-			$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4065
-			foreach($dirtpls as $reldir)
4066
-			{
4067
-				$tpl = dol_buildpath($reldir.'/objectline_view.tpl.php');
4068
-				if (empty($conf->file->strict_mode)) {
4069
-					$res=@include $tpl;
4070
-				} else {
4071
-					$res=include $tpl; // for debug
4072
-				}
4073
-				if ($res) break;
4074
-			}
4075
-		}
4076
-
4077
-		// Ligne en mode update
4078
-		if ($this->statut == 0 && $action == 'editline' && $selected == $line->id)
4079
-		{
4080
-			$label = (! empty($line->label) ? $line->label : (($line->fk_product > 0) ? $line->product_label : ''));
4081
-			$placeholder=' placeholder="'.$langs->trans("Label").'"';
4082
-
4083
-			$line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
4084
-
4085
-			// Output template part (modules that overwrite templates must declare this into descriptor)
4086
-			// Use global variables + $dateSelector + $seller and $buyer
4087
-			$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4088
-			foreach($dirtpls as $reldir)
4089
-			{
4090
-				$tpl = dol_buildpath($reldir.'/objectline_edit.tpl.php');
4091
-				if (empty($conf->file->strict_mode)) {
4092
-					$res=@include $tpl;
4093
-				} else {
4094
-					$res=include $tpl; // for debug
4095
-				}
4096
-				if ($res) break;
4097
-			}
4098
-		}
4099
-	}
4100
-
4101
-
4102
-	/* This is to show array of line of details of source object */
4103
-
4104
-
4105
-	/**
4106
-	 * 	Return HTML table table of source object lines
4107
-	 *  TODO Move this and previous function into output html class file (htmlline.class.php).
4108
-	 *  If lines are into a template, title must also be into a template
4109
-	 *  But for the moment we don't know if it's possible, so we keep the method available on overloaded objects.
4110
-	 *
4111
-	 *	@param	string		$restrictlist		''=All lines, 'services'=Restrict to services only
4112
-	 *  @return	void
4113
-	 */
4114
-	function printOriginLinesList($restrictlist='')
4115
-	{
4116
-		global $langs, $hookmanager, $conf;
4117
-
4118
-		print '<tr class="liste_titre">';
4119
-		print '<td>'.$langs->trans('Ref').'</td>';
4120
-		print '<td>'.$langs->trans('Description').'</td>';
4121
-		print '<td align="right">'.$langs->trans('VATRate').'</td>';
4122
-		print '<td align="right">'.$langs->trans('PriceUHT').'</td>';
4123
-		if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$langs->trans('PriceUHTCurrency').'</td>';
4124
-		print '<td align="right">'.$langs->trans('Qty').'</td>';
4125
-		if($conf->global->PRODUCT_USE_UNITS)
4126
-		{
4127
-			print '<td align="left">'.$langs->trans('Unit').'</td>';
4128
-		}
4129
-		print '<td align="right">'.$langs->trans('ReductionShort').'</td></tr>';
4130
-
4131
-		$var = true;
4132
-		$i	 = 0;
4133
-
4134
-		if (! empty($this->lines))
4135
-		{
4136
-			foreach ($this->lines as $line)
4137
-			{
4138
-				if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
4139
-				{
4140
-					if (empty($line->fk_parent_line))
4141
-					{
4142
-						$parameters=array('line'=>$line,'var'=>$var,'i'=>$i);
4143
-						$action='';
4144
-						$hookmanager->executeHooks('printOriginObjectLine',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
4145
-					}
4146
-				}
4147
-				else
4148
-				{
4149
-					$this->printOriginLine($line, $var, $restrictlist);
4150
-				}
1360
+        $project = new Project($this->db);
1361
+        $result = $project->fetch($this->fk_project);
4151 1362
 
4152
-				$i++;
4153
-			}
4154
-		}
4155
-	}
4156
-
4157
-	/**
4158
-	 * 	Return HTML with a line of table array of source object lines
4159
-	 *  TODO Move this and previous function into output html class file (htmlline.class.php).
4160
-	 *  If lines are into a template, title must also be into a template
4161
-	 *  But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
4162
-	 *
4163
-	 * 	@param	CommonObjectLine	$line				Line
4164
-	 * 	@param	string				$var				Var
4165
-	 *	@param	string				$restrictlist		''=All lines, 'services'=Restrict to services only (strike line if not)
4166
-	 * 	@return	void
4167
-	 */
4168
-	function printOriginLine($line, $var, $restrictlist='')
4169
-	{
4170
-		global $langs, $conf;
4171
-
4172
-		//var_dump($line);
4173
-		if (!empty($line->date_start))
4174
-		{
4175
-			$date_start=$line->date_start;
4176
-		}
4177
-		else
4178
-		{
4179
-			$date_start=$line->date_debut_prevue;
4180
-			if ($line->date_debut_reel) $date_start=$line->date_debut_reel;
4181
-		}
4182
-		if (!empty($line->date_end))
4183
-		{
4184
-			$date_end=$line->date_end;
4185
-		}
4186
-		else
4187
-		{
4188
-			$date_end=$line->date_fin_prevue;
4189
-			if ($line->date_fin_reel) $date_end=$line->date_fin_reel;
4190
-		}
4191
-
4192
-		$this->tpl['label'] = '';
4193
-		if (! empty($line->fk_parent_line)) $this->tpl['label'].= img_picto('', 'rightarrow');
4194
-
4195
-		if (($line->info_bits & 2) == 2)  // TODO Not sure this is used for source object
4196
-		{
4197
-			$discount=new DiscountAbsolute($this->db);
4198
-			$discount->fk_soc = $this->socid;
4199
-			$this->tpl['label'].= $discount->getNomUrl(0,'discount');
4200
-		}
4201
-		else if (! empty($line->fk_product))
4202
-		{
4203
-			$productstatic = new Product($this->db);
4204
-			$productstatic->id = $line->fk_product;
4205
-			$productstatic->ref = $line->ref;
4206
-			$productstatic->type = $line->fk_product_type;
4207
-            if(empty($productstatic->ref)){
4208
-				$line->fetch_product();
4209
-				$productstatic = $line->product;
4210
-			}
4211
-			
4212
-			$this->tpl['label'].= $productstatic->getNomUrl(1);
4213
-			$this->tpl['label'].= ' - '.(! empty($line->label)?$line->label:$line->product_label);
4214
-			// Dates
4215
-			if ($line->product_type == 1 && ($date_start || $date_end))
4216
-			{
4217
-				$this->tpl['label'].= get_date_range($date_start,$date_end);
4218
-			}
4219
-		}
4220
-		else
4221
-		{
4222
-			$this->tpl['label'].= ($line->product_type == -1 ? '&nbsp;' : ($line->product_type == 1 ? img_object($langs->trans(''),'service') : img_object($langs->trans(''),'product')));
4223
-			if (!empty($line->desc)) {
4224
-				$this->tpl['label'].=$line->desc;
4225
-			}else {
4226
-				$this->tpl['label'].= ($line->label ? '&nbsp;'.$line->label : '');
4227
-			}
4228
-			
4229
-			// Dates
4230
-			if ($line->product_type == 1 && ($date_start || $date_end))
4231
-			{
4232
-				$this->tpl['label'].= get_date_range($date_start,$date_end);
4233
-			}
4234
-		}
1363
+        $this->projet = $project;	// deprecated
1364
+        $this->project = $project;
1365
+        return $result;
1366
+    }
4235 1367
 
4236
-		if (! empty($line->desc))
4237
-		{
4238
-			if ($line->desc == '(CREDIT_NOTE)')  // TODO Not sure this is used for source object
4239
-			{
4240
-				$discount=new DiscountAbsolute($this->db);
4241
-				$discount->fetch($line->fk_remise_except);
4242
-				$this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote",$discount->getNomUrl(0));
4243
-			}
4244
-			elseif ($line->desc == '(DEPOSIT)')  // TODO Not sure this is used for source object
4245
-			{
4246
-				$discount=new DiscountAbsolute($this->db);
4247
-				$discount->fetch($line->fk_remise_except);
4248
-				$this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit",$discount->getNomUrl(0));
4249
-			}
4250
-			elseif ($line->desc == '(EXCESS RECEIVED)')
4251
-			{
4252
-				$discount=new DiscountAbsolute($this->db);
4253
-				$discount->fetch($line->fk_remise_except);
4254
-				$this->tpl['description'] = $langs->transnoentities("DiscountFromExcessReceived",$discount->getNomUrl(0));
4255
-			}
4256
-			elseif ($line->desc == '(EXCESS PAID)')
4257
-			{
4258
-				$discount=new DiscountAbsolute($this->db);
4259
-				$discount->fetch($line->fk_remise_except);
4260
-				$this->tpl['description'] = $langs->transnoentities("DiscountFromExcessPaid",$discount->getNomUrl(0));
4261
-			}
4262
-			else
4263
-			{
4264
-				$this->tpl['description'] = dol_trunc($line->desc,60);
4265
-			}
4266
-		}
4267
-		else
4268
-		{
4269
-			$this->tpl['description'] = '&nbsp;';
4270
-		}
1368
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1369
+    /**
1370
+     *		Load the product with id $this->fk_product into this->product
1371
+     *
1372
+     *		@return		int			<0 if KO, >=0 if OK
1373
+     */
1374
+    function fetch_product()
1375
+    {
1376
+        // phpcs:enable
1377
+        include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
4271 1378
 
4272
-        // VAT Rate
4273
-        $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
4274
-        $this->tpl['vat_rate'] .= (($line->info_bits & 1) == 1) ? '*' : '';
4275
-        if (! empty($line->vat_src_code) && ! preg_match('/\(/', $this->tpl['vat_rate'])) $this->tpl['vat_rate'].=' ('.$line->vat_src_code.')';
1379
+        if (empty($this->fk_product)) return 0;
4276 1380
 
4277
-		$this->tpl['price'] = price($line->subprice);
4278
-		$this->tpl['multicurrency_price'] = price($line->multicurrency_subprice);
4279
-		$this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : '&nbsp;';
4280
-		if ($conf->global->PRODUCT_USE_UNITS) $this->tpl['unit'] = $langs->transnoentities($line->getLabelOfUnit('long'));
4281
-		$this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : '&nbsp;';
4282
-
4283
-		// Is the line strike or not
4284
-		$this->tpl['strike']=0;
4285
-		if ($restrictlist == 'services' && $line->product_type != Product::TYPE_SERVICE) $this->tpl['strike']=1;
4286
-
4287
-		// Output template part (modules that overwrite templates must declare this into descriptor)
4288
-		// Use global variables + $dateSelector + $seller and $buyer
4289
-		$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4290
-		foreach($dirtpls as $reldir)
4291
-		{
4292
-			$tpl = dol_buildpath($reldir.'/originproductline.tpl.php');
4293
-			if (empty($conf->file->strict_mode)) {
4294
-				$res=@include $tpl;
4295
-			} else {
4296
-				$res=include $tpl; // for debug
4297
-			}
4298
-			if ($res) break;
4299
-		}
4300
-	}
1381
+        $product = new Product($this->db);
1382
+        $result = $product->fetch($this->fk_product);
4301 1383
 
1384
+        $this->product = $product;
1385
+        return $result;
1386
+    }
4302 1387
 
4303 1388
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4304
-	/**
4305
-	 *	Add resources to the current object : add entry into llx_element_resources
4306
-	 *	Need $this->element & $this->id
4307
-	 *
4308
-	 *	@param		int		$resource_id		Resource id
4309
-	 *	@param		string	$resource_type		'resource'
4310
-	 *	@param		int		$busy				Busy or not
4311
-	 *	@param		int		$mandatory			Mandatory or not
4312
-	 *	@return		int							<=0 if KO, >0 if OK
4313
-	 */
4314
-	function add_element_resource($resource_id, $resource_type, $busy=0, $mandatory=0)
4315
-	{
1389
+    /**
1390
+     *		Load the user with id $userid into this->user
1391
+     *
1392
+     *		@param	int		$userid 		Id du contact
1393
+     *		@return	int						<0 if KO, >0 if OK
1394
+     */
1395
+    function fetch_user($userid)
1396
+    {
4316 1397
         // phpcs:enable
4317
-		$this->db->begin();
4318
-
4319
-		$sql = "INSERT INTO ".MAIN_DB_PREFIX."element_resources (";
4320
-		$sql.= "resource_id";
4321
-		$sql.= ", resource_type";
4322
-		$sql.= ", element_id";
4323
-		$sql.= ", element_type";
4324
-		$sql.= ", busy";
4325
-		$sql.= ", mandatory";
4326
-		$sql.= ") VALUES (";
4327
-		$sql.= $resource_id;
4328
-		$sql.= ", '".$this->db->escape($resource_type)."'";
4329
-		$sql.= ", '".$this->db->escape($this->id)."'";
4330
-		$sql.= ", '".$this->db->escape($this->element)."'";
4331
-		$sql.= ", '".$this->db->escape($busy)."'";
4332
-		$sql.= ", '".$this->db->escape($mandatory)."'";
4333
-		$sql.= ")";
4334
-
4335
-		dol_syslog(get_class($this)."::add_element_resource", LOG_DEBUG);
4336
-		if ($this->db->query($sql))
4337
-		{
4338
-			$this->db->commit();
4339
-			return 1;
4340
-		}
4341
-		else
4342
-		{
4343
-			$this->error=$this->db->lasterror();
4344
-			$this->db->rollback();
4345
-			return  0;
4346
-		}
4347
-	}
1398
+        $user = new User($this->db);
1399
+        $result=$user->fetch($userid);
1400
+        $this->user = $user;
1401
+        return $result;
1402
+    }
4348 1403
 
4349 1404
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4350
-	/**
4351
-	 *    Delete a link to resource line
4352
-	 *
4353
-	 *    @param	int		$rowid			Id of resource line to delete
4354
-	 *    @param	int		$element		element name (for trigger) TODO: use $this->element into commonobject class
4355
-	 *    @param	int		$notrigger		Disable all triggers
4356
-	 *    @return   int						>0 if OK, <0 if KO
4357
-	 */
4358
-	function delete_resource($rowid, $element, $notrigger=0)
4359
-	{
1405
+    /**
1406
+     *	Read linked origin object
1407
+     *
1408
+     *	@return		void
1409
+     */
1410
+    function fetch_origin()
1411
+    {
4360 1412
         // phpcs:enable
4361
-		global $user;
1413
+        if ($this->origin == 'shipping') $this->origin = 'expedition';
1414
+        if ($this->origin == 'delivery') $this->origin = 'livraison';
1415
+        if ($this->origin == 'order_supplier') $this->origin = 'commandeFournisseur';
4362 1416
 
4363
-		$this->db->begin();
1417
+        $origin = $this->origin;
4364 1418
 
4365
-		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_resources";
4366
-		$sql.= " WHERE rowid=".$rowid;
1419
+        $classname = ucfirst($origin);
1420
+        $this->$origin = new $classname($this->db);
1421
+        $this->$origin->fetch($this->origin_id);
1422
+    }
4367 1423
 
4368
-		dol_syslog(get_class($this)."::delete_resource", LOG_DEBUG);
1424
+    /**
1425
+     *  Load object from specific field
1426
+     *
1427
+     *  @param	string	$table		Table element or element line
1428
+     *  @param	string	$field		Field selected
1429
+     *  @param	string	$key		Import key
1430
+     *  @param	string	$element	Element name
1431
+     *	@return	int					<0 if KO, >0 if OK
1432
+     */
1433
+    function fetchObjectFrom($table, $field, $key, $element = null)
1434
+    {
1435
+        global $conf;
4369 1436
 
4370
-		$resql=$this->db->query($sql);
4371
-		if (! $resql)
4372
-		{
4373
-			$this->error=$this->db->lasterror();
4374
-			$this->db->rollback();
4375
-			return -1;
4376
-		}
4377
-		else
4378
-		{
4379
-			if (! $notrigger)
4380
-			{
4381
-				$result=$this->call_trigger(strtoupper($element).'_DELETE_RESOURCE', $user);
4382
-				if ($result < 0) { $this->db->rollback(); return -1; }
4383
-			}
4384
-			$this->db->commit();
4385
-			return 1;
4386
-		}
4387
-	}
4388
-
4389
-
4390
-	/**
4391
-	 * Overwrite magic function to solve problem of cloning object that are kept as references
4392
-	 *
4393
-	 * @return void
4394
-	 */
4395
-	function __clone()
4396
-	{
4397
-		// Force a copy of this->lines, otherwise it will point to same object.
4398
-		if (isset($this->lines) && is_array($this->lines))
4399
-		{
4400
-			$nboflines=count($this->lines);
4401
-			for($i=0; $i < $nboflines; $i++)
4402
-			{
4403
-				$this->lines[$i] = clone $this->lines[$i];
4404
-			}
4405
-		}
4406
-	}
4407
-
4408
-	/**
4409
-	 * Common function for all objects extending CommonObject for generating documents
4410
-	 *
4411
-	 * @param 	string 		$modelspath 	Relative folder where generators are placed
4412
-	 * @param 	string 		$modele 		Generator to use. Caller must set it to obj->modelpdf or GETPOST('modelpdf') for example.
4413
-	 * @param 	Translate 	$outputlangs 	Output language to use
4414
-	 * @param 	int 		$hidedetails 	1 to hide details. 0 by default
4415
-	 * @param 	int 		$hidedesc 		1 to hide product description. 0 by default
4416
-	 * @param 	int 		$hideref 		1 to hide product reference. 0 by default
4417
-	 * @param   null|array  $moreparams     Array to provide more information
4418
-	 * @return 	int 						>0 if OK, <0 if KO
4419
-	 * @see	addFileIntoDatabaseIndex
4420
-	 */
4421
-	protected function commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
4422
-	{
4423
-		global $conf, $langs, $user;
4424
-
4425
-		$srctemplatepath='';
4426
-
4427
-		// Increase limit for PDF build
4428
-		$err=error_reporting();
4429
-		error_reporting(0);
4430
-		@set_time_limit(120);
4431
-		error_reporting($err);
4432
-
4433
-		// If selected model is a filename template (then $modele="modelname" or "modelname:filename")
4434
-		$tmp=explode(':',$modele,2);
4435
-		if (! empty($tmp[1]))
4436
-		{
4437
-			$modele=$tmp[0];
4438
-			$srctemplatepath=$tmp[1];
4439
-		}
4440
-
4441
-		// Search template files
4442
-		$file=''; $classname=''; $filefound=0;
4443
-		$dirmodels=array('/');
4444
-		if (is_array($conf->modules_parts['models'])) $dirmodels=array_merge($dirmodels,$conf->modules_parts['models']);
4445
-		foreach($dirmodels as $reldir)
4446
-		{
4447
-			foreach(array('doc','pdf') as $prefix)
4448
-			{
4449
-				if (in_array(get_class($this), array('Adherent'))) $file = $prefix."_".$modele.".class.php";     // Member module use prefix_module.class.php
4450
-				else $file = $prefix."_".$modele.".modules.php";
1437
+        $result=false;
4451 1438
 
4452
-				// On verifie l'emplacement du modele
4453
-				$file=dol_buildpath($reldir.$modelspath.$file,0);
4454
-				if (file_exists($file))
4455
-				{
4456
-					$filefound=1;
4457
-					$classname=$prefix.'_'.$modele;
4458
-					break;
4459
-				}
4460
-			}
4461
-			if ($filefound) break;
4462
-		}
1439
+        $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$table;
1440
+        $sql.= " WHERE ".$field." = '".$key."'";
1441
+        if (! empty($element)) {
1442
+            $sql.= " AND entity IN (".getEntity($element).")";
1443
+        } else {
1444
+            $sql.= " AND entity = ".$conf->entity;
1445
+        }
4463 1446
 
4464
-		// If generator was found
4465
-		if ($filefound)
4466
-		{
4467
-			global $db;  // Required to solve a conception default in commonstickergenerator.class.php making an include of code using $db
1447
+        dol_syslog(get_class($this).'::fetchObjectFrom', LOG_DEBUG);
1448
+        $resql = $this->db->query($sql);
1449
+        if ($resql)
1450
+        {
1451
+            $row = $this->db->fetch_row($resql);
1452
+            // Test for avoid error -1
1453
+            if ($row[0] > 0) {
1454
+                $result = $this->fetch($row[0]);
1455
+            }
1456
+        }
4468 1457
 
4469
-			require_once $file;
1458
+        return $result;
1459
+    }
4470 1460
 
4471
-			$obj = new $classname($this->db);
1461
+    /**
1462
+     *	Getter generic. Load value from a specific field
1463
+     *
1464
+     *	@param	string	$table		Table of element or element line
1465
+     *	@param	int		$id			Element id
1466
+     *	@param	string	$field		Field selected
1467
+     *	@return	int					<0 if KO, >0 if OK
1468
+     */
1469
+    function getValueFrom($table, $id, $field)
1470
+    {
1471
+        $result=false;
1472
+        if (!empty($id) && !empty($field) && !empty($table)) {
1473
+            $sql = "SELECT ".$field." FROM ".MAIN_DB_PREFIX.$table;
1474
+            $sql.= " WHERE rowid = ".$id;
1475
+
1476
+            dol_syslog(get_class($this).'::getValueFrom', LOG_DEBUG);
1477
+            $resql = $this->db->query($sql);
1478
+            if ($resql)
1479
+            {
1480
+                $row = $this->db->fetch_row($resql);
1481
+                $result = $row[0];
1482
+            }
1483
+        }
1484
+        return $result;
1485
+    }
4472 1486
 
4473
-			// If generator is ODT, we must have srctemplatepath defined, if not we set it.
4474
-			if ($obj->type == 'odt' && empty($srctemplatepath))
4475
-			{
4476
-				$varfortemplatedir=$obj->scandir;
4477
-				if ($varfortemplatedir && ! empty($conf->global->$varfortemplatedir))
4478
-				{
4479
-					$dirtoscan=$conf->global->$varfortemplatedir;
4480
-
4481
-					$listoffiles=array();
4482
-
4483
-					// Now we add first model found in directories scanned
4484
-					$listofdir=explode(',',$dirtoscan);
4485
-					foreach($listofdir as $key => $tmpdir)
4486
-					{
4487
-						$tmpdir=trim($tmpdir);
4488
-						$tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir);
4489
-						if (! $tmpdir) { unset($listofdir[$key]); continue; }
4490
-						if (is_dir($tmpdir))
4491
-						{
4492
-							$tmpfiles=dol_dir_list($tmpdir,'files',0,'\.od(s|t)$','','name',SORT_ASC,0);
4493
-							if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles);
4494
-						}
4495
-					}
4496
-
4497
-					if (count($listoffiles))
4498
-					{
4499
-						foreach($listoffiles as $record)
4500
-						{
4501
-							$srctemplatepath=$record['fullname'];
4502
-							break;
4503
-						}
4504
-					}
4505
-				}
1487
+    /**
1488
+     *	Setter generic. Update a specific field into database.
1489
+     *  Warning: Trigger is run only if param trigkey is provided.
1490
+     *
1491
+     *	@param	string		$field			Field to update
1492
+     *	@param	mixed		$value			New value
1493
+     *	@param	string		$table			To force other table element or element line (should not be used)
1494
+     *	@param	int			$id				To force other object id (should not be used)
1495
+     *	@param	string		$format			Data format ('text', 'date'). 'text' is used if not defined
1496
+     *	@param	string		$id_field		To force rowid field name. 'rowid' is used if not defined
1497
+     *	@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'
1498
+     *  @param  string      $trigkey    	Trigger key to run (in most cases something like 'XXX_MODIFY')
1499
+     *  @param	string		$fk_user_field	Name of field to save user id making change
1500
+     *	@return	int							<0 if KO, >0 if OK
1501
+     *  @see updateExtraField
1502
+     */
1503
+    function setValueFrom($field, $value, $table='', $id=null, $format='', $id_field='', $fuser=null, $trigkey='', $fk_user_field='fk_user_modif')
1504
+    {
1505
+        global $user,$langs,$conf;
4506 1506
 
4507
-				if (empty($srctemplatepath))
4508
-				{
4509
-					$this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotDefined';
4510
-					return -1;
4511
-				}
4512
-			}
4513
-
4514
-			if ($obj->type == 'odt' && ! empty($srctemplatepath))
4515
-			{
4516
-				if (! dol_is_file($srctemplatepath))
4517
-				{
4518
-					$this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotFound';
4519
-					return -1;
4520
-				}
4521
-			}
4522
-
4523
-			// We save charset_output to restore it because write_file can change it if needed for
4524
-			// output format that does not support UTF8.
4525
-			$sav_charset_output=$outputlangs->charset_output;
1507
+        if (empty($table)) 	  $table=$this->table_element;
1508
+        if (empty($id))    	  $id=$this->id;
1509
+        if (empty($format))   $format='text';
1510
+        if (empty($id_field)) $id_field='rowid';
4526 1511
 
4527
-			if (in_array(get_class($this), array('Adherent')))
4528
-			{
4529
-				$arrayofrecords = array();   // The write_file of templates of adherent class need this var
4530
-				$resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, $moreparams);
4531
-			}
4532
-			else
4533
-			{
4534
-				$resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams);
4535
-			}
4536
-			// After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index.
1512
+        $error=0;
4537 1513
 
4538
-			if ($resultwritefile > 0)
4539
-			{
4540
-				$outputlangs->charset_output=$sav_charset_output;
1514
+        $this->db->begin();
4541 1515
 
4542
-				// We delete old preview
4543
-				require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
4544
-				dol_delete_preview($this);
1516
+        // Special case
1517
+        if ($table == 'product' && $field == 'note_private') $field='note';
1518
+        if (in_array($table, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))) $fk_user_field = 'fk_user_mod';
4545 1519
 
4546
-				// Index file in database
4547
-				if (! empty($obj->result['fullpath']))
4548
-				{
4549
-					$destfull = $obj->result['fullpath'];
4550
-					$upload_dir = dirname($destfull);
4551
-					$destfile = basename($destfull);
4552
-					$rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $upload_dir);
4553
-
4554
-					if (! preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir))     // If not a tmp dir
4555
-					{
4556
-						$filename = basename($destfile);
4557
-						$rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
4558
-						$rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
4559
-
4560
-						include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
4561
-						$ecmfile=new EcmFiles($this->db);
4562
-						$result = $ecmfile->fetch(0, '', ($rel_dir?$rel_dir.'/':'').$filename);
4563
-
4564
-						// Set the public "share" key
4565
-						$setsharekey = false;
4566
-						if ($this->element == 'propal')
4567
-						{
4568
-							$useonlinesignature = $conf->global->MAIN_FEATURES_LEVEL;	// Replace this with 1 when feature to make online signature is ok
4569
-							if ($useonlinesignature) $setsharekey=true;
4570
-							if (! empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4571
-						}
4572
-						if ($this->element == 'commande'     && ! empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD))        $setsharekey=true;
4573
-						if ($this->element == 'facture'      && ! empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD))      $setsharekey=true;
4574
-						if ($this->element == 'bank_account' && ! empty($conf->global->BANK_ACCOUNT_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4575
-
4576
-						if ($setsharekey)
4577
-						{
4578
-							if (empty($ecmfile->share))	// Because object not found or share not set yet
4579
-							{
4580
-								require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
4581
-								$ecmfile->share = getRandomPassword(true);
4582
-							}
4583
-						}
1520
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$table." SET ";
4584 1521
 
4585
-						if ($result > 0)
4586
-						{
4587
-							$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
4588
-							$ecmfile->fullpath_orig = '';
4589
-							$ecmfile->gen_or_uploaded = 'generated';
4590
-							$ecmfile->description = '';    // indexed content
4591
-							$ecmfile->keyword = '';        // keyword content
4592
-							$result = $ecmfile->update($user);
4593
-							if ($result < 0)
4594
-							{
4595
-								setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4596
-							}
4597
-						}
4598
-						else
4599
-						{
4600
-							$ecmfile->entity = $conf->entity;
4601
-							$ecmfile->filepath = $rel_dir;
4602
-							$ecmfile->filename = $filename;
4603
-							$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
4604
-							$ecmfile->fullpath_orig = '';
4605
-							$ecmfile->gen_or_uploaded = 'generated';
4606
-							$ecmfile->description = '';    // indexed content
4607
-							$ecmfile->keyword = '';        // keyword content
4608
-							$ecmfile->src_object_type = $this->table_element;
4609
-							$ecmfile->src_object_id   = $this->id;
4610
-
4611
-							$result = $ecmfile->create($user);
4612
-							if ($result < 0)
4613
-							{
4614
-								setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4615
-							}
4616
-						}
1522
+        if ($format == 'text') $sql.= $field." = '".$this->db->escape($value)."'";
1523
+        else if ($format == 'int') $sql.= $field." = ".$this->db->escape($value);
1524
+        else if ($format == 'date') $sql.= $field." = ".($value ? "'".$this->db->idate($value)."'" : "null");
4617 1525
 
4618
-						/*$this->result['fullname']=$destfull;
4619
-						$this->result['filepath']=$ecmfile->filepath;
4620
-						$this->result['filename']=$ecmfile->filename;*/
4621
-						//var_dump($obj->update_main_doc_field);exit;
4622
-
4623
-						// Update the last_main_doc field into main object (if documenent generator has property ->update_main_doc_field set)
4624
-						$update_main_doc_field=0;
4625
-						if (! empty($obj->update_main_doc_field)) $update_main_doc_field=1;
4626
-						if ($update_main_doc_field && ! empty($this->table_element))
4627
-						{
4628
-							$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET last_main_doc = '".($ecmfile->filepath.'/'.$ecmfile->filename)."'";
4629
-							$sql.= ' WHERE rowid = '.$this->id;
4630
-							$resql = $this->db->query($sql);
4631
-							if (! $resql) dol_print_error($this->db);
4632
-						}
4633
-					}
4634
-				}
4635
-				else
4636
-				{
4637
-					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);
4638
-				}
1526
+        if ($fk_user_field)
1527
+        {
1528
+            if (! empty($fuser) && is_object($fuser)) $sql.=", ".$fk_user_field." = ".$fuser->id;
1529
+            elseif (empty($fuser) || $fuser != 'none') $sql.=", ".$fk_user_field." = ".$user->id;
1530
+        }
4639 1531
 
4640
-				// Success in building document. We build meta file.
4641
-				dol_meta_create($this);
1532
+        $sql.= " WHERE ".$id_field." = ".$id;
4642 1533
 
4643
-				return 1;
4644
-			}
4645
-			else
4646
-			{
4647
-				$outputlangs->charset_output=$sav_charset_output;
4648
-				dol_print_error($this->db, "Error generating document for ".__CLASS__.". Error: ".$obj->error, $obj->errors);
4649
-				return -1;
4650
-			}
4651
-		}
4652
-		else
4653
-		{
4654
-			$this->error=$langs->trans("Error")." ".$langs->trans("ErrorFileDoesNotExists",$file);
4655
-			dol_print_error('',$this->error);
4656
-			return -1;
4657
-		}
4658
-	}
4659
-
4660
-	/**
4661
-	 *  Build thumb
4662
-	 *  @TODO Move this into files.lib.php
4663
-	 *
4664
-	 *  @param      string	$file           Path file in UTF8 to original file to create thumbs from.
4665
-	 *	@return		void
4666
-	 */
4667
-	function addThumbs($file)
4668
-	{
4669
-		global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini, $quality;
4670
-
4671
-		require_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';		// This define also $maxwidthsmall, $quality, ...
4672
-
4673
-		$file_osencoded=dol_osencode($file);
4674
-		if (file_exists($file_osencoded))
4675
-		{
4676
-			// Create small thumbs for company (Ratio is near 16/9)
4677
-			// Used on logon for example
4678
-			vignette($file_osencoded, $maxwidthsmall, $maxheightsmall, '_small', $quality);
4679
-
4680
-			// Create mini thumbs for company (Ratio is near 16/9)
4681
-			// Used on menu or for setup page for example
4682
-			vignette($file_osencoded, $maxwidthmini, $maxheightmini, '_mini', $quality);
4683
-		}
4684
-	}
4685
-
4686
-
4687
-	/* Functions common to commonobject and commonobjectline */
4688
-
4689
-	/* For default values */
4690
-
4691
-	/**
4692
-	 * Return the default value to use for a field when showing the create form of object.
4693
-	 * Return values in this order:
4694
-	 * 1) If parameter is available into POST, we return it first.
4695
-	 * 2) If not but an alternate value was provided as parameter of function, we return it.
4696
-	 * 3) If not but a constant $conf->global->OBJECTELEMENT_FIELDNAME is set, we return it (It is better to use the dedicated table).
4697
-	 * 4) Return value found into database (TODO No yet implemented)
4698
-	 *
4699
-	 * @param   string              $fieldname          Name of field
4700
-	 * @param   string              $alternatevalue     Alternate value to use
4701
-	 * @return  string|string[]                         Default value (can be an array if the GETPOST return an array)
4702
-	 **/
4703
-	function getDefaultCreateValueFor($fieldname, $alternatevalue=null)
4704
-	{
4705
-		global $conf, $_POST;
4706
-
4707
-		// If param here has been posted, we use this value first.
4708
-		if (isset($_POST[$fieldname])) return GETPOST($fieldname, 2);
4709
-
4710
-		if (isset($alternatevalue)) return $alternatevalue;
4711
-
4712
-		$newelement=$this->element;
4713
-		if ($newelement == 'facture') $newelement='invoice';
4714
-		if ($newelement == 'commande') $newelement='order';
4715
-		if (empty($newelement))
4716
-		{
4717
-			dol_syslog("Ask a default value using common method getDefaultCreateValueForField on an object with no property ->element defined. Return empty string.", LOG_WARNING);
4718
-			return '';
4719
-		}
4720
-
4721
-		$keyforfieldname=strtoupper($newelement.'_DEFAULT_'.$fieldname);
4722
-		//var_dump($keyforfieldname);
4723
-		if (isset($conf->global->$keyforfieldname)) return $conf->global->$keyforfieldname;
4724
-
4725
-		// TODO Ad here a scan into table llx_overwrite_default with a filter on $this->element and $fieldname
4726
-	}
4727
-
4728
-
4729
-	/* For triggers */
1534
+        dol_syslog(get_class($this)."::".__FUNCTION__."", LOG_DEBUG);
1535
+        $resql = $this->db->query($sql);
1536
+        if ($resql)
1537
+        {
1538
+            if ($trigkey)
1539
+            {
1540
+                // call trigger with updated object values
1541
+                if (empty($this->fields) && method_exists($this, 'fetch'))
1542
+                {
1543
+                    $result = $this->fetch($id);
1544
+                }
1545
+                else
1546
+                {
1547
+                    $result = $this->fetchCommon($id);
1548
+                }
1549
+                if ($result >= 0) $result=$this->call_trigger($trigkey, (! empty($fuser) && is_object($fuser)) ? $fuser : $user);   // This may set this->errors
1550
+                if ($result < 0) $error++;
1551
+            }
4730 1552
 
1553
+            if (! $error)
1554
+            {
1555
+                if (property_exists($this, $field)) $this->$field = $value;
1556
+                $this->db->commit();
1557
+                return 1;
1558
+            }
1559
+            else
1560
+            {
1561
+                $this->db->rollback();
1562
+                return -2;
1563
+            }
1564
+        }
1565
+        else
1566
+        {
1567
+            $this->error=$this->db->lasterror();
1568
+            $this->db->rollback();
1569
+            return -1;
1570
+        }
1571
+    }
4731 1572
 
4732 1573
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4733
-	/**
4734
-	 * Call trigger based on this instance.
4735
-	 * Some context information may also be provided into array property this->context.
4736
-	 * NB:  Error from trigger are stacked in interface->errors
4737
-	 * NB2: If return code of triggers are < 0, action calling trigger should cancel all transaction.
4738
-	 *
4739
-	 * @param   string    $trigger_name   trigger's name to execute
4740
-	 * @param   User      $user           Object user
4741
-	 * @return  int                       Result of run_triggers
4742
-	 */
4743
-	function call_trigger($trigger_name, $user)
4744
-	{
1574
+    /**
1575
+     *      Load properties id_previous and id_next by comparing $fieldid with $this->ref
1576
+     *
1577
+     *      @param	string	$filter		Optional filter. Example: " AND (t.field1 = 'aa' OR t.field2 = 'bb')"
1578
+     *	 	@param  string	$fieldid   	Name of field to use for the select MAX and MIN
1579
+     *		@param	int		$nodbprefix	Do not include DB prefix to forge table name
1580
+     *      @return int         		<0 if KO, >0 if OK
1581
+     */
1582
+    function load_previous_next_ref($filter, $fieldid, $nodbprefix=0)
1583
+    {
4745 1584
         // phpcs:enable
4746
-		global $langs,$conf;
1585
+        global $conf, $user;
4747 1586
 
4748
-		include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
4749
-		$interface=new Interfaces($this->db);
4750
-		$result=$interface->run_triggers($trigger_name,$this,$user,$langs,$conf);
1587
+        if (! $this->table_element)
1588
+        {
1589
+            dol_print_error('',get_class($this)."::load_previous_next_ref was called on objet with property table_element not defined");
1590
+            return -1;
1591
+        }
1592
+        if ($fieldid == 'none') return 1;
4751 1593
 
4752
-		if ($result < 0)
4753
-		{
4754
-			if (!empty($this->errors))
4755
-			{
4756
-				$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.
4757
-			}
4758
-			else
4759
-			{
4760
-				$this->errors=$interface->errors;
4761
-			}
4762
-		}
4763
-		return $result;
4764
-	}
1594
+        // Security on socid
1595
+        $socid = 0;
1596
+        if ($user->societe_id > 0) $socid = $user->societe_id;
4765 1597
 
1598
+        // this->ismultientitymanaged contains
1599
+        // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
1600
+        $alias = 's';
1601
+        if ($this->element == 'societe') $alias = 'te';
4766 1602
 
4767
-	/* Functions for extrafields */
1603
+        $sql = "SELECT MAX(te.".$fieldid.")";
1604
+        $sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1605
+        if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1606
+            $sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
1607
+        }
1608
+        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
1609
+        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
1610
+        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
1611
+        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";
1612
+        $sql.= " WHERE te.".$fieldid." < '".$this->db->escape($this->ref)."'";  // ->ref must always be defined (set to id if field does not exists)
1613
+        if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1614
+        if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1615
+        if (! empty($filter))
1616
+        {
1617
+            if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND ";   // For backward compatibility
1618
+            $sql.=$filter;
1619
+        }
1620
+        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
1621
+        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
1622
+        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1623
+            if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1624
+                if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1625
+                    $sql.= " AND te.entity IS NOT NULL"; // Show all users
1626
+                } else {
1627
+                    $sql.= " AND ug.fk_user = te.rowid";
1628
+                    $sql.= " AND ug.entity IN (".getEntity($this->element).")";
1629
+                }
1630
+            } else {
1631
+                $sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1632
+            }
1633
+        }
1634
+        if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1635
+        if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1636
+        if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1637
+        //print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
4768 1638
 
1639
+        $result = $this->db->query($sql);
1640
+        if (! $result)
1641
+        {
1642
+            $this->error=$this->db->lasterror();
1643
+            return -1;
1644
+        }
1645
+        $row = $this->db->fetch_row($result);
1646
+        $this->ref_previous = $row[0];
4769 1647
 
4770
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4771
-	/**
4772
-	 *  Function to get extra fields of an object into $this->array_options
4773
-	 *  This method is in most cases called by method fetch of objects but you can call it separately.
4774
-	 *
4775
-	 *  @param	int		$rowid			Id of line. Use the id of object if not defined. Deprecated. Function must be called without parameters.
4776
-	 *  @param  array	$optionsArray   Array resulting of call of extrafields->fetch_name_optionals_label(). Deprecated. Function must be called without parameters.
4777
-	 *  @return	int						<0 if error, 0 if no values of extrafield to find nor found, 1 if an attribute is found and value loaded
4778
-	 */
4779
-	function fetch_optionals($rowid=null, $optionsArray=null)
4780
-	{
4781
-        // phpcs:enable
4782
-		if (empty($rowid)) $rowid=$this->id;
4783
-
4784
-		// To avoid SQL errors. Probably not the better solution though
4785
-		if (!$this->table_element) {
4786
-			return 0;
4787
-		}
4788
-
4789
-		$this->array_options=array();
4790
-
4791
-		if (! is_array($optionsArray))
4792
-		{
4793
-			// If $extrafields is not a known object, we initialize it. Best practice is to have $extrafields defined into card.php or list.php page.
4794
-			// TODO Use of existing $extrafield is not yet ready (must mutualize code that use extrafields in form first)
4795
-			// global $extrafields;
4796
-			//if (! is_object($extrafields))
4797
-			//{
4798
-				require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4799
-				$extrafields = new ExtraFields($this->db);
4800
-			//}
4801
-
4802
-			// Load array of extrafields for elementype = $this->table_element
4803
-			if (empty($extrafields->attributes[$this->table_element]['loaded']))
4804
-			{
4805
-				$extrafields->fetch_name_optionals_label($this->table_element);
4806
-			}
4807
-			$optionsArray = (! empty($extrafields->attributes[$this->table_element]['label'])?$extrafields->attributes[$this->table_element]['label']:null);
4808
-		}
4809
-		else
4810
-		{
4811
-			global $extrafields;
4812
-			dol_syslog("Warning: fetch_optionals was called with param optionsArray defined when you should pass null now", LOG_WARNING);
4813
-		}
4814
-
4815
-		$table_element = $this->table_element;
4816
-		if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4817
-
4818
-		// Request to get complementary values
4819
-		if (is_array($optionsArray) && count($optionsArray) > 0)
4820
-		{
4821
-			$sql = "SELECT rowid";
4822
-			foreach ($optionsArray as $name => $label)
4823
-			{
4824
-				if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] != 'separate')
4825
-				{
4826
-					$sql.= ", ".$name;
4827
-				}
4828
-			}
4829
-			$sql.= " FROM ".MAIN_DB_PREFIX.$table_element."_extrafields";
4830
-			$sql.= " WHERE fk_object = ".$rowid;
4831 1648
 
4832
-			//dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG);		// Too verbose
4833
-			$resql=$this->db->query($sql);
4834
-			if ($resql)
4835
-			{
4836
-				$this->array_options = array();
4837
-				$numrows=$this->db->num_rows($resql);
4838
-				if ($numrows)
4839
-				{
4840
-					$tab = $this->db->fetch_array($resql);
4841
-
4842
-					foreach ($tab as $key => $value)
4843
-					{
4844
-						// 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)
4845
-						if ($key != 'rowid' && $key != 'tms' && $key != 'fk_member' && ! is_int($key))
4846
-						{
4847
-							// we can add this attribute to object
4848
-							if (! empty($extrafields) && in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date','datetime')))
4849
-							{
4850
-								//var_dump($extrafields->attributes[$this->table_element]['type'][$key]);
4851
-								$this->array_options["options_".$key]=$this->db->jdate($value);
4852
-							}
4853
-							else
4854
-							{
4855
-								$this->array_options["options_".$key]=$value;
4856
-							}
1649
+        $sql = "SELECT MIN(te.".$fieldid.")";
1650
+        $sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1651
+        if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1652
+            $sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
1653
+        }
1654
+        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
1655
+        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
1656
+        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
1657
+        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";
1658
+        $sql.= " WHERE te.".$fieldid." > '".$this->db->escape($this->ref)."'";  // ->ref must always be defined (set to id if field does not exists)
1659
+        if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1660
+        if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1661
+        if (! empty($filter))
1662
+        {
1663
+            if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND ";   // For backward compatibility
1664
+            $sql.=$filter;
1665
+        }
1666
+        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
1667
+        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
1668
+        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1669
+            if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1670
+                if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1671
+                    $sql.= " AND te.entity IS NOT NULL"; // Show all users
1672
+                } else {
1673
+                    $sql.= " AND ug.fk_user = te.rowid";
1674
+                    $sql.= " AND ug.entity IN (".getEntity($this->element).")";
1675
+                }
1676
+            } else {
1677
+                $sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1678
+            }
1679
+        }
1680
+        if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1681
+        if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1682
+        if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1683
+        //print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1684
+        // 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
1685
+
1686
+        $result = $this->db->query($sql);
1687
+        if (! $result)
1688
+        {
1689
+            $this->error=$this->db->lasterror();
1690
+            return -2;
1691
+        }
1692
+        $row = $this->db->fetch_row($result);
1693
+        $this->ref_next = $row[0];
4857 1694
 
4858
-							//var_dump('key '.$key.' '.$value.' type='.$extrafields->attributes[$this->table_element]['type'][$key].' '.$this->array_options["options_".$key]);
4859
-						}
4860
-					}
4861
-				}
1695
+        return 1;
1696
+    }
4862 1697
 
4863
-				$this->db->free($resql);
4864 1698
 
4865
-				if ($numrows) return $numrows;
4866
-				else return 0;
4867
-			}
4868
-			else
4869
-			{
4870
-				dol_print_error($this->db);
4871
-				return -1;
4872
-			}
4873
-		}
4874
-		return 0;
4875
-	}
4876
-
4877
-	/**
4878
-	 *	Delete all extra fields values for the current object.
4879
-	 *
4880
-	 *  @return	int		<0 if KO, >0 if OK
4881
-	 */
4882
-	function deleteExtraFields()
4883
-	{
4884
-		$this->db->begin();
4885
-
4886
-		$table_element = $this->table_element;
4887
-		if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4888
-
4889
-		$sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
4890
-		dol_syslog(get_class($this)."::deleteExtraFields delete", LOG_DEBUG);
4891
-		$resql=$this->db->query($sql_del);
4892
-		if (! $resql)
4893
-		{
4894
-			$this->error=$this->db->lasterror();
4895
-			$this->db->rollback();
4896
-			return -1;
4897
-		}
4898
-		else
4899
-		{
4900
-			$this->db->commit();
4901
-			return 1;
4902
-		}
4903
-	}
4904
-
4905
-	/**
4906
-	 *	Add/Update all extra fields values for the current object.
4907
-	 *  Data to describe values to insert/update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
4908
-	 *  This function delete record with all extrafields and insert them again from the array $this->array_options.
4909
-	 *
4910
-	 *  @param	string		$trigger		If defined, call also the trigger (for example COMPANY_MODIFY)
4911
-	 *  @param	User		$userused		Object user
4912
-	 *  @return int 						-1=error, O=did nothing, 1=OK
4913
-	 *  @see updateExtraField, setValueFrom
4914
-	 */
4915
-	function insertExtraFields($trigger='', $userused=null)
4916
-	{
4917
-		global $conf,$langs,$user;
4918
-
4919
-		if (empty($userused)) $userused=$user;
4920
-
4921
-		$error=0;
4922
-
4923
-		if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0;	// For avoid conflicts if trigger used
4924
-
4925
-		if (! empty($this->array_options))
4926
-		{
4927
-			// Check parameters
4928
-			$langs->load('admin');
4929
-			require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4930
-			$extrafields = new ExtraFields($this->db);
4931
-			$target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
4932
-
4933
-			//Eliminate copied source object extra_fields that do not exist in target object
4934
-			$new_array_options=array();
4935
-			foreach ($this->array_options as $key => $value) {
4936
-				if (in_array(substr($key,8), array_keys($target_extrafields)))	// We remove the 'options_' from $key for test
4937
-					$new_array_options[$key] = $value;
4938
-				elseif (in_array($key, array_keys($target_extrafields)))		// We test on $key that does not contains the 'options_' prefix
4939
-					$new_array_options['options_'.$key] = $value;
4940
-			}
4941
-
4942
-			foreach($new_array_options as $key => $value)
4943
-			{
4944
-			   	$attributeKey      = substr($key,8);   // Remove 'options_' prefix
4945
-			   	$attributeType     = $extrafields->attributes[$this->table_element]['type'][$attributeKey];
4946
-			   	$attributeLabel    = $extrafields->attributes[$this->table_element]['label'][$attributeKey];
4947
-			   	$attributeParam    = $extrafields->attributes[$this->table_element]['param'][$attributeKey];
4948
-			   	$attributeRequired = $extrafields->attributes[$this->table_element]['required'][$attributeKey];
4949
-
4950
-			   	if ($attributeRequired)
4951
-			   	{
4952
-			   		$mandatorypb=false;
4953
-			   		if ($attributeType == 'link' && $this->array_options[$key] == '-1') $mandatorypb=true;
4954
-			   		if ($this->array_options[$key] === '') $mandatorypb=true;
4955
-			   		if ($mandatorypb)
4956
-			   		{
4957
-			   			dol_syslog($this->error);
4958
-			   			$this->errors[]=$langs->trans('ErrorFieldRequired', $attributeLabel);
4959
-			   			return -1;
4960
-			   		}
4961
-			   	}
4962
-
4963
-				//dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
4964
-				//dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
4965
-
4966
-			   	switch ($attributeType)
4967
-			   	{
4968
-			   		case 'int':
4969
-			  			if (!is_numeric($value) && $value!='')
4970
-			   			{
4971
-			   				$this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4972
-			   				return -1;
4973
-			  			}
4974
-			   			elseif ($value=='')
4975
-			   			{
4976
-			   				$new_array_options[$key] = null;
4977
-			   			}
4978
-			 			break;
4979
-					case 'double':
4980
-						$value = price2num($value);
4981
-						if (!is_numeric($value) && $value!='')
4982
-						{
4983
-							dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
4984
-							$this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4985
-							return -1;
4986
-						}
4987
-						elseif ($value=='')
4988
-						{
4989
-							$new_array_options[$key] = null;
4990
-						}
4991
-						//dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
4992
-						$new_array_options[$key] = $value;
4993
-						break;
4994
-			 		/*case 'select':	// Not required, we chosed value='0' for undefined values
4995
-             			if ($value=='-1')
4996
-             			{
4997
-             				$this->array_options[$key] = null;
4998
-             			}
4999
-             			break;*/
5000
-			   		case 'password':
5001
-			   			$algo='';
5002
-			   			if ($this->array_options[$key] != '' && is_array($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']))
5003
-			   			{
5004
-			   				// If there is an encryption choice, we use it to crypt data before insert
5005
-			   				$tmparrays = array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']);
5006
-			   				$algo=reset($tmparrays);
5007
-			   				if ($algo != '')
5008
-			   				{
5009
-			   					//global $action;		// $action may be 'create', 'update', 'update_extras'...
5010
-			   					//var_dump($action);
5011
-			   					//var_dump($this->oldcopy);exit;
5012
-			   					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
5013
-			   					{
5014
-			   						//var_dump($this->oldcopy->array_options[$key]); var_dump($this->array_options[$key]);
5015
-				   					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.
5016
-				   					{
5017
-				   						$new_array_options[$key] = $this->array_options[$key];	// Value is kept
5018
-				   					}
5019
-									else
5020
-									{
5021
-										// var_dump($algo);
5022
-										$newvalue = dol_hash($this->array_options[$key], $algo);
5023
-										$new_array_options[$key] = $newvalue;
5024
-									}
5025
-			   					}
5026
-			   					else
5027
-			   					{
5028
-			   						$new_array_options[$key] = $this->array_options[$key];	// Value is kept
5029
-			   					}
5030
-			   				}
5031
-			   			}
5032
-			   			else	// Common usage
5033
-			   			{
5034
-			   				$new_array_options[$key] = $this->array_options[$key];
5035
-			   			}
5036
-			   			break;
5037
-			   		case 'price':
5038
-						$new_array_options[$key] = price2num($this->array_options[$key]);
5039
-						break;
5040
-					case 'date':
5041
-						$new_array_options[$key] = $this->db->idate($this->array_options[$key]);
5042
-						break;
5043
-					case 'datetime':
5044
-						// If data is a string instead of a timestamp, we convert it
5045
-						if (! is_int($this->array_options[$key])) {
5046
-							$this->array_options[$key] = strtotime($this->array_options[$key]);
5047
-						}
5048
-						$new_array_options[$key] = $this->db->idate($this->array_options[$key]);
5049
-						break;
5050
-		   			case 'link':
5051
-						$param_list=array_keys($attributeParam['options']);
5052
-						// 0 : ObjectName
5053
-						// 1 : classPath
5054
-						$InfoFieldList = explode(":", $param_list[0]);
5055
-						dol_include_once($InfoFieldList[1]);
5056
-						if ($InfoFieldList[0] && class_exists($InfoFieldList[0]))
5057
-						{
5058
-							if ($value == '-1')	// -1 is key for no defined in combo list of objects
5059
-							{
5060
-								$new_array_options[$key]='';
5061
-							}
5062
-							elseif ($value)
5063
-							{
5064
-								$object = new $InfoFieldList[0]($this->db);
5065
-								if (is_numeric($value)) $res=$object->fetch($value);
5066
-								else $res=$object->fetch('',$value);
5067
-
5068
-								if ($res > 0) $new_array_options[$key]=$object->id;
5069
-								else
5070
-								{
5071
-									$this->error="Id/Ref '".$value."' for object '".$object->element."' not found";
5072
-									$this->db->rollback();
5073
-									return -1;
5074
-								}
5075
-							}
5076
-						}
5077
-						else
5078
-						{
5079
-							dol_syslog('Error bad setup of extrafield', LOG_WARNING);
5080
-						}
5081
-						break;
5082
-			   	}
5083
-			}
1699
+    /**
1700
+     *      Return list of id of contacts of object
1701
+     *
1702
+     *      @param	string	$source     Source of contact: external (llx_socpeople) or internal (llx_user) or thirdparty (llx_societe)
1703
+     *      @return array				Array of id of contacts (if source=external or internal)
1704
+     * 									Array of id of third parties with at least one contact on object (if source=thirdparty)
1705
+     */
1706
+    function getListContactId($source='external')
1707
+    {
1708
+        $contactAlreadySelected = array();
1709
+        $tab = $this->liste_contact(-1,$source);
1710
+        $num=count($tab);
1711
+        $i = 0;
1712
+        while ($i < $num)
1713
+        {
1714
+            if ($source == 'thirdparty') $contactAlreadySelected[$i] = $tab[$i]['socid'];
1715
+            else  $contactAlreadySelected[$i] = $tab[$i]['id'];
1716
+            $i++;
1717
+        }
1718
+        return $contactAlreadySelected;
1719
+    }
5084 1720
 
5085
-			$this->db->begin();
5086 1721
 
5087
-			$table_element = $this->table_element;
5088
-			if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
1722
+    /**
1723
+     *	Link element with a project
1724
+     *
1725
+     *	@param     	int		$projectid		Project id to link element to
1726
+     *	@return		int						<0 if KO, >0 if OK
1727
+     */
1728
+    function setProject($projectid)
1729
+    {
1730
+        if (! $this->table_element)
1731
+        {
1732
+            dol_syslog(get_class($this)."::setProject was called on objet with property table_element not defined",LOG_ERR);
1733
+            return -1;
1734
+        }
5089 1735
 
5090
-			$sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
5091
-			dol_syslog(get_class($this)."::insertExtraFields delete", LOG_DEBUG);
5092
-			$this->db->query($sql_del);
1736
+        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1737
+        if ($this->table_element == 'actioncomm')
1738
+        {
1739
+            if ($projectid) $sql.= ' SET fk_project = '.$projectid;
1740
+            else $sql.= ' SET fk_project = NULL';
1741
+            $sql.= ' WHERE id = '.$this->id;
1742
+        }
1743
+        else
1744
+        {
1745
+            if ($projectid) $sql.= ' SET fk_projet = '.$projectid;
1746
+            else $sql.= ' SET fk_projet = NULL';
1747
+            $sql.= ' WHERE rowid = '.$this->id;
1748
+        }
5093 1749
 
5094
-			$sql = "INSERT INTO ".MAIN_DB_PREFIX.$table_element."_extrafields (fk_object";
5095
-			foreach($new_array_options as $key => $value)
5096
-			{
5097
-				$attributeKey = substr($key,8);   // Remove 'options_' prefix
5098
-				// Add field of attribut
5099
-				if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator
5100
-					$sql.=",".$attributeKey;
5101
-			}
5102
-			$sql .= ") VALUES (".$this->id;
5103
-
5104
-			foreach($new_array_options as $key => $value)
5105
-			{
5106
-				$attributeKey = substr($key,8);   // Remove 'options_' prefix
5107
-				// Add field of attribute
5108
-				if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator)
5109
-				{
5110
-					if ($new_array_options[$key] != '')
5111
-					{
5112
-						$sql.=",'".$this->db->escape($new_array_options[$key])."'";
5113
-					}
5114
-					else
5115
-					{
5116
-						$sql.=",null";
5117
-					}
5118
-				}
5119
-			}
5120
-			$sql.=")";
1750
+        dol_syslog(get_class($this)."::setProject", LOG_DEBUG);
1751
+        if ($this->db->query($sql))
1752
+        {
1753
+            $this->fk_project = $projectid;
1754
+            return 1;
1755
+        }
1756
+        else
1757
+        {
1758
+            dol_print_error($this->db);
1759
+            return -1;
1760
+        }
1761
+    }
5121 1762
 
5122
-			dol_syslog(get_class($this)."::insertExtraFields insert", LOG_DEBUG);
5123
-			$resql = $this->db->query($sql);
5124
-			if (! $resql)
5125
-			{
5126
-				$this->error=$this->db->lasterror();
5127
-				$error++;
5128
-			}
1763
+    /**
1764
+     *  Change the payments methods
1765
+     *
1766
+     *  @param		int		$id		Id of new payment method
1767
+     *  @return		int				>0 if OK, <0 if KO
1768
+     */
1769
+    function setPaymentMethods($id)
1770
+    {
1771
+        dol_syslog(get_class($this).'::setPaymentMethods('.$id.')');
1772
+        if ($this->statut >= 0 || $this->element == 'societe')
1773
+        {
1774
+            // TODO uniformize field name
1775
+            $fieldname = 'fk_mode_reglement';
1776
+            if ($this->element == 'societe') $fieldname = 'mode_reglement';
1777
+            if (get_class($this) == 'Fournisseur') $fieldname = 'mode_reglement_supplier';
5129 1778
 
5130
-			if (! $error && $trigger)
5131
-			{
5132
-				// Call trigger
5133
-				$this->context=array('extrafieldaddupdate'=>1);
5134
-				$result=$this->call_trigger($trigger, $userused);
5135
-				if ($result < 0) $error++;
5136
-				// End call trigger
5137
-			}
5138
-
5139
-			if ($error)
5140
-			{
5141
-				$this->db->rollback();
5142
-				return -1;
5143
-			}
5144
-			else
5145
-			{
5146
-				$this->db->commit();
5147
-				return 1;
5148
-			}
5149
-		}
5150
-		else return 0;
5151
-	}
5152
-
5153
-	/**
5154
-	 *	Update an extra field value for the current object.
5155
-	 *  Data to describe values to update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
5156
-	 *
5157
-	 *  @param  string      $key    		Key of the extrafield (without starting 'options_')
5158
-	 *  @param	string		$trigger		If defined, call also the trigger (for example COMPANY_MODIFY)
5159
-	 *  @param	User		$userused		Object user
5160
-	 *  @return int                 		-1=error, O=did nothing, 1=OK
5161
-	 *  @see setValueFrom, insertExtraFields
5162
-	 */
5163
-	function updateExtraField($key, $trigger=null, $userused=null)
5164
-	{
5165
-		global $conf,$langs,$user;
5166
-
5167
-		if (empty($userused)) $userused=$user;
5168
-
5169
-		$error=0;
5170
-
5171
-		if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0;	// For avoid conflicts if trigger used
5172
-
5173
-		if (! empty($this->array_options) && isset($this->array_options["options_".$key]))
5174
-		{
5175
-			// Check parameters
5176
-			$langs->load('admin');
5177
-			require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
5178
-			$extrafields = new ExtraFields($this->db);
5179
-			$target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
5180
-
5181
-			$value=$this->array_options["options_".$key];
5182
-
5183
-			$attributeType     = $extrafields->attributes[$this->table_element]['type'][$key];
5184
-			$attributeLabel    = $extrafields->attributes[$this->table_element]['label'][$key];
5185
-			$attributeParam    = $extrafields->attributes[$this->table_element]['param'][$key];
5186
-			$attributeRequired = $extrafields->attributes[$this->table_element]['required'][$key];
5187
-
5188
-			//dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
5189
-			//dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
5190
-
5191
-			switch ($attributeType)
5192
-			{
5193
-				case 'int':
5194
-					if (!is_numeric($value) && $value!='')
5195
-					{
5196
-						$this->errors[]=$langs->trans("ExtraFieldHasWrongValue",$attributeLabel);
5197
-						return -1;
5198
-					}
5199
-					elseif ($value=='')
5200
-					{
5201
-						$this->array_options["options_".$key] = null;
5202
-					}
5203
-					break;
5204
-				case 'double':
5205
-					$value = price2num($value);
5206
-					if (!is_numeric($value) && $value!='')
5207
-					{
5208
-						dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
5209
-						$this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
5210
-						return -1;
5211
-					}
5212
-					elseif ($value=='')
5213
-					{
5214
-						$this->array_options["options_".$key] = null;
5215
-					}
5216
-					//dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
5217
-					$this->array_options["options_".$key] = $value;
5218
-					break;
5219
-			 	/*case 'select':	// Not required, we chosed value='0' for undefined values
5220
-             		if ($value=='-1')
5221
-             		{
5222
-             			$this->array_options[$key] = null;
5223
-             		}
5224
-             		break;*/
5225
-				case 'price':
5226
-					$this->array_options["options_".$key] = price2num($this->array_options["options_".$key]);
5227
-					break;
5228
-				case 'date':
5229
-					$this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
5230
-					break;
5231
-				case 'datetime':
5232
-					$this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
5233
-					break;
5234
-				case 'link':
5235
-					$param_list=array_keys($attributeParam['options']);
5236
-					// 0 : ObjectName
5237
-					// 1 : classPath
5238
-					$InfoFieldList = explode(":", $param_list[0]);
5239
-					dol_include_once($InfoFieldList[1]);
5240
-					if ($value)
5241
-					{
5242
-						$object = new $InfoFieldList[0]($this->db);
5243
-						$object->fetch(0,$value);
5244
-						$this->array_options["options_".$key]=$object->id;
5245
-					}
5246
-					break;
5247
-			}
5248
-
5249
-			$this->db->begin();
5250
-			$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element."_extrafields SET ".$key."='".$this->db->escape($this->array_options["options_".$key])."'";
5251
-			$sql .= " WHERE fk_object = ".$this->id;
5252
-			$resql = $this->db->query($sql);
5253
-			if (! $resql)
5254
-			{
5255
-				$error++;
5256
-				$this->error=$this->db->lasterror();
5257
-			}
1779
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1780
+            $sql .= ' SET '.$fieldname.' = '.$id;
1781
+            $sql .= ' WHERE rowid='.$this->id;
5258 1782
 
5259
-			if (! $error && $trigger)
5260
-			{
5261
-				// Call trigger
5262
-				$this->context=array('extrafieldupdate'=>1);
5263
-				$result=$this->call_trigger($trigger, $userused);
5264
-				if ($result < 0) $error++;
5265
-				// End call trigger
5266
-			}
5267
-
5268
-			if ($error)
5269
-			{
5270
-				dol_syslog(get_class($this) . "::".__METHOD__ . $this->error, LOG_ERR);
5271
-				$this->db->rollback();
5272
-				return -1;
5273
-			}
5274
-			else
5275
-			{
5276
-				$this->db->commit();
5277
-				return 1;
5278
-			}
5279
-		}
5280
-		else return 0;
5281
-	}
5282
-
5283
-
5284
-	/**
5285
-	 * Return HTML string to put an input field into a page
5286
-	 * Code very similar with showInputField of extra fields
5287
-	 *
5288
-	 * @param  array   		$val	       Array of properties for field to show
5289
-	 * @param  string  		$key           Key of attribute
5290
-	 * @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)
5291
-	 * @param  string  		$moreparam     To add more parameters on html input tag
5292
-	 * @param  string  		$keysuffix     Prefix string to add into name and id of field (can be used to avoid duplicate names)
5293
-	 * @param  string  		$keyprefix     Suffix string to add into name and id of field (can be used to avoid duplicate names)
5294
-	 * @param  string|int		$morecss       Value for css to define style/length of field. May also be a numeric.
5295
-	 * @return string
5296
-	 */
5297
-	function showInputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $morecss=0)
5298
-	{
5299
-		global $conf,$langs,$form;
5300
-
5301
-		if (! is_object($form))
5302
-		{
5303
-			require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5304
-			$form=new Form($this->db);
5305
-		}
5306
-
5307
-		$val=$this->fields[$key];
5308
-
5309
-		$out='';
5310
-        $type='';
5311
-        $param = array();
5312
-        $param['options']=array();
5313
-        $size =$this->fields[$key]['size'];
5314
-        // Because we work on extrafields
5315
-        if(preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)){
5316
-            $param['options']=array($reg[1].':'.$reg[2]=>'N');
5317
-            $type ='link';
5318
-        } elseif(preg_match('/^link:(.*):(.*)/i', $val['type'], $reg)) {
5319
-            $param['options']=array($reg[1].':'.$reg[2]=>'N');
5320
-            $type ='link';
5321
-        } elseif(preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
5322
-            $param['options']=array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4]=>'N');
5323
-            $type ='sellist';
5324
-        } elseif(preg_match('/varchar\((\d+)\)/', $val['type'],$reg)) {
5325
-            $param['options']=array();
5326
-            $type ='varchar';
5327
-            $size=$reg[1];
5328
-        } elseif(preg_match('/varchar/', $val['type'])) {
5329
-            $param['options']=array();
5330
-            $type ='varchar';
5331
-        } elseif(is_array($this->fields[$key]['arrayofkeyval'])) {
5332
-            $param['options']=$this->fields[$key]['arrayofkeyval'];
5333
-            $type ='select';
5334
-        } else {
5335
-            $param['options']=array();
5336
-            $type =$this->fields[$key]['type'];
1783
+            if ($this->db->query($sql))
1784
+            {
1785
+                $this->mode_reglement_id = $id;
1786
+                // for supplier
1787
+                if (get_class($this) == 'Fournisseur') $this->mode_reglement_supplier_id = $id;
1788
+                return 1;
1789
+            }
1790
+            else
1791
+            {
1792
+                dol_syslog(get_class($this).'::setPaymentMethods Erreur '.$sql.' - '.$this->db->error());
1793
+                $this->error=$this->db->error();
1794
+                return -1;
1795
+            }
5337 1796
         }
1797
+        else
1798
+        {
1799
+            dol_syslog(get_class($this).'::setPaymentMethods, status of the object is incompatible');
1800
+            $this->error='Status of the object is incompatible '.$this->statut;
1801
+            return -2;
1802
+        }
1803
+    }
5338 1804
 
5339
-		$label=$this->fields[$key]['label'];
5340
-		//$elementtype=$this->fields[$key]['elementtype'];	// Seems not used
5341
-		$default=$this->fields[$key]['default'];
5342
-		$computed=$this->fields[$key]['computed'];
5343
-		$unique=$this->fields[$key]['unique'];
5344
-		$required=$this->fields[$key]['required'];
5345
-
5346
-		$langfile=$this->fields[$key]['langfile'];
5347
-		$list=$this->fields[$key]['list'];
5348
-		$hidden=abs($this->fields[$key]['visible'])!=1?1:0;
5349
-
5350
-		$objectid = $this->id;
1805
+    /**
1806
+     *  Change the multicurrency code
1807
+     *
1808
+     *  @param		string	$code	multicurrency code
1809
+     *  @return		int				>0 if OK, <0 if KO
1810
+     */
1811
+    function setMulticurrencyCode($code)
1812
+    {
1813
+        dol_syslog(get_class($this).'::setMulticurrencyCode('.$id.')');
1814
+        if ($this->statut >= 0 || $this->element == 'societe')
1815
+        {
1816
+            $fieldname = 'multicurrency_code';
5351 1817
 
1818
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1819
+            $sql .= ' SET '.$fieldname." = '".$this->db->escape($code)."'";
1820
+            $sql .= ' WHERE rowid='.$this->id;
5352 1821
 
5353
-		if ($computed)
5354
-		{
5355
-			if (! preg_match('/^search_/', $keyprefix)) return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
5356
-			else return '';
5357
-		}
1822
+            if ($this->db->query($sql))
1823
+            {
1824
+                $this->multicurrency_code = $code;
5358 1825
 
1826
+                list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code);
1827
+                if ($rate) $this->setMulticurrencyRate($rate,2);
5359 1828
 
5360
-		// Use in priority showsize from parameters, then $val['css'] then autodefine
5361
-		if (empty($morecss) && ! empty($val['css']))
5362
-		{
5363
-			$showsize = $val['css'];
5364
-		}
5365
-		if (empty($morecss))
5366
-		{
5367
-			if ($type == 'date')
5368
-			{
5369
-				$morecss = 'minwidth100imp';
5370
-			}
5371
-			elseif ($type == 'datetime')
5372
-			{
5373
-				$morecss = 'minwidth200imp';
5374
-			}
5375
-			elseif (in_array($type,array('int','integer','price')) || preg_match('/^double(\([0-9],[0-9]\)){0,1}/',$type))
5376
-			{
5377
-				$morecss = 'maxwidth75';
5378
-                        }elseif ($type == 'url')
5379
-			{
5380
-				$morecss='minwidth400';
5381
-			}
5382
-			elseif ($type == 'boolean')
5383
-			{
5384
-				$morecss='';
5385
-			}
5386
-			else
5387
-			{
5388
-				if (round($size) < 12)
5389
-				{
5390
-					$morecss = 'minwidth100';
5391
-				}
5392
-				else if (round($size) <= 48)
5393
-				{
5394
-					$morecss = 'minwidth200';
5395
-				}
5396
-				else
5397
-				{
5398
-					$morecss = 'minwidth400';
5399
-				}
5400
-			}
5401
-		}
5402
-
5403
-		if (in_array($type,array('date','datetime')))
5404
-		{
5405
-			$tmp=explode(',',$size);
5406
-			$newsize=$tmp[0];
5407
-
5408
-			$showtime = in_array($type,array('datetime')) ? 1 : 0;
5409
-
5410
-			// Do not show current date when field not required (see selectDate() method)
5411
-			if (!$required && $value == '') $value = '-1';
5412
-
5413
-			// TODO Must also support $moreparam
5414
-			$out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
5415
-		}
5416
-		elseif (in_array($type,array('int','integer')))
5417
-		{
5418
-			$tmp=explode(',',$size);
5419
-			$newsize=$tmp[0];
5420
-			$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:'').'>';
5421
-		}
5422
-		elseif (preg_match('/varchar/', $type))
5423
-		{
5424
-			$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:'').'>';
5425
-		}
5426
-		elseif (in_array($type, array('mail', 'phone', 'url')))
5427
-		{
5428
-			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5429
-		}
5430
-		elseif ($type == 'text')
5431
-		{
5432
-			if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
5433
-			{
5434
-				require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
5435
-				$doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,false,ROWS_5,'90%');
5436
-				$out=$doleditor->Create(1);
5437
-			}
5438
-			else
5439
-			{
5440
-				$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5441
-			}
5442
-		}
5443
-		elseif ($type == 'html')
5444
-		{
5445
-			if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
5446
-			{
5447
-				require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
5448
-				$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%');
5449
-				$out=$doleditor->Create(1);
5450
-			}
5451
-			else
5452
-			{
5453
-				$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5454
-			}
5455
-		}
5456
-		elseif ($type == 'boolean')
5457
-		{
5458
-			$checked='';
5459
-			if (!empty($value)) {
5460
-				$checked=' checked value="1" ';
5461
-			} else {
5462
-				$checked=' value="1" ';
5463
-			}
5464
-			$out='<input type="checkbox" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam?$moreparam:'').'>';
5465
-		}
5466
-		elseif ($type == 'price')
5467
-		{
5468
-			if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
5469
-				$value=price($value);
5470
-			}
5471
-			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> '.$langs->getCurrencySymbol($conf->currency);
5472
-		}
5473
-		elseif (preg_match('/^double(\([0-9],[0-9]\)){0,1}/',$type))
5474
-		{
5475
-			if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
5476
-				$value=price($value);
5477
-			}
5478
-			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> ';
5479
-		}
5480
-		elseif ($type == 'select')
5481
-		{
5482
-			$out = '';
5483
-			if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
5484
-			{
5485
-				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5486
-				$out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
5487
-			}
1829
+                return 1;
1830
+            }
1831
+            else
1832
+            {
1833
+                dol_syslog(get_class($this).'::setMulticurrencyCode Erreur '.$sql.' - '.$this->db->error());
1834
+                $this->error=$this->db->error();
1835
+                return -1;
1836
+            }
1837
+        }
1838
+        else
1839
+        {
1840
+            dol_syslog(get_class($this).'::setMulticurrencyCode, status of the object is incompatible');
1841
+            $this->error='Status of the object is incompatible '.$this->statut;
1842
+            return -2;
1843
+        }
1844
+    }
5488 1845
 
5489
-			$out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
5490
-                if((! isset($this->fields[$key]['default'])) ||($this->fields[$key]['notnull']!=1))$out.='<option value="0">&nbsp;</option>';
5491
-			foreach ($param['options'] as $key => $val)
5492
-			{
5493
-				if ((string) $key == '') continue;
5494
-				list($val, $parent) = explode('|', $val);
5495
-				$out.='<option value="'.$key.'"';
5496
-				$out.= (((string) $value == (string) $key)?' selected':'');
5497
-				$out.= (!empty($parent)?' parent="'.$parent.'"':'');
5498
-				$out.='>'.$val.'</option>';
5499
-			}
5500
-			$out.='</select>';
5501
-		}
5502
-		elseif ($type == 'sellist')
5503
-		{
5504
-			$out = '';
5505
-			if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
5506
-			{
5507
-				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5508
-				$out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
5509
-			}
1846
+    /**
1847
+     *  Change the multicurrency rate
1848
+     *
1849
+     *  @param		double	$rate	multicurrency rate
1850
+     *  @param		int		$mode	mode 1 : amounts in company currency will be recalculated, mode 2 : amounts in foreign currency
1851
+     *  @return		int				>0 if OK, <0 if KO
1852
+     */
1853
+    function setMulticurrencyRate($rate, $mode=1)
1854
+    {
1855
+        dol_syslog(get_class($this).'::setMulticurrencyRate('.$id.')');
1856
+        if ($this->statut >= 0 || $this->element == 'societe')
1857
+        {
1858
+            $fieldname = 'multicurrency_tx';
5510 1859
 
5511
-			$out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
5512
-			if (is_array($param['options']))
5513
-			{
5514
-				$param_list=array_keys($param['options']);
5515
-				$InfoFieldList = explode(":", $param_list[0]);
5516
-				$parentName='';
5517
-				$parentField='';
5518
-				// 0 : tableName
5519
-				// 1 : label field name
5520
-				// 2 : key fields name (if differ of rowid)
5521
-				// 3 : key field parent (for dependent lists)
5522
-				// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5523
-				$keyList=(empty($InfoFieldList[2])?'rowid':$InfoFieldList[2].' as rowid');
5524
-
5525
-
5526
-				if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4]))
5527
-				{
5528
-					if (strpos($InfoFieldList[4], 'extra.') !== false)
5529
-					{
5530
-						$keyList='main.'.$InfoFieldList[2].' as rowid';
5531
-					} else {
5532
-						$keyList=$InfoFieldList[2].' as rowid';
5533
-					}
5534
-				}
5535
-				if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3]))
5536
-				{
5537
-					list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
5538
-					$keyList.= ', '.$parentField;
5539
-				}
1860
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1861
+            $sql .= ' SET '.$fieldname.' = '.$rate;
1862
+            $sql .= ' WHERE rowid='.$this->id;
5540 1863
 
5541
-				$fields_label = explode('|',$InfoFieldList[1]);
5542
-				if (is_array($fields_label))
5543
-				{
5544
-					$keyList .=', ';
5545
-					$keyList .= implode(', ', $fields_label);
5546
-				}
1864
+            if ($this->db->query($sql))
1865
+            {
1866
+                $this->multicurrency_tx = $rate;
1867
+
1868
+                // Update line price
1869
+                if (!empty($this->lines))
1870
+                {
1871
+                    foreach ($this->lines as &$line)
1872
+                    {
1873
+                        if($mode == 1) {
1874
+                            $line->subprice = 0;
1875
+                        }
1876
+
1877
+                        switch ($this->element) {
1878
+                            case 'propal':
1879
+                                $this->updateline(
1880
+                                    $line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1881
+                                    ($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1882
+                                    $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start,
1883
+                                    $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1884
+                                );
1885
+                                break;
1886
+                            case 'commande':
1887
+                                $this->updateline(
1888
+                                    $line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1889
+                                    $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->date_start, $line->date_end,
1890
+                                    $line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1891
+                                    $line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1892
+                                );
1893
+                                break;
1894
+                            case 'facture':
1895
+                                $this->updateline(
1896
+                                    $line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1897
+                                    $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits,
1898
+                                    $line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1899
+                                    $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice
1900
+                                );
1901
+                                break;
1902
+                            case 'supplier_proposal':
1903
+                                $this->updateline(
1904
+                                    $line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1905
+                                    ($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1906
+                                    $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->array_options,
1907
+                                    $line->ref_fourn, $line->multicurrency_subprice
1908
+                                );
1909
+                                break;
1910
+                            case 'order_supplier':
1911
+                                $this->updateline(
1912
+                                    $line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1913
+                                    $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, false,
1914
+                                    $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1915
+                                );
1916
+                                break;
1917
+                            case 'invoice_supplier':
1918
+                                $this->updateline(
1919
+                                    $line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->tva_tx, $line->localtax1_tx,
1920
+                                    $line->localtax2_tx, $line->qty, 0, 'HT', $line->info_bits, $line->product_type, $line->remise_percent, false,
1921
+                                    $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1922
+                                );
1923
+                                break;
1924
+                            default:
1925
+                                dol_syslog(get_class($this).'::setMulticurrencyRate no updateline defined', LOG_DEBUG);
1926
+                                break;
1927
+                        }
1928
+                    }
1929
+                }
1930
+
1931
+                return 1;
1932
+            }
1933
+            else
1934
+            {
1935
+                dol_syslog(get_class($this).'::setMulticurrencyRate Erreur '.$sql.' - '.$this->db->error());
1936
+                $this->error=$this->db->error();
1937
+                return -1;
1938
+            }
1939
+        }
1940
+        else
1941
+        {
1942
+            dol_syslog(get_class($this).'::setMulticurrencyRate, status of the object is incompatible');
1943
+            $this->error='Status of the object is incompatible '.$this->statut;
1944
+            return -2;
1945
+        }
1946
+    }
5547 1947
 
5548
-				$sqlwhere='';
5549
-				$sql = 'SELECT '.$keyList;
5550
-				$sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
5551
-				if (!empty($InfoFieldList[4]))
5552
-				{
5553
-					// can use SELECT request
5554
-					if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5555
-						$InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5556
-					}
5557
-
5558
-					// current object id can be use into filter
5559
-					if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5560
-						$InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5561
-					} else {
5562
-						$InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5563
-					}
5564
-					//We have to join on extrafield table
5565
-					if (strpos($InfoFieldList[4], 'extra')!==false)
5566
-					{
5567
-						$sql.= ' as main, '.MAIN_DB_PREFIX .$InfoFieldList[0].'_extrafields as extra';
5568
-						$sqlwhere.= ' WHERE extra.fk_object=main.'.$InfoFieldList[2]. ' AND '.$InfoFieldList[4];
5569
-					}
5570
-					else
5571
-					{
5572
-						$sqlwhere.= ' WHERE '.$InfoFieldList[4];
5573
-					}
5574
-				}
5575
-				else
5576
-				{
5577
-					$sqlwhere.= ' WHERE 1=1';
5578
-				}
5579
-				// Some tables may have field, some other not. For the moment we disable it.
5580
-				if (in_array($InfoFieldList[0],array('tablewithentity')))
5581
-				{
5582
-					$sqlwhere.= ' AND entity = '.$conf->entity;
5583
-				}
5584
-				$sql.=$sqlwhere;
5585
-				//print $sql;
1948
+    /**
1949
+     *  Change the payments terms
1950
+     *
1951
+     *  @param		int		$id		Id of new payment terms
1952
+     *  @return		int				>0 if OK, <0 if KO
1953
+     */
1954
+    function setPaymentTerms($id)
1955
+    {
1956
+        dol_syslog(get_class($this).'::setPaymentTerms('.$id.')');
1957
+        if ($this->statut >= 0 || $this->element == 'societe')
1958
+        {
1959
+            // TODO uniformize field name
1960
+            $fieldname = 'fk_cond_reglement';
1961
+            if ($this->element == 'societe') $fieldname = 'cond_reglement';
1962
+            if (get_class($this) == 'Fournisseur') $fieldname = 'cond_reglement_supplier';
5586 1963
 
5587
-				$sql .= ' ORDER BY ' . implode(', ', $fields_label);
1964
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1965
+            $sql .= ' SET '.$fieldname.' = '.$id;
1966
+            $sql .= ' WHERE rowid='.$this->id;
5588 1967
 
5589
-				dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
5590
-				$resql = $this->db->query($sql);
5591
-				if ($resql)
5592
-				{
5593
-					$out.='<option value="0">&nbsp;</option>';
5594
-					$num = $this->db->num_rows($resql);
5595
-					$i = 0;
5596
-					while ($i < $num)
5597
-					{
5598
-						$labeltoshow='';
5599
-						$obj = $this->db->fetch_object($resql);
5600
-
5601
-						// Several field into label (eq table:code|libelle:rowid)
5602
-						$notrans = false;
5603
-						$fields_label = explode('|',$InfoFieldList[1]);
5604
-						if (is_array($fields_label))
5605
-						{
5606
-							$notrans = true;
5607
-							foreach ($fields_label as $field_toshow)
5608
-							{
5609
-								$labeltoshow.= $obj->$field_toshow.' ';
5610
-							}
5611
-						}
5612
-						else
5613
-						{
5614
-							$labeltoshow=$obj->{$InfoFieldList[1]};
5615
-						}
5616
-						$labeltoshow=dol_trunc($labeltoshow,45);
5617
-
5618
-						if ($value == $obj->rowid)
5619
-						{
5620
-							foreach ($fields_label as $field_toshow)
5621
-							{
5622
-								$translabel=$langs->trans($obj->$field_toshow);
5623
-								if ($translabel!=$obj->$field_toshow) {
5624
-									$labeltoshow=dol_trunc($translabel,18).' ';
5625
-								}else {
5626
-									$labeltoshow=dol_trunc($obj->$field_toshow,18).' ';
5627
-								}
5628
-							}
5629
-							$out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5630
-						}
5631
-						else
5632
-						{
5633
-							if (! $notrans)
5634
-							{
5635
-								$translabel=$langs->trans($obj->{$InfoFieldList[1]});
5636
-								if ($translabel!=$obj->{$InfoFieldList[1]}) {
5637
-									$labeltoshow=dol_trunc($translabel,18);
5638
-								}
5639
-								else {
5640
-									$labeltoshow=dol_trunc($obj->{$InfoFieldList[1]},18);
5641
-								}
5642
-							}
5643
-							if (empty($labeltoshow)) $labeltoshow='(not defined)';
5644
-							if ($value==$obj->rowid)
5645
-							{
5646
-								$out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
1968
+            if ($this->db->query($sql))
1969
+            {
1970
+                $this->cond_reglement_id = $id;
1971
+                // for supplier
1972
+                if (get_class($this) == 'Fournisseur') $this->cond_reglement_supplier_id = $id;
1973
+                $this->cond_reglement = $id;	// for compatibility
1974
+                return 1;
1975
+            }
1976
+            else
1977
+            {
1978
+                dol_syslog(get_class($this).'::setPaymentTerms Erreur '.$sql.' - '.$this->db->error());
1979
+                $this->error=$this->db->error();
1980
+                return -1;
1981
+            }
1982
+        }
1983
+        else
1984
+        {
1985
+            dol_syslog(get_class($this).'::setPaymentTerms, status of the object is incompatible');
1986
+            $this->error='Status of the object is incompatible '.$this->statut;
1987
+            return -2;
1988
+        }
1989
+    }
1990
+
1991
+    /**
1992
+     *	Define delivery address
1993
+     *  @deprecated
1994
+     *
1995
+     *	@param      int		$id		Address id
1996
+     *	@return     int				<0 si ko, >0 si ok
1997
+     */
1998
+    function setDeliveryAddress($id)
1999
+    {
2000
+        $fieldname = 'fk_delivery_address';
2001
+        if ($this->element == 'delivery' || $this->element == 'shipping') $fieldname = 'fk_address';
2002
+
2003
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET ".$fieldname." = ".$id;
2004
+        $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
2005
+
2006
+        if ($this->db->query($sql))
2007
+        {
2008
+            $this->fk_delivery_address = $id;
2009
+            return 1;
2010
+        }
2011
+        else
2012
+        {
2013
+            $this->error=$this->db->error();
2014
+            dol_syslog(get_class($this).'::setDeliveryAddress Erreur '.$sql.' - '.$this->error);
2015
+            return -1;
2016
+        }
2017
+    }
2018
+
2019
+
2020
+    /**
2021
+     *  Change the shipping method
2022
+     *
2023
+     *  @param      int     $shipping_method_id     Id of shipping method
2024
+     *  @param      bool    $notrigger              false=launch triggers after, true=disable triggers
2025
+     *  @param      User	$userused               Object user
2026
+     *
2027
+     *  @return     int              1 if OK, 0 if KO
2028
+     */
2029
+    function setShippingMethod($shipping_method_id, $notrigger=false, $userused=null)
2030
+    {
2031
+        global $user;
2032
+
2033
+        if (empty($userused)) $userused=$user;
2034
+
2035
+        $error = 0;
2036
+
2037
+        if (! $this->table_element) {
2038
+            dol_syslog(get_class($this)."::setShippingMethod was called on objet with property table_element not defined",LOG_ERR);
2039
+            return -1;
2040
+        }
2041
+
2042
+        $this->db->begin();
2043
+
2044
+        if ($shipping_method_id<0) $shipping_method_id='NULL';
2045
+        dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')');
2046
+
2047
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2048
+        $sql.= " SET fk_shipping_method = ".$shipping_method_id;
2049
+        $sql.= " WHERE rowid=".$this->id;
2050
+        $resql = $this->db->query($sql);
2051
+        if (! $resql) {
2052
+            dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG);
2053
+            $this->error = $this->db->lasterror();
2054
+            $error++;
2055
+        } else {
2056
+            if (!$notrigger)
2057
+            {
2058
+                // Call trigger
2059
+                $this->context=array('shippingmethodupdate'=>1);
2060
+                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2061
+                if ($result < 0) $error++;
2062
+                // End call trigger
2063
+            }
2064
+        }
2065
+        if ($error)
2066
+        {
2067
+            $this->db->rollback();
2068
+            return -1;
2069
+        } else {
2070
+            $this->shipping_method_id = ($shipping_method_id=='NULL')?null:$shipping_method_id;
2071
+            $this->db->commit();
2072
+            return 1;
2073
+        }
2074
+    }
2075
+
2076
+
2077
+    /**
2078
+     *  Change the warehouse
2079
+     *
2080
+     *  @param      int     $warehouse_id     Id of warehouse
2081
+     *  @return     int              1 if OK, 0 if KO
2082
+     */
2083
+    function setWarehouse($warehouse_id)
2084
+    {
2085
+        if (! $this->table_element) {
2086
+            dol_syslog(get_class($this)."::setWarehouse was called on objet with property table_element not defined",LOG_ERR);
2087
+            return -1;
2088
+        }
2089
+        if ($warehouse_id<0) $warehouse_id='NULL';
2090
+        dol_syslog(get_class($this).'::setWarehouse('.$warehouse_id.')');
2091
+
2092
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2093
+        $sql.= " SET fk_warehouse = ".$warehouse_id;
2094
+        $sql.= " WHERE rowid=".$this->id;
2095
+
2096
+        if ($this->db->query($sql)) {
2097
+            $this->warehouse_id = ($warehouse_id=='NULL')?null:$warehouse_id;
2098
+            return 1;
2099
+        } else {
2100
+            dol_syslog(get_class($this).'::setWarehouse Error ', LOG_DEBUG);
2101
+            $this->error=$this->db->error();
2102
+            return 0;
2103
+        }
2104
+    }
2105
+
2106
+
2107
+    /**
2108
+     *		Set last model used by doc generator
2109
+     *
2110
+     *		@param		User	$user		User object that make change
2111
+     *		@param		string	$modelpdf	Modele name
2112
+     *		@return		int					<0 if KO, >0 if OK
2113
+     */
2114
+    function setDocModel($user, $modelpdf)
2115
+    {
2116
+        if (! $this->table_element)
2117
+        {
2118
+            dol_syslog(get_class($this)."::setDocModel was called on objet with property table_element not defined",LOG_ERR);
2119
+            return -1;
2120
+        }
2121
+
2122
+        $newmodelpdf=dol_trunc($modelpdf,255);
2123
+
2124
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2125
+        $sql.= " SET model_pdf = '".$this->db->escape($newmodelpdf)."'";
2126
+        $sql.= " WHERE rowid = ".$this->id;
2127
+        // if ($this->element == 'facture') $sql.= " AND fk_statut < 2";
2128
+        // if ($this->element == 'propal')  $sql.= " AND fk_statut = 0";
2129
+
2130
+        dol_syslog(get_class($this)."::setDocModel", LOG_DEBUG);
2131
+        $resql=$this->db->query($sql);
2132
+        if ($resql)
2133
+        {
2134
+            $this->modelpdf=$modelpdf;
2135
+            return 1;
2136
+        }
2137
+        else
2138
+        {
2139
+            dol_print_error($this->db);
2140
+            return 0;
2141
+        }
2142
+    }
2143
+
2144
+
2145
+    /**
2146
+     *  Change the bank account
2147
+     *
2148
+     *  @param		int		$fk_account		Id of bank account
2149
+     *  @param      bool    $notrigger      false=launch triggers after, true=disable triggers
2150
+     *  @param      User	$userused		Object user
2151
+     *  @return		int				1 if OK, 0 if KO
2152
+     */
2153
+    function setBankAccount($fk_account, $notrigger=false, $userused=null)
2154
+    {
2155
+        global $user;
2156
+
2157
+        if (empty($userused)) $userused=$user;
2158
+
2159
+        $error = 0;
2160
+
2161
+        if (! $this->table_element) {
2162
+            dol_syslog(get_class($this)."::setBankAccount was called on objet with property table_element not defined",LOG_ERR);
2163
+            return -1;
2164
+        }
2165
+        $this->db->begin();
2166
+
2167
+        if ($fk_account<0) $fk_account='NULL';
2168
+        dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')');
2169
+
2170
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2171
+        $sql.= " SET fk_account = ".$fk_account;
2172
+        $sql.= " WHERE rowid=".$this->id;
2173
+
2174
+        $resql = $this->db->query($sql);
2175
+        if (! $resql)
2176
+        {
2177
+            dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error());
2178
+            $this->error = $this->db->lasterror();
2179
+            $error++;
2180
+        }
2181
+        else
2182
+        {
2183
+            if (!$notrigger)
2184
+            {
2185
+                // Call trigger
2186
+                $this->context=array('bankaccountupdate'=>1);
2187
+                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2188
+                if ($result < 0) $error++;
2189
+                // End call trigger
2190
+            }
2191
+        }
2192
+        if ($error)
2193
+        {
2194
+            $this->db->rollback();
2195
+            return -1;
2196
+        }
2197
+        else
2198
+        {
2199
+            $this->fk_account = ($fk_account=='NULL')?null:$fk_account;
2200
+            $this->db->commit();
2201
+            return 1;
2202
+        }
2203
+    }
2204
+
2205
+
2206
+    // TODO: Move line related operations to CommonObjectLine?
2207
+
2208
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2209
+    /**
2210
+     *  Save a new position (field rang) for details lines.
2211
+     *  You can choose to set position for lines with already a position or lines without any position defined.
2212
+     *
2213
+     * 	@param		boolean		$renum			   True to renum all already ordered lines, false to renum only not already ordered lines.
2214
+     * 	@param		string		$rowidorder		   ASC or DESC
2215
+     * 	@param		boolean		$fk_parent_line    Table with fk_parent_line field or not
2216
+     * 	@return		int                            <0 if KO, >0 if OK
2217
+     */
2218
+    function line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
2219
+    {
2220
+        // phpcs:enable
2221
+        if (! $this->table_element_line)
2222
+        {
2223
+            dol_syslog(get_class($this)."::line_order was called on objet with property table_element_line not defined",LOG_ERR);
2224
+            return -1;
2225
+        }
2226
+        if (! $this->fk_element)
2227
+        {
2228
+            dol_syslog(get_class($this)."::line_order was called on objet with property fk_element not defined",LOG_ERR);
2229
+            return -1;
2230
+        }
2231
+
2232
+        // Count number of lines to reorder (according to choice $renum)
2233
+        $nl=0;
2234
+        $sql = 'SELECT count(rowid) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2235
+        $sql.= ' WHERE '.$this->fk_element.'='.$this->id;
2236
+        if (! $renum) $sql.= ' AND rang = 0';
2237
+        if ($renum) $sql.= ' AND rang <> 0';
2238
+
2239
+        dol_syslog(get_class($this)."::line_order", LOG_DEBUG);
2240
+        $resql = $this->db->query($sql);
2241
+        if ($resql)
2242
+        {
2243
+            $row = $this->db->fetch_row($resql);
2244
+            $nl = $row[0];
2245
+        }
2246
+        else dol_print_error($this->db);
2247
+        if ($nl > 0)
2248
+        {
2249
+            // The goal of this part is to reorder all lines, with all children lines sharing the same
2250
+            // counter that parents.
2251
+            $rows=array();
2252
+
2253
+            // We first search all lines that are parent lines (for multilevel details lines)
2254
+            $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2255
+            $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2256
+            if ($fk_parent_line) $sql.= ' AND fk_parent_line IS NULL';
2257
+            $sql.= ' ORDER BY rang ASC, rowid '.$rowidorder;
2258
+
2259
+            dol_syslog(get_class($this)."::line_order search all parent lines", LOG_DEBUG);
2260
+            $resql = $this->db->query($sql);
2261
+            if ($resql)
2262
+            {
2263
+                $i=0;
2264
+                $num = $this->db->num_rows($resql);
2265
+                while ($i < $num)
2266
+                {
2267
+                    $row = $this->db->fetch_row($resql);
2268
+                    $rows[] = $row[0];	// Add parent line into array rows
2269
+                    $childrens = $this->getChildrenOfLine($row[0]);
2270
+                    if (! empty($childrens))
2271
+                    {
2272
+                        foreach($childrens as $child)
2273
+                        {
2274
+                            array_push($rows, $child);
2275
+                        }
2276
+                    }
2277
+                    $i++;
2278
+                }
2279
+
2280
+                // Now we set a new number for each lines (parent and children with children included into parent tree)
2281
+                if (! empty($rows))
2282
+                {
2283
+                    foreach($rows as $key => $row)
2284
+                    {
2285
+                        $this->updateRangOfLine($row, ($key+1));
2286
+                    }
2287
+                }
2288
+            }
2289
+            else
2290
+            {
2291
+                dol_print_error($this->db);
2292
+            }
2293
+        }
2294
+        return 1;
2295
+    }
2296
+
2297
+    /**
2298
+     * 	Get children of line
2299
+     *
2300
+     * 	@param	int		$id		Id of parent line
2301
+     * 	@return	array			Array with list of children lines id
2302
+     */
2303
+    function getChildrenOfLine($id)
2304
+    {
2305
+        $rows=array();
2306
+
2307
+        $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2308
+        $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2309
+        $sql.= ' AND fk_parent_line = '.$id;
2310
+        $sql.= ' ORDER BY rang ASC';
2311
+
2312
+        dol_syslog(get_class($this)."::getChildrenOfLine search children lines for line ".$id."", LOG_DEBUG);
2313
+        $resql = $this->db->query($sql);
2314
+        if ($resql)
2315
+        {
2316
+            $i=0;
2317
+            $num = $this->db->num_rows($resql);
2318
+            while ($i < $num)
2319
+            {
2320
+                $row = $this->db->fetch_row($resql);
2321
+                $rows[$i] = $row[0];
2322
+                $i++;
2323
+            }
2324
+        }
2325
+
2326
+        return $rows;
2327
+    }
2328
+
2329
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2330
+    /**
2331
+     * 	Update a line to have a lower rank
2332
+     *
2333
+     * 	@param 	int			$rowid				Id of line
2334
+     * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2335
+     * 	@return	void
2336
+     */
2337
+    function line_up($rowid, $fk_parent_line=true)
2338
+    {
2339
+        // phpcs:enable
2340
+        $this->line_order(false, 'ASC', $fk_parent_line);
2341
+
2342
+        // Get rang of line
2343
+        $rang = $this->getRangOfLine($rowid);
2344
+
2345
+        // Update position of line
2346
+        $this->updateLineUp($rowid, $rang);
2347
+    }
2348
+
2349
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2350
+    /**
2351
+     * 	Update a line to have a higher rank
2352
+     *
2353
+     * 	@param	int			$rowid				Id of line
2354
+     * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2355
+     * 	@return	void
2356
+     */
2357
+    function line_down($rowid, $fk_parent_line=true)
2358
+    {
2359
+        // phpcs:enable
2360
+        $this->line_order(false, 'ASC', $fk_parent_line);
2361
+
2362
+        // Get rang of line
2363
+        $rang = $this->getRangOfLine($rowid);
2364
+
2365
+        // Get max value for rang
2366
+        $max = $this->line_max();
2367
+
2368
+        // Update position of line
2369
+        $this->updateLineDown($rowid, $rang, $max);
2370
+    }
2371
+
2372
+    /**
2373
+     * 	Update position of line (rang)
2374
+     *
2375
+     * 	@param	int		$rowid		Id of line
2376
+     * 	@param	int		$rang		Position
2377
+     * 	@return	void
2378
+     */
2379
+    function updateRangOfLine($rowid,$rang)
2380
+    {
2381
+        $fieldposition = 'rang';
2382
+        if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2383
+
2384
+        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2385
+        $sql.= ' WHERE rowid = '.$rowid;
2386
+
2387
+        dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
2388
+        if (! $this->db->query($sql))
2389
+        {
2390
+            dol_print_error($this->db);
2391
+        }
2392
+    }
2393
+
2394
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2395
+    /**
2396
+     * 	Update position of line with ajax (rang)
2397
+     *
2398
+     * 	@param	array	$rows	Array of rows
2399
+     * 	@return	void
2400
+     */
2401
+    function line_ajaxorder($rows)
2402
+    {
2403
+        // phpcs:enable
2404
+        $num = count($rows);
2405
+        for ($i = 0 ; $i < $num ; $i++)
2406
+        {
2407
+            $this->updateRangOfLine($rows[$i], ($i+1));
2408
+        }
2409
+    }
2410
+
2411
+    /**
2412
+     * 	Update position of line up (rang)
2413
+     *
2414
+     * 	@param	int		$rowid		Id of line
2415
+     * 	@param	int		$rang		Position
2416
+     * 	@return	void
2417
+     */
2418
+    function updateLineUp($rowid,$rang)
2419
+    {
2420
+        if ($rang > 1)
2421
+        {
2422
+            $fieldposition = 'rang';
2423
+            if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2424
+
2425
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang ;
2426
+            $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2427
+            $sql.= ' AND rang = '.($rang - 1);
2428
+            if ($this->db->query($sql) )
2429
+            {
2430
+                $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang - 1);
2431
+                $sql.= ' WHERE rowid = '.$rowid;
2432
+                if (! $this->db->query($sql) )
2433
+                {
2434
+                    dol_print_error($this->db);
2435
+                }
2436
+            }
2437
+            else
2438
+            {
2439
+                dol_print_error($this->db);
2440
+            }
2441
+        }
2442
+    }
2443
+
2444
+    /**
2445
+     * 	Update position of line down (rang)
2446
+     *
2447
+     * 	@param	int		$rowid		Id of line
2448
+     * 	@param	int		$rang		Position
2449
+     * 	@param	int		$max		Max
2450
+     * 	@return	void
2451
+     */
2452
+    function updateLineDown($rowid,$rang,$max)
2453
+    {
2454
+        if ($rang < $max)
2455
+        {
2456
+            $fieldposition = 'rang';
2457
+            if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2458
+
2459
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2460
+            $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2461
+            $sql.= ' AND rang = '.($rang+1);
2462
+            if ($this->db->query($sql) )
2463
+            {
2464
+                $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang+1);
2465
+                $sql.= ' WHERE rowid = '.$rowid;
2466
+                if (! $this->db->query($sql) )
2467
+                {
2468
+                    dol_print_error($this->db);
2469
+                }
2470
+            }
2471
+            else
2472
+            {
2473
+                dol_print_error($this->db);
2474
+            }
2475
+        }
2476
+    }
2477
+
2478
+    /**
2479
+     * 	Get position of line (rang)
2480
+     *
2481
+     * 	@param		int		$rowid		Id of line
2482
+     *  @return		int     			Value of rang in table of lines
2483
+     */
2484
+    function getRangOfLine($rowid)
2485
+    {
2486
+        $sql = 'SELECT rang FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2487
+        $sql.= ' WHERE rowid ='.$rowid;
2488
+
2489
+        dol_syslog(get_class($this)."::getRangOfLine", LOG_DEBUG);
2490
+        $resql = $this->db->query($sql);
2491
+        if ($resql)
2492
+        {
2493
+            $row = $this->db->fetch_row($resql);
2494
+            return $row[0];
2495
+        }
2496
+    }
2497
+
2498
+    /**
2499
+     * 	Get rowid of the line relative to its position
2500
+     *
2501
+     * 	@param		int		$rang		Rang value
2502
+     *  @return     int     			Rowid of the line
2503
+     */
2504
+    function getIdOfLine($rang)
2505
+    {
2506
+        $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2507
+        $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2508
+        $sql.= ' AND rang = '.$rang;
2509
+        $resql = $this->db->query($sql);
2510
+        if ($resql)
2511
+        {
2512
+            $row = $this->db->fetch_row($resql);
2513
+            return $row[0];
2514
+        }
2515
+    }
2516
+
2517
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2518
+    /**
2519
+     * 	Get max value used for position of line (rang)
2520
+     *
2521
+     * 	@param		int		$fk_parent_line		Parent line id
2522
+     *  @return     int  			   			Max value of rang in table of lines
2523
+     */
2524
+    function line_max($fk_parent_line=0)
2525
+    {
2526
+        // phpcs:enable
2527
+        // Search the last rang with fk_parent_line
2528
+        if ($fk_parent_line)
2529
+        {
2530
+            $sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2531
+            $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2532
+            $sql.= ' AND fk_parent_line = '.$fk_parent_line;
2533
+
2534
+            dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2535
+            $resql = $this->db->query($sql);
2536
+            if ($resql)
2537
+            {
2538
+                $row = $this->db->fetch_row($resql);
2539
+                if (! empty($row[0]))
2540
+                {
2541
+                    return $row[0];
2542
+                }
2543
+                else
2544
+                {
2545
+                    return $this->getRangOfLine($fk_parent_line);
2546
+                }
2547
+            }
2548
+        }
2549
+        // If not, search the last rang of element
2550
+        else
2551
+        {
2552
+            $sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2553
+            $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2554
+
2555
+            dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2556
+            $resql = $this->db->query($sql);
2557
+            if ($resql)
2558
+            {
2559
+                $row = $this->db->fetch_row($resql);
2560
+                return $row[0];
2561
+            }
2562
+        }
2563
+    }
2564
+
2565
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2566
+    /**
2567
+     *  Update external ref of element
2568
+     *
2569
+     *  @param      string		$ref_ext	Update field ref_ext
2570
+     *  @return     int      		   		<0 if KO, >0 if OK
2571
+     */
2572
+    function update_ref_ext($ref_ext)
2573
+    {
2574
+        // phpcs:enable
2575
+        if (! $this->table_element)
2576
+        {
2577
+            dol_syslog(get_class($this)."::update_ref_ext was called on objet with property table_element not defined", LOG_ERR);
2578
+            return -1;
2579
+        }
2580
+
2581
+        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2582
+        $sql.= " SET ref_ext = '".$this->db->escape($ref_ext)."'";
2583
+        $sql.= " WHERE ".(isset($this->table_rowid)?$this->table_rowid:'rowid')." = ". $this->id;
2584
+
2585
+        dol_syslog(get_class($this)."::update_ref_ext", LOG_DEBUG);
2586
+        if ($this->db->query($sql))
2587
+        {
2588
+            $this->ref_ext = $ref_ext;
2589
+            return 1;
2590
+        }
2591
+        else
2592
+        {
2593
+            $this->error=$this->db->error();
2594
+            return -1;
2595
+        }
2596
+    }
2597
+
2598
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2599
+    /**
2600
+     *  Update note of element
2601
+     *
2602
+     *  @param      string		$note		New value for note
2603
+     *  @param		string		$suffix		'', '_public' or '_private'
2604
+     *  @return     int      		   		<0 if KO, >0 if OK
2605
+     */
2606
+    function update_note($note, $suffix='')
2607
+    {
2608
+        // phpcs:enable
2609
+        global $user;
2610
+
2611
+        if (! $this->table_element)
2612
+        {
2613
+            $this->error='update_note was called on objet with property table_element not defined';
2614
+            dol_syslog(get_class($this)."::update_note was called on objet with property table_element not defined", LOG_ERR);
2615
+            return -1;
2616
+        }
2617
+        if (! in_array($suffix,array('','_public','_private')))
2618
+        {
2619
+            $this->error='update_note Parameter suffix must be empty, \'_private\' or \'_public\'';
2620
+            dol_syslog(get_class($this)."::update_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR);
2621
+            return -2;
2622
+        }
2623
+        // Special cas
2624
+        //var_dump($this->table_element);exit;
2625
+        if ($this->table_element == 'product') $suffix='';
2626
+
2627
+        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2628
+        $sql.= " SET note".$suffix." = ".(!empty($note)?("'".$this->db->escape($note)."'"):"NULL");
2629
+        $sql.= " ,".(in_array($this->table_element, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))?"fk_user_mod":"fk_user_modif")." = ".$user->id;
2630
+        $sql.= " WHERE rowid =". $this->id;
2631
+
2632
+        dol_syslog(get_class($this)."::update_note", LOG_DEBUG);
2633
+        if ($this->db->query($sql))
2634
+        {
2635
+            if ($suffix == '_public') $this->note_public = $note;
2636
+            else if ($suffix == '_private') $this->note_private = $note;
2637
+            else
2638
+            {
2639
+                $this->note = $note;      // deprecated
2640
+                $this->note_private = $note;
2641
+            }
2642
+            return 1;
2643
+        }
2644
+        else
2645
+        {
2646
+            $this->error=$this->db->lasterror();
2647
+            return -1;
2648
+        }
2649
+    }
2650
+
2651
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2652
+    /**
2653
+     * 	Update public note (kept for backward compatibility)
2654
+     *
2655
+     * @param      string		$note		New value for note
2656
+     * @return     int      		   		<0 if KO, >0 if OK
2657
+     * @deprecated
2658
+     * @see update_note()
2659
+     */
2660
+    function update_note_public($note)
2661
+    {
2662
+        // phpcs:enable
2663
+        return $this->update_note($note,'_public');
2664
+    }
2665
+
2666
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2667
+    /**
2668
+     *	Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
2669
+     *  Must be called at end of methods addline or updateline.
2670
+     *
2671
+     *	@param	int		$exclspec          	>0 = Exclude special product (product_type=9)
2672
+     *  @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
2673
+     *  @param	int		$nodatabaseupdate	1=Do not update database. Update only properties of object.
2674
+     *  @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.
2675
+     *	@return	int    			           	<0 if KO, >0 if OK
2676
+     */
2677
+    function update_price($exclspec=0,$roundingadjust='none',$nodatabaseupdate=0,$seller=null)
2678
+    {
2679
+        // phpcs:enable
2680
+        global $conf, $hookmanager, $action;
2681
+
2682
+        // Some external module want no update price after a trigger because they have another method to calculate the total (ex: with an extrafield)
2683
+        $MODULE = "";
2684
+        if ($this->element == 'propal')
2685
+            $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_PROPOSAL";
2686
+        elseif ($this->element == 'order')
2687
+            $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER";
2688
+        elseif ($this->element == 'facture')
2689
+            $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE";
2690
+        elseif ($this->element == 'facture_fourn')
2691
+            $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE";
2692
+        elseif ($this->element == 'order_supplier')
2693
+            $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER";
2694
+        elseif ($this->element == 'supplier_proposal')
2695
+            $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_PROPOSAL";
2696
+
2697
+        if (! empty($MODULE)) {
2698
+            if (! empty($conf->global->$MODULE)) {
2699
+                $modsactivated = explode(',', $conf->global->$MODULE);
2700
+                foreach ($modsactivated as $mod) {
2701
+                    if ($conf->$mod->enabled)
2702
+                        return 1; // update was disabled by specific setup
2703
+                }
2704
+            }
2705
+        }
2706
+
2707
+        include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2708
+
2709
+        if ($roundingadjust == '-1') $roundingadjust='auto';	// For backward compatibility
2710
+
2711
+        $forcedroundingmode=$roundingadjust;
2712
+        if ($forcedroundingmode == 'auto' && isset($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)) $forcedroundingmode=$conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND;
2713
+        elseif ($forcedroundingmode == 'auto') $forcedroundingmode='0';
2714
+
2715
+        $error=0;
2716
+
2717
+        $multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1;
2718
+
2719
+        // Define constants to find lines to sum
2720
+        $fieldtva='total_tva';
2721
+        $fieldlocaltax1='total_localtax1';
2722
+        $fieldlocaltax2='total_localtax2';
2723
+        $fieldup='subprice';
2724
+        if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier')
2725
+        {
2726
+            $fieldtva='tva';
2727
+            $fieldup='pu_ht';
2728
+        }
2729
+        if ($this->element == 'expensereport')
2730
+        {
2731
+            $fieldup='value_unit';
2732
+        }
2733
+
2734
+        $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,';
2735
+        $sql.= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type';
2736
+            if ($this->table_element_line == 'facturedet') $sql.= ', situation_percent';
2737
+            $sql.= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
2738
+        $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2739
+        $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2740
+        if ($exclspec)
2741
+        {
2742
+            $product_field='product_type';
2743
+            if ($this->table_element_line == 'contratdet') $product_field='';    // contratdet table has no product_type field
2744
+            if ($product_field) $sql.= ' AND '.$product_field.' <> 9';
2745
+        }
2746
+        $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
2747
+
2748
+        dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2749
+        $resql = $this->db->query($sql);
2750
+        if ($resql)
2751
+        {
2752
+            $this->total_ht  = 0;
2753
+            $this->total_tva = 0;
2754
+            $this->total_localtax1 = 0;
2755
+            $this->total_localtax2 = 0;
2756
+            $this->total_ttc = 0;
2757
+            $total_ht_by_vats  = array();
2758
+            $total_tva_by_vats = array();
2759
+            $total_ttc_by_vats = array();
2760
+            $this->multicurrency_total_ht	= 0;
2761
+            $this->multicurrency_total_tva	= 0;
2762
+            $this->multicurrency_total_ttc	= 0;
2763
+
2764
+            $num = $this->db->num_rows($resql);
2765
+            $i = 0;
2766
+            while ($i < $num)
2767
+            {
2768
+                $obj = $this->db->fetch_object($resql);
2769
+
2770
+                // Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none'
2771
+                $parameters=array('fk_element' => $obj->rowid);
2772
+                $reshook = $hookmanager->executeHooks('changeRoundingMode', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2773
+
2774
+                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'
2775
+                {
2776
+                    $localtax_array=array($obj->localtax1_type,$obj->localtax1_tx,$obj->localtax2_type,$obj->localtax2_tx);
2777
+                    $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);
2778
+                    $diff=price2num($tmpcal[1] - $obj->total_tva, 'MT', 1);
2779
+                    if ($diff)
2780
+                    {
2781
+                        $sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".$tmpcal[1].", total_ttc = ".$tmpcal[2]." WHERE rowid = ".$obj->rowid;
2782
+                        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);
2783
+                                $resqlfix=$this->db->query($sqlfix);
2784
+                                if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2785
+                                $obj->total_tva = $tmpcal[1];
2786
+                                $obj->total_ttc = $tmpcal[2];
2787
+                        //
2788
+                    }
2789
+                }
2790
+
2791
+                $this->total_ht        += $obj->total_ht;		// The field visible at end of line detail
2792
+                $this->total_tva       += $obj->total_tva;
2793
+                $this->total_localtax1 += $obj->total_localtax1;
2794
+                $this->total_localtax2 += $obj->total_localtax2;
2795
+                $this->total_ttc       += $obj->total_ttc;
2796
+                $this->multicurrency_total_ht        += $obj->multicurrency_total_ht;		// The field visible at end of line detail
2797
+                $this->multicurrency_total_tva       += $obj->multicurrency_total_tva;
2798
+                $this->multicurrency_total_ttc       += $obj->multicurrency_total_ttc;
2799
+
2800
+                if (! isset($total_ht_by_vats[$obj->vatrate]))  $total_ht_by_vats[$obj->vatrate]=0;
2801
+                if (! isset($total_tva_by_vats[$obj->vatrate])) $total_tva_by_vats[$obj->vatrate]=0;
2802
+                if (! isset($total_ttc_by_vats[$obj->vatrate])) $total_ttc_by_vats[$obj->vatrate]=0;
2803
+                $total_ht_by_vats[$obj->vatrate]  += $obj->total_ht;
2804
+                $total_tva_by_vats[$obj->vatrate] += $obj->total_tva;
2805
+                $total_ttc_by_vats[$obj->vatrate] += $obj->total_ttc;
2806
+
2807
+                if ($forcedroundingmode == '1')	// Check if we need adjustement onto line for vat. TODO This works on the company currency but not on multicurrency
2808
+                {
2809
+                    $tmpvat=price2num($total_ht_by_vats[$obj->vatrate] * $obj->vatrate / 100, 'MT', 1);
2810
+                    $diff=price2num($total_tva_by_vats[$obj->vatrate]-$tmpvat, 'MT', 1);
2811
+                    //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";
2812
+                    if ($diff)
2813
+                    {
2814
+                        if (abs($diff) > 0.1) { dol_syslog('A rounding difference was detected into TOTAL but is too high to be corrected', LOG_WARNING); exit; }
2815
+                        $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;
2816
+                        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);
2817
+                                $resqlfix=$this->db->query($sqlfix);
2818
+                                if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2819
+                                $this->total_tva -= $diff;
2820
+                                $this->total_ttc -= $diff;
2821
+                                $total_tva_by_vats[$obj->vatrate] -= $diff;
2822
+                                $total_ttc_by_vats[$obj->vatrate] -= $diff;
2823
+                    }
2824
+                }
2825
+
2826
+                $i++;
2827
+            }
2828
+
2829
+            // Add revenue stamp to total
2830
+            $this->total_ttc       			+= isset($this->revenuestamp)?$this->revenuestamp:0;
2831
+            $this->multicurrency_total_ttc  += isset($this->revenuestamp)?($this->revenuestamp * $multicurrency_tx):0;
2832
+
2833
+            // Situations totals
2834
+            if ($this->situation_cycle_ref && $this->situation_counter > 1 && method_exists($this, 'get_prev_sits') && $this->type != $this::TYPE_CREDIT_NOTE )
2835
+            {
2836
+                $prev_sits = $this->get_prev_sits();
2837
+
2838
+                foreach ($prev_sits as $sit) {				// $sit is an object Facture loaded with a fetch.
2839
+                    $this->total_ht -= $sit->total_ht;
2840
+                    $this->total_tva -= $sit->total_tva;
2841
+                    $this->total_localtax1 -= $sit->total_localtax1;
2842
+                    $this->total_localtax2 -= $sit->total_localtax2;
2843
+                    $this->total_ttc -= $sit->total_ttc;
2844
+                    $this->multicurrency_total_ht -= $sit->multicurrency_total_ht;
2845
+                    $this->multicurrency_total_tva -= $sit->multicurrency_total_tva;
2846
+                    $this->multicurrency_total_ttc -= $sit->multicurrency_total_ttc;
2847
+                }
2848
+            }
2849
+
2850
+            $this->db->free($resql);
2851
+
2852
+            // Now update global field total_ht, total_ttc and tva
2853
+            $fieldht='total_ht';
2854
+            $fieldtva='tva';
2855
+            $fieldlocaltax1='localtax1';
2856
+            $fieldlocaltax2='localtax2';
2857
+            $fieldttc='total_ttc';
2858
+            // Specific code for backward compatibility with old field names
2859
+            if ($this->element == 'facture' || $this->element == 'facturerec')             $fieldht='total';
2860
+            if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva='total_tva';
2861
+            if ($this->element == 'propal')                                                $fieldttc='total';
2862
+            if ($this->element == 'expensereport')                                         $fieldtva='total_tva';
2863
+            if ($this->element == 'supplier_proposal')                                     $fieldttc='total';
2864
+
2865
+            if (empty($nodatabaseupdate))
2866
+            {
2867
+                $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET';
2868
+                $sql .= " ".$fieldht."='".price2num($this->total_ht)."',";
2869
+                $sql .= " ".$fieldtva."='".price2num($this->total_tva)."',";
2870
+                $sql .= " ".$fieldlocaltax1."='".price2num($this->total_localtax1)."',";
2871
+                $sql .= " ".$fieldlocaltax2."='".price2num($this->total_localtax2)."',";
2872
+                $sql .= " ".$fieldttc."='".price2num($this->total_ttc)."'";
2873
+                        $sql .= ", multicurrency_total_ht='".price2num($this->multicurrency_total_ht, 'MT', 1)."'";
2874
+                        $sql .= ", multicurrency_total_tva='".price2num($this->multicurrency_total_tva, 'MT', 1)."'";
2875
+                        $sql .= ", multicurrency_total_ttc='".price2num($this->multicurrency_total_ttc, 'MT', 1)."'";
2876
+                $sql .= ' WHERE rowid = '.$this->id;
2877
+
2878
+
2879
+                dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2880
+                $resql=$this->db->query($sql);
2881
+                if (! $resql)
2882
+                {
2883
+                    $error++;
2884
+                    $this->error=$this->db->lasterror();
2885
+                    $this->errors[]=$this->db->lasterror();
2886
+                }
2887
+            }
2888
+
2889
+            if (! $error)
2890
+            {
2891
+                return 1;
2892
+            }
2893
+            else
2894
+            {
2895
+                return -1;
2896
+            }
2897
+        }
2898
+        else
2899
+        {
2900
+            dol_print_error($this->db,'Bad request in update_price');
2901
+            return -1;
2902
+        }
2903
+    }
2904
+
2905
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2906
+    /**
2907
+     *	Add objects linked in llx_element_element.
2908
+     *
2909
+     *	@param		string	$origin		Linked element type
2910
+     *	@param		int		$origin_id	Linked element id
2911
+     *	@return		int					<=0 if KO, >0 if OK
2912
+     *	@see		fetchObjectLinked, updateObjectLinked, deleteObjectLinked
2913
+     */
2914
+    function add_object_linked($origin=null, $origin_id=null)
2915
+    {
2916
+        // phpcs:enable
2917
+        $origin = (! empty($origin) ? $origin : $this->origin);
2918
+        $origin_id = (! empty($origin_id) ? $origin_id : $this->origin_id);
2919
+
2920
+        // Special case
2921
+        if ($origin == 'order') $origin='commande';
2922
+        if ($origin == 'invoice') $origin='facture';
2923
+        if ($origin == 'invoice_template') $origin='facturerec';
2924
+        if ($origin == 'supplierorder') $origin='order_supplier';
2925
+        $this->db->begin();
2926
+
2927
+        $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_element (";
2928
+        $sql.= "fk_source";
2929
+        $sql.= ", sourcetype";
2930
+        $sql.= ", fk_target";
2931
+        $sql.= ", targettype";
2932
+        $sql.= ") VALUES (";
2933
+        $sql.= $origin_id;
2934
+        $sql.= ", '".$this->db->escape($origin)."'";
2935
+        $sql.= ", ".$this->id;
2936
+        $sql.= ", '".$this->db->escape($this->element)."'";
2937
+        $sql.= ")";
2938
+
2939
+        dol_syslog(get_class($this)."::add_object_linked", LOG_DEBUG);
2940
+        if ($this->db->query($sql))
2941
+            {
2942
+                $this->db->commit();
2943
+                return 1;
2944
+            }
2945
+            else
2946
+            {
2947
+                $this->error=$this->db->lasterror();
2948
+                $this->db->rollback();
2949
+                return 0;
2950
+            }
2951
+    }
2952
+
2953
+    /**
2954
+     *	Fetch array of objects linked to current object (object of enabled modules only). Links are loaded into
2955
+     *		this->linkedObjectsIds array and
2956
+     *		this->linkedObjects array if $loadalsoobjects = 1
2957
+     *  Possible usage for parameters:
2958
+     *  - all parameters empty -> we look all link to current object (current object can be source or target)
2959
+     *  - source id+type -> will get target list linked to source
2960
+     *  - target id+type -> will get source list linked to target
2961
+     *  - source id+type + target type -> will get target list of the type
2962
+     *  - target id+type + target source -> will get source list of the type
2963
+     *
2964
+     *	@param	int		$sourceid			Object source id (if not defined, id of object)
2965
+     *	@param  string	$sourcetype			Object source type (if not defined, element name of object)
2966
+     *	@param  int		$targetid			Object target id (if not defined, id of object)
2967
+     *	@param  string	$targettype			Object target type (if not defined, elemennt name of object)
2968
+     *	@param  string	$clause				'OR' or 'AND' clause used when both source id and target id are provided
2969
+     *  @param  int		$alsosametype		0=Return only links to object that differs from source type. 1=Include also link to objects of same type.
2970
+     *  @param  string	$orderby			SQL 'ORDER BY' clause
2971
+     *  @param	int		$loadalsoobjects	Load also array this->linkedObjects (Use 0 to increase performances)
2972
+     *	@return int							<0 if KO, >0 if OK
2973
+     *  @see	add_object_linked, updateObjectLinked, deleteObjectLinked
2974
+     */
2975
+    function fetchObjectLinked($sourceid=null,$sourcetype='',$targetid=null,$targettype='',$clause='OR',$alsosametype=1,$orderby='sourcetype',$loadalsoobjects=1)
2976
+    {
2977
+        global $conf;
2978
+
2979
+        $this->linkedObjectsIds=array();
2980
+        $this->linkedObjects=array();
2981
+
2982
+        $justsource=false;
2983
+        $justtarget=false;
2984
+        $withtargettype=false;
2985
+        $withsourcetype=false;
2986
+
2987
+        if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid))
2988
+        {
2989
+            $justsource=true;  // the source (id and type) is a search criteria
2990
+            if (! empty($targettype)) $withtargettype=true;
2991
+        }
2992
+        if (! empty($targetid) && ! empty($targettype) && empty($sourceid))
2993
+        {
2994
+            $justtarget=true;  // the target (id and type) is a search criteria
2995
+            if (! empty($sourcetype)) $withsourcetype=true;
2996
+        }
2997
+
2998
+        $sourceid = (! empty($sourceid) ? $sourceid : $this->id);
2999
+        $targetid = (! empty($targetid) ? $targetid : $this->id);
3000
+        $sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
3001
+        $targettype = (! empty($targettype) ? $targettype : $this->element);
3002
+
3003
+        /*if (empty($sourceid) && empty($targetid))
3004
+		 {
3005
+		 dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR);
3006
+		 return -1;
3007
+		 }*/
3008
+
3009
+        // Links between objects are stored in table element_element
3010
+        $sql = 'SELECT rowid, fk_source, sourcetype, fk_target, targettype';
3011
+        $sql.= ' FROM '.MAIN_DB_PREFIX.'element_element';
3012
+        $sql.= " WHERE ";
3013
+        if ($justsource || $justtarget)
3014
+        {
3015
+            if ($justsource)
3016
+            {
3017
+                $sql.= "fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."'";
3018
+                if ($withtargettype) $sql.= " AND targettype = '".$targettype."'";
3019
+            }
3020
+            else if ($justtarget)
3021
+            {
3022
+                $sql.= "fk_target = ".$targetid." AND targettype = '".$targettype."'";
3023
+                if ($withsourcetype) $sql.= " AND sourcetype = '".$sourcetype."'";
3024
+            }
3025
+        }
3026
+        else
3027
+        {
3028
+            $sql.= "(fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."')";
3029
+            $sql.= " ".$clause." (fk_target = ".$targetid." AND targettype = '".$targettype."')";
3030
+        }
3031
+        $sql .= ' ORDER BY '.$orderby;
3032
+
3033
+        dol_syslog(get_class($this)."::fetchObjectLink", LOG_DEBUG);
3034
+        $resql = $this->db->query($sql);
3035
+        if ($resql)
3036
+        {
3037
+            $num = $this->db->num_rows($resql);
3038
+            $i = 0;
3039
+            while ($i < $num)
3040
+            {
3041
+                $obj = $this->db->fetch_object($resql);
3042
+                if ($justsource || $justtarget)
3043
+                {
3044
+                    if ($justsource)
3045
+                    {
3046
+                        $this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
3047
+                    }
3048
+                    else if ($justtarget)
3049
+                    {
3050
+                        $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
3051
+                    }
3052
+                }
3053
+                else
3054
+                {
3055
+                    if ($obj->fk_source == $sourceid && $obj->sourcetype == $sourcetype)
3056
+                    {
3057
+                        $this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
3058
+                    }
3059
+                    if ($obj->fk_target == $targetid && $obj->targettype == $targettype)
3060
+                    {
3061
+                        $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
3062
+                    }
3063
+                }
3064
+                $i++;
3065
+            }
3066
+
3067
+            if (! empty($this->linkedObjectsIds))
3068
+            {
3069
+                $tmparray = $this->linkedObjectsIds;
3070
+                foreach($tmparray as $objecttype => $objectids)       // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...)
3071
+                {
3072
+                    // Parse element/subelement (ex: project_task, cabinetmed_consultation, ...)
3073
+                    $module = $element = $subelement = $objecttype;
3074
+                    if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier'
3075
+                        && preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
3076
+                    {
3077
+                        $module = $element = $regs[1];
3078
+                        $subelement = $regs[2];
3079
+                    }
3080
+
3081
+                    $classpath = $element.'/class';
3082
+                    // To work with non standard classpath or module name
3083
+                    if ($objecttype == 'facture')			{
3084
+                        $classpath = 'compta/facture/class';
3085
+                    }
3086
+                    else if ($objecttype == 'facturerec')			{
3087
+                        $classpath = 'compta/facture/class'; $module = 'facture';
3088
+                    }
3089
+                    else if ($objecttype == 'propal')			{
3090
+                        $classpath = 'comm/propal/class';
3091
+                    }
3092
+                    else if ($objecttype == 'supplier_proposal')			{
3093
+                        $classpath = 'supplier_proposal/class';
3094
+                    }
3095
+                    else if ($objecttype == 'shipping')			{
3096
+                        $classpath = 'expedition/class'; $subelement = 'expedition'; $module = 'expedition_bon';
3097
+                    }
3098
+                    else if ($objecttype == 'delivery')			{
3099
+                        $classpath = 'livraison/class'; $subelement = 'livraison'; $module = 'livraison_bon';
3100
+                    }
3101
+                    else if ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier')	{
3102
+                        $classpath = 'fourn/class'; $module = 'fournisseur';
3103
+                    }
3104
+                    else if ($objecttype == 'fichinter')			{
3105
+                        $classpath = 'fichinter/class'; $subelement = 'fichinter'; $module = 'ficheinter';
3106
+                    }
3107
+                    else if ($objecttype == 'subscription')			{
3108
+                        $classpath = 'adherents/class'; $module = 'adherent';
3109
+                    }
3110
+
3111
+                    // Set classfile
3112
+                    $classfile = strtolower($subelement); $classname = ucfirst($subelement);
3113
+
3114
+                    if ($objecttype == 'order') {
3115
+                        $classfile = 'commande'; $classname = 'Commande';
3116
+                    }
3117
+                    else if ($objecttype == 'invoice_supplier') {
3118
+                        $classfile = 'fournisseur.facture'; $classname = 'FactureFournisseur';
3119
+                    }
3120
+                    else if ($objecttype == 'order_supplier')   {
3121
+                        $classfile = 'fournisseur.commande'; $classname = 'CommandeFournisseur';
3122
+                    }
3123
+                    else if ($objecttype == 'supplier_proposal')   {
3124
+                        $classfile = 'supplier_proposal'; $classname = 'SupplierProposal';
3125
+                    }
3126
+                    else if ($objecttype == 'facturerec')   {
3127
+                        $classfile = 'facture-rec'; $classname = 'FactureRec';
3128
+                    }
3129
+                    else if ($objecttype == 'subscription')   {
3130
+                        $classfile = 'subscription'; $classname = 'Subscription';
3131
+                    }
3132
+
3133
+                    // Here $module, $classfile and $classname are set
3134
+                    if ($conf->$module->enabled && (($element != $this->element) || $alsosametype))
3135
+                    {
3136
+                        if ($loadalsoobjects)
3137
+                        {
3138
+                            dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
3139
+                            //print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname);
3140
+                            if (class_exists($classname))
3141
+                            {
3142
+                                foreach($objectids as $i => $objectid)	// $i is rowid into llx_element_element
3143
+                                {
3144
+                                    $object = new $classname($this->db);
3145
+                                    $ret = $object->fetch($objectid);
3146
+                                    if ($ret >= 0)
3147
+                                    {
3148
+                                        $this->linkedObjects[$objecttype][$i] = $object;
3149
+                                    }
3150
+                                }
3151
+                            }
3152
+                        }
3153
+                    }
3154
+                    else
3155
+                    {
3156
+                        unset($this->linkedObjectsIds[$objecttype]);
3157
+                    }
3158
+                }
3159
+            }
3160
+            return 1;
3161
+        }
3162
+        else
3163
+        {
3164
+            dol_print_error($this->db);
3165
+            return -1;
3166
+        }
3167
+    }
3168
+
3169
+    /**
3170
+     *	Update object linked of a current object
3171
+     *
3172
+     *	@param	int		$sourceid		Object source id
3173
+     *	@param  string	$sourcetype		Object source type
3174
+     *	@param  int		$targetid		Object target id
3175
+     *	@param  string	$targettype		Object target type
3176
+     *	@return							int	>0 if OK, <0 if KO
3177
+     *	@see	add_object_linked, fetObjectLinked, deleteObjectLinked
3178
+     */
3179
+    function updateObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='')
3180
+    {
3181
+        $updatesource=false;
3182
+        $updatetarget=false;
3183
+
3184
+        if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $updatesource=true;
3185
+        else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $updatetarget=true;
3186
+
3187
+        $sql = "UPDATE ".MAIN_DB_PREFIX."element_element SET ";
3188
+        if ($updatesource)
3189
+        {
3190
+            $sql.= "fk_source = ".$sourceid;
3191
+            $sql.= ", sourcetype = '".$this->db->escape($sourcetype)."'";
3192
+            $sql.= " WHERE fk_target = ".$this->id;
3193
+            $sql.= " AND targettype = '".$this->db->escape($this->element)."'";
3194
+        }
3195
+        else if ($updatetarget)
3196
+        {
3197
+            $sql.= "fk_target = ".$targetid;
3198
+            $sql.= ", targettype = '".$this->db->escape($targettype)."'";
3199
+            $sql.= " WHERE fk_source = ".$this->id;
3200
+            $sql.= " AND sourcetype = '".$this->db->escape($this->element)."'";
3201
+        }
3202
+
3203
+        dol_syslog(get_class($this)."::updateObjectLinked", LOG_DEBUG);
3204
+        if ($this->db->query($sql))
3205
+        {
3206
+            return 1;
3207
+        }
3208
+        else
3209
+        {
3210
+            $this->error=$this->db->lasterror();
3211
+            return -1;
3212
+        }
3213
+    }
3214
+
3215
+    /**
3216
+     *	Delete all links between an object $this
3217
+     *
3218
+     *	@param	int		$sourceid		Object source id
3219
+     *	@param  string	$sourcetype		Object source type
3220
+     *	@param  int		$targetid		Object target id
3221
+     *	@param  string	$targettype		Object target type
3222
+     *  @param	int		$rowid			Row id of line to delete. If defined, other parameters are not used.
3223
+     *	@return     					int	>0 if OK, <0 if KO
3224
+     *	@see	add_object_linked, updateObjectLinked, fetchObjectLinked
3225
+     */
3226
+    function deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
3227
+    {
3228
+        $deletesource=false;
3229
+        $deletetarget=false;
3230
+
3231
+        if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $deletesource=true;
3232
+        else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $deletetarget=true;
3233
+
3234
+        $sourceid = (! empty($sourceid) ? $sourceid : $this->id);
3235
+        $sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
3236
+        $targetid = (! empty($targetid) ? $targetid : $this->id);
3237
+        $targettype = (! empty($targettype) ? $targettype : $this->element);
3238
+
3239
+        $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_element";
3240
+        $sql.= " WHERE";
3241
+        if ($rowid > 0)
3242
+        {
3243
+            $sql.=" rowid = ".$rowid;
3244
+        }
3245
+        else
3246
+        {
3247
+            if ($deletesource)
3248
+            {
3249
+                $sql.= " fk_source = ".$sourceid." AND sourcetype = '".$this->db->escape($sourcetype)."'";
3250
+                $sql.= " AND fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."'";
3251
+            }
3252
+            else if ($deletetarget)
3253
+            {
3254
+                $sql.= " fk_target = ".$targetid." AND targettype = '".$this->db->escape($targettype)."'";
3255
+                $sql.= " AND fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."'";
3256
+            }
3257
+            else
3258
+            {
3259
+                $sql.= " (fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."')";
3260
+                $sql.= " OR";
3261
+                $sql.= " (fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."')";
3262
+            }
3263
+        }
3264
+
3265
+        dol_syslog(get_class($this)."::deleteObjectLinked", LOG_DEBUG);
3266
+        if ($this->db->query($sql))
3267
+        {
3268
+            return 1;
3269
+        }
3270
+        else
3271
+        {
3272
+            $this->error=$this->db->lasterror();
3273
+            $this->errors[]=$this->error;
3274
+            return -1;
3275
+        }
3276
+    }
3277
+
3278
+    /**
3279
+     *      Set status of an object
3280
+     *
3281
+     *      @param	int		$status			Status to set
3282
+     *      @param	int		$elementId		Id of element to force (use this->id by default)
3283
+     *      @param	string	$elementType	Type of element to force (use this->table_element by default)
3284
+     *      @param	string	$trigkey		Trigger key to use for trigger
3285
+     *      @return int						<0 if KO, >0 if OK
3286
+     */
3287
+    function setStatut($status, $elementId=null, $elementType='', $trigkey='')
3288
+    {
3289
+        global $user,$langs,$conf;
3290
+
3291
+        $savElementId=$elementId;  // To be used later to know if we were using the method using the id of this or not.
3292
+
3293
+        $elementId = (!empty($elementId)?$elementId:$this->id);
3294
+        $elementTable = (!empty($elementType)?$elementType:$this->table_element);
3295
+
3296
+        $this->db->begin();
3297
+
3298
+        $fieldstatus="fk_statut";
3299
+        if ($elementTable == 'facture_rec') $fieldstatus="suspended";
3300
+        if ($elementTable == 'mailing') $fieldstatus="statut";
3301
+        if ($elementTable == 'cronjob') $fieldstatus="status";
3302
+        if ($elementTable == 'user') $fieldstatus="statut";
3303
+        if ($elementTable == 'expensereport') $fieldstatus="fk_statut";
3304
+        if ($elementTable == 'commande_fournisseur_dispatch') $fieldstatus="status";
3305
+
3306
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$elementTable;
3307
+        $sql.= " SET ".$fieldstatus." = ".$status;
3308
+        // If status = 1 = validated, update also fk_user_valid
3309
+        if ($status == 1 && $elementTable == 'expensereport') $sql.=", fk_user_valid = ".$user->id;
3310
+        $sql.= " WHERE rowid=".$elementId;
3311
+
3312
+        dol_syslog(get_class($this)."::setStatut", LOG_DEBUG);
3313
+        if ($this->db->query($sql))
3314
+        {
3315
+            $error = 0;
3316
+
3317
+            // Try autoset of trigkey
3318
+            if (empty($trigkey))
3319
+            {
3320
+                if ($this->element == 'supplier_proposal' && $status == 2) $trigkey='SUPPLIER_PROPOSAL_SIGN';   // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class
3321
+                if ($this->element == 'supplier_proposal' && $status == 3) $trigkey='SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class
3322
+                if ($this->element == 'supplier_proposal' && $status == 4) $trigkey='SUPPLIER_PROPOSAL_CLOSE';  // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class
3323
+                if ($this->element == 'fichinter' && $status == 3) $trigkey='FICHINTER_CLASSIFY_DONE';
3324
+                if ($this->element == 'fichinter' && $status == 2) $trigkey='FICHINTER_CLASSIFY_BILLED';
3325
+                if ($this->element == 'fichinter' && $status == 1) $trigkey='FICHINTER_CLASSIFY_UNBILLED';
3326
+            }
3327
+
3328
+            if ($trigkey)
3329
+            {
3330
+                // Appel des triggers
3331
+                include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
3332
+                $interface=new Interfaces($this->db);
3333
+                $result=$interface->run_triggers($trigkey,$this,$user,$langs,$conf);
3334
+                if ($result < 0) {
3335
+                    $error++; $this->errors=$interface->errors;
3336
+                }
3337
+                // Fin appel triggers
3338
+            }
3339
+
3340
+            if (! $error)
3341
+            {
3342
+                $this->db->commit();
3343
+
3344
+                if (empty($savElementId))    // If the element we update was $this (so $elementId is null)
3345
+                {
3346
+                    $this->statut = $status;
3347
+                    $this->status = $status;
3348
+                }
3349
+
3350
+                return 1;
3351
+            }
3352
+            else
3353
+            {
3354
+                $this->db->rollback();
3355
+                dol_syslog(get_class($this)."::setStatus ".$this->error,LOG_ERR);
3356
+                return -1;
3357
+            }
3358
+        }
3359
+        else
3360
+        {
3361
+            $this->error=$this->db->lasterror();
3362
+            $this->db->rollback();
3363
+            return -1;
3364
+        }
3365
+    }
3366
+
3367
+
3368
+    /**
3369
+     *  Load type of canvas of an object if it exists
3370
+     *
3371
+     *  @param      int		$id     Record id
3372
+     *  @param      string	$ref    Record ref
3373
+     *  @return		int				<0 if KO, 0 if nothing done, >0 if OK
3374
+     */
3375
+    function getCanvas($id=0,$ref='')
3376
+    {
3377
+        global $conf;
3378
+
3379
+        if (empty($id) && empty($ref)) return 0;
3380
+        if (! empty($conf->global->MAIN_DISABLE_CANVAS)) return 0;    // To increase speed. Not enabled by default.
3381
+
3382
+        // Clean parameters
3383
+        $ref = trim($ref);
3384
+
3385
+        $sql = "SELECT rowid, canvas";
3386
+        $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element;
3387
+        $sql.= " WHERE entity IN (".getEntity($this->element).")";
3388
+        if (! empty($id))  $sql.= " AND rowid = ".$id;
3389
+        if (! empty($ref)) $sql.= " AND ref = '".$this->db->escape($ref)."'";
3390
+
3391
+        $resql = $this->db->query($sql);
3392
+        if ($resql)
3393
+        {
3394
+            $obj = $this->db->fetch_object($resql);
3395
+            if ($obj)
3396
+            {
3397
+                $this->canvas   = $obj->canvas;
3398
+                return 1;
3399
+            }
3400
+            else return 0;
3401
+        }
3402
+        else
3403
+        {
3404
+            dol_print_error($this->db);
3405
+            return -1;
3406
+        }
3407
+    }
3408
+
3409
+
3410
+    /**
3411
+     * 	Get special code of a line
3412
+     *
3413
+     * 	@param	int		$lineid		Id of line
3414
+     * 	@return	int					Special code
3415
+     */
3416
+    function getSpecialCode($lineid)
3417
+    {
3418
+        $sql = 'SELECT special_code FROM '.MAIN_DB_PREFIX.$this->table_element_line;
3419
+        $sql.= ' WHERE rowid = '.$lineid;
3420
+        $resql = $this->db->query($sql);
3421
+        if ($resql)
3422
+        {
3423
+            $row = $this->db->fetch_row($resql);
3424
+            return $row[0];
3425
+        }
3426
+    }
3427
+
3428
+    /**
3429
+     *  Function to check if an object is used by others.
3430
+     *  Check is done into this->childtables. There is no check into llx_element_element.
3431
+     *
3432
+     *  @param	int		$id			Force id of object
3433
+     *  @return	int					<0 if KO, 0 if not used, >0 if already used
3434
+     */
3435
+    function isObjectUsed($id=0)
3436
+    {
3437
+        global $langs;
3438
+
3439
+        if (empty($id)) $id=$this->id;
3440
+
3441
+        // Check parameters
3442
+        if (! isset($this->childtables) || ! is_array($this->childtables) || count($this->childtables) == 0)
3443
+        {
3444
+            dol_print_error('Called isObjectUsed on a class with property this->childtables not defined');
3445
+            return -1;
3446
+        }
3447
+
3448
+        $arraytoscan = $this->childtables;
3449
+        // For backward compatibility, we check if array is old format array('table1', 'table2', ...)
3450
+        $tmparray=array_keys($this->childtables);
3451
+        if (is_numeric($tmparray[0]))
3452
+        {
3453
+            $arraytoscan = array_flip($this->childtables);
3454
+        }
3455
+
3456
+        // Test if child exists
3457
+        $haschild=0;
3458
+        foreach($arraytoscan as $table => $elementname)
3459
+        {
3460
+            //print $id.'-'.$table.'-'.$elementname.'<br>';
3461
+            // Check if third party can be deleted
3462
+            $sql = "SELECT COUNT(*) as nb from ".MAIN_DB_PREFIX.$table;
3463
+            $sql.= " WHERE ".$this->fk_element." = ".$id;
3464
+            $resql=$this->db->query($sql);
3465
+            if ($resql)
3466
+            {
3467
+                $obj=$this->db->fetch_object($resql);
3468
+                if ($obj->nb > 0)
3469
+                {
3470
+                    $langs->load("errors");
3471
+                    //print 'Found into table '.$table.', type '.$langs->transnoentitiesnoconv($elementname).', haschild='.$haschild;
3472
+                    $haschild += $obj->nb;
3473
+                    if (is_numeric($elementname))	// old usage
3474
+                    {
3475
+                        $this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $table);
3476
+                    }
3477
+                    else	// new usage: $elementname=Translation key
3478
+                    {
3479
+                        $this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $langs->transnoentitiesnoconv($elementname));
3480
+                    }
3481
+                    break;    // We found at least one, we stop here
3482
+                }
3483
+            }
3484
+            else
3485
+            {
3486
+                $this->errors[]=$this->db->lasterror();
3487
+                return -1;
3488
+            }
3489
+        }
3490
+        if ($haschild > 0)
3491
+        {
3492
+            $this->errors[]="ErrorRecordHasChildren";
3493
+            return $haschild;
3494
+        }
3495
+        else return 0;
3496
+    }
3497
+
3498
+    /**
3499
+     *  Function to say how many lines object contains
3500
+     *
3501
+     *	@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
3502
+     *  @return	int						<0 if KO, 0 if no predefined products, nb of lines with predefined products if found
3503
+     */
3504
+    function hasProductsOrServices($predefined=-1)
3505
+    {
3506
+        $nb=0;
3507
+
3508
+        foreach($this->lines as $key => $val)
3509
+        {
3510
+            $qualified=0;
3511
+            if ($predefined == -1) $qualified=1;
3512
+            if ($predefined == 1 && $val->fk_product > 0) $qualified=1;
3513
+            if ($predefined == 0 && $val->fk_product <= 0) $qualified=1;
3514
+            if ($predefined == 2 && $val->fk_product > 0 && $val->product_type==0) $qualified=1;
3515
+            if ($predefined == 3 && $val->fk_product > 0 && $val->product_type==1) $qualified=1;
3516
+            if ($qualified) $nb++;
3517
+        }
3518
+        dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies');
3519
+        return $nb;
3520
+    }
3521
+
3522
+    /**
3523
+     * Function that returns the total amount HT of discounts applied for all lines.
3524
+     *
3525
+     * @return 	float
3526
+     */
3527
+    function getTotalDiscount()
3528
+    {
3529
+        $total_discount=0.00;
3530
+
3531
+        $sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht";
3532
+        $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element."det";
3533
+        $sql.= " WHERE ".$this->fk_element." = ".$this->id;
3534
+
3535
+        dol_syslog(get_class($this).'::getTotalDiscount', LOG_DEBUG);
3536
+        $resql = $this->db->query($sql);
3537
+        if ($resql)
3538
+        {
3539
+            $num=$this->db->num_rows($resql);
3540
+            $i=0;
3541
+            while ($i < $num)
3542
+            {
3543
+                $obj = $this->db->fetch_object($resql);
3544
+
3545
+                $pu_ht = $obj->pu_ht;
3546
+                $qty= $obj->qty;
3547
+                $total_ht = $obj->total_ht;
3548
+
3549
+                $total_discount_line = floatval(price2num(($pu_ht * $qty) - $total_ht, 'MT'));
3550
+                $total_discount += $total_discount_line;
3551
+
3552
+                $i++;
3553
+            }
3554
+        }
3555
+
3556
+        //print $total_discount; exit;
3557
+        return price2num($total_discount);
3558
+    }
3559
+
3560
+
3561
+    /**
3562
+     * Return into unit=0, the calculated total of weight and volume of all lines * qty
3563
+     * Calculate by adding weight and volume of each product line, so properties ->volume/volume_units/weight/weight_units must be loaded on line.
3564
+     *
3565
+     * @return  array                           array('weight'=>...,'volume'=>...)
3566
+     */
3567
+    function getTotalWeightVolume()
3568
+    {
3569
+        $totalWeight = 0;
3570
+        $totalVolume = 0;
3571
+        // defined for shipment only
3572
+        $totalOrdered = '';
3573
+        // defined for shipment only
3574
+        $totalToShip = '';
3575
+
3576
+        foreach ($this->lines as $line)
3577
+        {
3578
+            if (isset($line->qty_asked))
3579
+            {
3580
+                if (empty($totalOrdered)) $totalOrdered=0;  // Avoid warning because $totalOrdered is ''
3581
+                $totalOrdered+=$line->qty_asked;    // defined for shipment only
3582
+            }
3583
+            if (isset($line->qty_shipped))
3584
+            {
3585
+                if (empty($totalToShip)) $totalToShip=0;    // Avoid warning because $totalToShip is ''
3586
+                $totalToShip+=$line->qty_shipped;   // defined for shipment only
3587
+            }else if ($line->element == 'commandefournisseurdispatch' && isset($line->qty))
3588
+            {
3589
+                if (empty($totalToShip)) $totalToShip=0;
3590
+                $totalToShip+=$line->qty;   // defined for reception only
3591
+            }
3592
+
3593
+            // Define qty, weight, volume, weight_units, volume_units
3594
+            if ($this->element == 'shipping') {
3595
+                // for shipments
3596
+                $qty = $line->qty_shipped ? $line->qty_shipped : 0;
3597
+            }
3598
+            else {
3599
+                $qty = $line->qty ? $line->qty : 0;
3600
+            }
3601
+
3602
+            $weight = $line->weight ? $line->weight : 0;
3603
+            ($weight==0 && !empty($line->product->weight))? $weight=$line->product->weight: 0;
3604
+            $volume = $line->volume ? $line->volume : 0;
3605
+            ($volume==0 && !empty($line->product->volume))? $volume=$line->product->volume: 0;
3606
+
3607
+            $weight_units=$line->weight_units;
3608
+            ($weight_units==0 && !empty($line->product->weight_units))? $weight_units=$line->product->weight_units: 0;
3609
+            $volume_units=$line->volume_units;
3610
+            ($volume_units==0 && !empty($line->product->volume_units))? $volume_units=$line->product->volume_units: 0;
3611
+
3612
+            $weightUnit=0;
3613
+            $volumeUnit=0;
3614
+            if (! empty($weight_units)) $weightUnit = $weight_units;
3615
+            if (! empty($volume_units)) $volumeUnit = $volume_units;
3616
+
3617
+            if (empty($totalWeight)) $totalWeight=0;  // Avoid warning because $totalWeight is ''
3618
+            if (empty($totalVolume)) $totalVolume=0;  // Avoid warning because $totalVolume is ''
3619
+
3620
+            //var_dump($line->volume_units);
3621
+            if ($weight_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3622
+            {
3623
+                $trueWeightUnit=pow(10, $weightUnit);
3624
+                $totalWeight += $weight * $qty * $trueWeightUnit;
3625
+            }
3626
+            else {
3627
+        if ($weight_units == 99) {
3628
+            // conversion 1 Pound = 0.45359237 KG
3629
+            $trueWeightUnit = 0.45359237;
3630
+            $totalWeight += $weight * $qty * $trueWeightUnit;
3631
+        } elseif ($weight_units == 98) {
3632
+            // conversion 1 Ounce = 0.0283495 KG
3633
+            $trueWeightUnit = 0.0283495;
3634
+            $totalWeight += $weight * $qty * $trueWeightUnit;
3635
+        }
3636
+        else
3637
+                    $totalWeight += $weight * $qty;   // This may be wrong if we mix different units
3638
+            }
3639
+            if ($volume_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3640
+            {
3641
+                //print $line->volume."x".$line->volume_units."x".($line->volume_units < 50)."x".$volumeUnit;
3642
+                $trueVolumeUnit=pow(10, $volumeUnit);
3643
+                //print $line->volume;
3644
+                $totalVolume += $volume * $qty * $trueVolumeUnit;
3645
+            }
3646
+            else
3647
+            {
3648
+                $totalVolume += $volume * $qty;   // This may be wrong if we mix different units
3649
+            }
3650
+        }
3651
+
3652
+        return array('weight'=>$totalWeight, 'volume'=>$totalVolume, 'ordered'=>$totalOrdered, 'toship'=>$totalToShip);
3653
+    }
3654
+
3655
+
3656
+    /**
3657
+     *	Set extra parameters
3658
+     *
3659
+     *	@return	int      <0 if KO, >0 if OK
3660
+     */
3661
+    function setExtraParameters()
3662
+    {
3663
+        $this->db->begin();
3664
+
3665
+        $extraparams = (! empty($this->extraparams) ? json_encode($this->extraparams) : null);
3666
+
3667
+        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3668
+        $sql.= " SET extraparams = ".(! empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null");
3669
+        $sql.= " WHERE rowid = ".$this->id;
3670
+
3671
+        dol_syslog(get_class($this)."::setExtraParameters", LOG_DEBUG);
3672
+        $resql = $this->db->query($sql);
3673
+        if (! $resql)
3674
+        {
3675
+            $this->error=$this->db->lasterror();
3676
+            $this->db->rollback();
3677
+            return -1;
3678
+        }
3679
+        else
3680
+        {
3681
+            $this->db->commit();
3682
+            return 1;
3683
+        }
3684
+    }
3685
+
3686
+
3687
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3688
+    /**
3689
+     *    Return incoterms informations
3690
+     *    TODO Use a cache for label get
3691
+     *
3692
+     *    @return	string	incoterms info
3693
+     */
3694
+    function display_incoterms()
3695
+    {
3696
+        // phpcs:enable
3697
+        $out = '';
3698
+        $this->libelle_incoterms = '';
3699
+        if (!empty($this->fk_incoterms))
3700
+        {
3701
+            $sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3702
+            $result = $this->db->query($sql);
3703
+            if ($result)
3704
+            {
3705
+                $res = $this->db->fetch_object($result);
3706
+                $out .= $res->code;
3707
+            }
3708
+        }
3709
+
3710
+        $out .= (($res->code && $this->location_incoterms)?' - ':'').$this->location_incoterms;
3711
+
3712
+        return $out;
3713
+    }
3714
+
3715
+    /**
3716
+     *    Return incoterms informations for pdf display
3717
+     *
3718
+     *    @return	string		incoterms info
3719
+     */
3720
+    function getIncotermsForPDF()
3721
+    {
3722
+        $sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3723
+        $resql = $this->db->query($sql);
3724
+        if ($resql)
3725
+        {
3726
+            $num = $this->db->num_rows($resql);
3727
+            if ($num > 0)
3728
+            {
3729
+                $res = $this->db->fetch_object($resql);
3730
+                return 'Incoterm : '.$res->code.' - '.$this->location_incoterms;
3731
+            }
3732
+            else
3733
+            {
3734
+                return '';
3735
+            }
3736
+        }
3737
+        else
3738
+        {
3739
+            $this->errors[] = $this->db->lasterror();
3740
+            return false;
3741
+        }
3742
+    }
3743
+
3744
+    /**
3745
+     *    Define incoterms values of current object
3746
+     *
3747
+     *    @param	int		$id_incoterm     Id of incoterm to set or '' to remove
3748
+     * 	  @param 	string  $location		 location of incoterm
3749
+     *    @return	int     		<0 if KO, >0 if OK
3750
+     */
3751
+    function setIncoterms($id_incoterm, $location)
3752
+    {
3753
+        if ($this->id && $this->table_element)
3754
+        {
3755
+            $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3756
+            $sql.= " SET fk_incoterms = ".($id_incoterm > 0 ? $id_incoterm : "null");
3757
+            $sql.= ", location_incoterms = ".($id_incoterm > 0 ? "'".$this->db->escape($location)."'" : "null");
3758
+            $sql.= " WHERE rowid = " . $this->id;
3759
+            dol_syslog(get_class($this).'::setIncoterms', LOG_DEBUG);
3760
+            $resql=$this->db->query($sql);
3761
+            if ($resql)
3762
+            {
3763
+                $this->fk_incoterms = $id_incoterm;
3764
+                $this->location_incoterms = $location;
3765
+
3766
+                $sql = 'SELECT libelle FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3767
+                $res = $this->db->query($sql);
3768
+                if ($res)
3769
+                {
3770
+                    $obj = $this->db->fetch_object($res);
3771
+                    $this->libelle_incoterms = $obj->libelle;
3772
+                }
3773
+                return 1;
3774
+            }
3775
+            else
3776
+            {
3777
+                $this->errors[] = $this->db->lasterror();
3778
+                return -1;
3779
+            }
3780
+        }
3781
+        else return -1;
3782
+    }
3783
+
3784
+
3785
+    // --------------------
3786
+    // TODO: All functions here must be redesigned and moved as they are not business functions but output functions
3787
+    // --------------------
3788
+
3789
+    /* This is to show add lines */
3790
+
3791
+    /**
3792
+     *	Show add free and predefined products/services form
3793
+     *
3794
+     *  @param	int		        $dateSelector       1=Show also date range input fields
3795
+     *  @param	Societe			$seller				Object thirdparty who sell
3796
+     *  @param	Societe			$buyer				Object thirdparty who buy
3797
+     *	@return	void
3798
+     */
3799
+    function formAddObjectLine($dateSelector, $seller, $buyer)
3800
+    {
3801
+        global $conf,$user,$langs,$object,$hookmanager;
3802
+        global $form,$bcnd,$var;
3803
+
3804
+        // Line extrafield
3805
+        require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3806
+        $extrafieldsline = new ExtraFields($this->db);
3807
+        $extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3808
+
3809
+        // Output template part (modules that overwrite templates must declare this into descriptor)
3810
+        // Use global variables + $dateSelector + $seller and $buyer
3811
+        $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
3812
+        foreach($dirtpls as $reldir)
3813
+        {
3814
+            $tpl = dol_buildpath($reldir.'/objectline_create.tpl.php');
3815
+            if (empty($conf->file->strict_mode)) {
3816
+                $res=@include $tpl;
3817
+            } else {
3818
+                $res=include $tpl; // for debug
3819
+            }
3820
+            if ($res) break;
3821
+        }
3822
+    }
3823
+
3824
+
3825
+
3826
+    /* This is to show array of line of details */
3827
+
3828
+
3829
+    /**
3830
+     *	Return HTML table for object lines
3831
+     *	TODO Move this into an output class file (htmlline.class.php)
3832
+     *	If lines are into a template, title must also be into a template
3833
+     *	But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
3834
+     *
3835
+     *	@param	string		$action				Action code
3836
+     *	@param  string		$seller            	Object of seller third party
3837
+     *	@param  string  	$buyer             	Object of buyer third party
3838
+     *	@param	int			$selected		   	Object line selected
3839
+     *	@param  int	    	$dateSelector      	1=Show also date range input fields
3840
+     *	@return	void
3841
+     */
3842
+    function printObjectLines($action, $seller, $buyer, $selected=0, $dateSelector=0)
3843
+    {
3844
+        global $conf, $hookmanager, $langs, $user;
3845
+        // TODO We should not use global var for this !
3846
+        global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax;
3847
+
3848
+        // Define usemargins
3849
+        $usemargins=0;
3850
+        if (! empty($conf->margin->enabled) && ! empty($this->element) && in_array($this->element,array('facture','propal','commande'))) $usemargins=1;
3851
+
3852
+        $num = count($this->lines);
3853
+
3854
+        // Line extrafield
3855
+        require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3856
+        $extrafieldsline = new ExtraFields($this->db);
3857
+        $extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3858
+
3859
+        $parameters = array('num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3860
+        $reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3861
+        if (empty($reshook))
3862
+        {
3863
+            // Title line
3864
+            print "<thead>\n";
3865
+
3866
+            print '<tr class="liste_titre nodrag nodrop">';
3867
+
3868
+            // Adds a line numbering column
3869
+            if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) print '<td class="linecolnum" align="center" width="5">&nbsp;</td>';
3870
+
3871
+            // Description
3872
+            print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
3873
+
3874
+            if ($this->element == 'supplier_proposal' || $this->element == 'order_supplier' || $this->element == 'invoice_supplier')
3875
+            {
3876
+                print '<td class="linerefsupplier"><span id="title_fourn_ref">'.$langs->trans("SupplierRef").'</span></td>';
3877
+            }
3878
+
3879
+            // VAT
3880
+            print '<td class="linecolvat" align="right" width="80">'.$langs->trans('VAT').'</td>';
3881
+
3882
+            // Price HT
3883
+            print '<td class="linecoluht" align="right" width="80">'.$langs->trans('PriceUHT').'</td>';
3884
+
3885
+            // Multicurrency
3886
+            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>';
3887
+
3888
+            if ($inputalsopricewithtax) print '<td align="right" width="80">'.$langs->trans('PriceUTTC').'</td>';
3889
+
3890
+            // Qty
3891
+            print '<td class="linecolqty" align="right">'.$langs->trans('Qty').'</td>';
3892
+
3893
+            if($conf->global->PRODUCT_USE_UNITS)
3894
+            {
3895
+                print '<td class="linecoluseunit" align="left">'.$langs->trans('Unit').'</td>';
3896
+            }
3897
+
3898
+            // Reduction short
3899
+            print '<td class="linecoldiscount" align="right">'.$langs->trans('ReductionShort').'</td>';
3900
+
3901
+            if ($this->situation_cycle_ref) {
3902
+                print '<td class="linecolcycleref" align="right">' . $langs->trans('Progress') . '</td>';
3903
+            }
3904
+
3905
+            if ($usemargins && ! empty($conf->margin->enabled) && empty($user->societe_id))
3906
+            {
3907
+                if (!empty($user->rights->margins->creer))
3908
+                {
3909
+                    if ($conf->global->MARGIN_TYPE == "1")
3910
+                        print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('BuyingPrice').'</td>';
3911
+                    else
3912
+                        print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('CostPrice').'</td>';
3913
+                }
3914
+
3915
+                if (! empty($conf->global->DISPLAY_MARGIN_RATES) && $user->rights->margins->liretous)
3916
+                    print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarginRate').'</td>';
3917
+                if (! empty($conf->global->DISPLAY_MARK_RATES) && $user->rights->margins->liretous)
3918
+                    print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarkRate').'</td>';
3919
+            }
3920
+
3921
+            // Total HT
3922
+            print '<td class="linecolht" align="right">'.$langs->trans('TotalHTShort').'</td>';
3923
+
3924
+            // Multicurrency
3925
+            if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) print '<td class="linecoltotalht_currency" align="right">'.$langs->trans('TotalHTShortCurrency', $this->multicurrency_code).'</td>';
3926
+
3927
+            if ($outputalsopricetotalwithtax) print '<td align="right" width="80">'.$langs->trans('TotalTTCShort').'</td>';
3928
+
3929
+            print '<td class="linecoledit"></td>';  // No width to allow autodim
3930
+
3931
+            print '<td class="linecoldelete" width="10"></td>';
3932
+
3933
+            print '<td class="linecolmove" width="10"></td>';
3934
+
3935
+            if($action == 'selectlines')
3936
+            {
3937
+                print '<td class="linecolcheckall" align="center">';
3938
+                print '<input type="checkbox" class="linecheckboxtoggle" />';
3939
+                print '<script type="text/javascript">$(document).ready(function() {$(".linecheckboxtoggle").click(function() {var checkBoxes = $(".linecheckbox");checkBoxes.prop("checked", this.checked);})});</script>';
3940
+                print '</td>';
3941
+            }
3942
+
3943
+            print "</tr>\n";
3944
+            print "</thead>\n";
3945
+        }
3946
+
3947
+        $var = true;
3948
+        $i	 = 0;
3949
+
3950
+        print "<tbody>\n";
3951
+        foreach ($this->lines as $line)
3952
+        {
3953
+            //Line extrafield
3954
+            $line->fetch_optionals();
3955
+
3956
+            //if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
3957
+            if (is_object($hookmanager))   // Old code is commented on preceding line.
3958
+            {
3959
+                if (empty($line->fk_parent_line))
3960
+                {
3961
+                    $parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3962
+                    $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3963
+                }
3964
+                else
3965
+                {
3966
+                    $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);
3967
+                    $reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3968
+                }
3969
+            }
3970
+            if (empty($reshook))
3971
+            {
3972
+                $this->printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected,$extrafieldsline);
3973
+            }
3974
+
3975
+            $i++;
3976
+        }
3977
+        print "</tbody>\n";
3978
+    }
3979
+
3980
+    /**
3981
+     *	Return HTML content of a detail line
3982
+     *	TODO Move this into an output class file (htmlline.class.php)
3983
+     *
3984
+     *	@param	string		$action				GET/POST action
3985
+     *	@param CommonObjectLine $line		       	Selected object line to output
3986
+     *	@param  string	    $var               	Is it a an odd line (true)
3987
+     *	@param  int		    $num               	Number of line (0)
3988
+     *	@param  int		    $i					I
3989
+     *	@param  int		    $dateSelector      	1=Show also date range input fields
3990
+     *	@param  string	    $seller            	Object of seller third party
3991
+     *	@param  string	    $buyer             	Object of buyer third party
3992
+     *	@param	int			$selected		   	Object line selected
3993
+     *  @param  int			$extrafieldsline	Object of extrafield line attribute
3994
+     *	@return	void
3995
+     */
3996
+    function printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected=0,$extrafieldsline=0)
3997
+    {
3998
+        global $conf,$langs,$user,$object,$hookmanager;
3999
+        global $form,$bc,$bcdd;
4000
+        global $object_rights, $disableedit, $disablemove, $disableremove;   // TODO We should not use global var for this !
4001
+
4002
+        $object_rights = $this->getRights();
4003
+
4004
+        $element=$this->element;
4005
+
4006
+        $text=''; $description=''; $type=0;
4007
+
4008
+        // Show product and description
4009
+        $type=(! empty($line->product_type)?$line->product_type:$line->fk_product_type);
4010
+        // Try to enhance type detection using date_start and date_end for free lines where type was not saved.
4011
+        if (! empty($line->date_start)) $type=1; // deprecated
4012
+        if (! empty($line->date_end)) $type=1; // deprecated
4013
+
4014
+        // Ligne en mode visu
4015
+        if ($action != 'editline' || $selected != $line->id)
4016
+        {
4017
+            // Product
4018
+            if ($line->fk_product > 0)
4019
+            {
4020
+                $product_static = new Product($this->db);
4021
+                $product_static->fetch($line->fk_product);
4022
+
4023
+                $product_static->ref = $line->ref; //can change ref in hook
4024
+                $product_static->label = $line->label; //can change label in hook
4025
+                $text=$product_static->getNomUrl(1);
4026
+
4027
+                // Define output language and label
4028
+                if (! empty($conf->global->MAIN_MULTILANGS))
4029
+                {
4030
+                    if (! is_object($this->thirdparty))
4031
+                    {
4032
+                        dol_print_error('','Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before');
4033
+                        return;
4034
+                    }
4035
+
4036
+                    $prod = new Product($this->db);
4037
+                    $prod->fetch($line->fk_product);
4038
+
4039
+                    $outputlangs = $langs;
4040
+                    $newlang='';
4041
+                    if (empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09');
4042
+                    if (! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && empty($newlang)) $newlang=$this->thirdparty->default_lang;		// For language to language of customer
4043
+                    if (! empty($newlang))
4044
+                    {
4045
+                        $outputlangs = new Translate("",$conf);
4046
+                        $outputlangs->setDefaultLang($newlang);
4047
+                    }
4048
+
4049
+                    $label = (! empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $line->product_label;
4050
+                }
4051
+                else
4052
+                {
4053
+                    $label = $line->product_label;
4054
+                }
4055
+
4056
+                $text.= ' - '.(! empty($line->label)?$line->label:$label);
4057
+                $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.
4058
+            }
4059
+
4060
+            $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
4061
+
4062
+            // Output template part (modules that overwrite templates must declare this into descriptor)
4063
+            // Use global variables + $dateSelector + $seller and $buyer
4064
+            $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4065
+            foreach($dirtpls as $reldir)
4066
+            {
4067
+                $tpl = dol_buildpath($reldir.'/objectline_view.tpl.php');
4068
+                if (empty($conf->file->strict_mode)) {
4069
+                    $res=@include $tpl;
4070
+                } else {
4071
+                    $res=include $tpl; // for debug
4072
+                }
4073
+                if ($res) break;
4074
+            }
4075
+        }
4076
+
4077
+        // Ligne en mode update
4078
+        if ($this->statut == 0 && $action == 'editline' && $selected == $line->id)
4079
+        {
4080
+            $label = (! empty($line->label) ? $line->label : (($line->fk_product > 0) ? $line->product_label : ''));
4081
+            $placeholder=' placeholder="'.$langs->trans("Label").'"';
4082
+
4083
+            $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
4084
+
4085
+            // Output template part (modules that overwrite templates must declare this into descriptor)
4086
+            // Use global variables + $dateSelector + $seller and $buyer
4087
+            $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4088
+            foreach($dirtpls as $reldir)
4089
+            {
4090
+                $tpl = dol_buildpath($reldir.'/objectline_edit.tpl.php');
4091
+                if (empty($conf->file->strict_mode)) {
4092
+                    $res=@include $tpl;
4093
+                } else {
4094
+                    $res=include $tpl; // for debug
4095
+                }
4096
+                if ($res) break;
4097
+            }
4098
+        }
4099
+    }
4100
+
4101
+
4102
+    /* This is to show array of line of details of source object */
4103
+
4104
+
4105
+    /**
4106
+     * 	Return HTML table table of source object lines
4107
+     *  TODO Move this and previous function into output html class file (htmlline.class.php).
4108
+     *  If lines are into a template, title must also be into a template
4109
+     *  But for the moment we don't know if it's possible, so we keep the method available on overloaded objects.
4110
+     *
4111
+     *	@param	string		$restrictlist		''=All lines, 'services'=Restrict to services only
4112
+     *  @return	void
4113
+     */
4114
+    function printOriginLinesList($restrictlist='')
4115
+    {
4116
+        global $langs, $hookmanager, $conf;
4117
+
4118
+        print '<tr class="liste_titre">';
4119
+        print '<td>'.$langs->trans('Ref').'</td>';
4120
+        print '<td>'.$langs->trans('Description').'</td>';
4121
+        print '<td align="right">'.$langs->trans('VATRate').'</td>';
4122
+        print '<td align="right">'.$langs->trans('PriceUHT').'</td>';
4123
+        if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$langs->trans('PriceUHTCurrency').'</td>';
4124
+        print '<td align="right">'.$langs->trans('Qty').'</td>';
4125
+        if($conf->global->PRODUCT_USE_UNITS)
4126
+        {
4127
+            print '<td align="left">'.$langs->trans('Unit').'</td>';
4128
+        }
4129
+        print '<td align="right">'.$langs->trans('ReductionShort').'</td></tr>';
4130
+
4131
+        $var = true;
4132
+        $i	 = 0;
4133
+
4134
+        if (! empty($this->lines))
4135
+        {
4136
+            foreach ($this->lines as $line)
4137
+            {
4138
+                if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
4139
+                {
4140
+                    if (empty($line->fk_parent_line))
4141
+                    {
4142
+                        $parameters=array('line'=>$line,'var'=>$var,'i'=>$i);
4143
+                        $action='';
4144
+                        $hookmanager->executeHooks('printOriginObjectLine',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
4145
+                    }
4146
+                }
4147
+                else
4148
+                {
4149
+                    $this->printOriginLine($line, $var, $restrictlist);
4150
+                }
4151
+
4152
+                $i++;
4153
+            }
4154
+        }
4155
+    }
4156
+
4157
+    /**
4158
+     * 	Return HTML with a line of table array of source object lines
4159
+     *  TODO Move this and previous function into output html class file (htmlline.class.php).
4160
+     *  If lines are into a template, title must also be into a template
4161
+     *  But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
4162
+     *
4163
+     * 	@param	CommonObjectLine	$line				Line
4164
+     * 	@param	string				$var				Var
4165
+     *	@param	string				$restrictlist		''=All lines, 'services'=Restrict to services only (strike line if not)
4166
+     * 	@return	void
4167
+     */
4168
+    function printOriginLine($line, $var, $restrictlist='')
4169
+    {
4170
+        global $langs, $conf;
4171
+
4172
+        //var_dump($line);
4173
+        if (!empty($line->date_start))
4174
+        {
4175
+            $date_start=$line->date_start;
4176
+        }
4177
+        else
4178
+        {
4179
+            $date_start=$line->date_debut_prevue;
4180
+            if ($line->date_debut_reel) $date_start=$line->date_debut_reel;
4181
+        }
4182
+        if (!empty($line->date_end))
4183
+        {
4184
+            $date_end=$line->date_end;
4185
+        }
4186
+        else
4187
+        {
4188
+            $date_end=$line->date_fin_prevue;
4189
+            if ($line->date_fin_reel) $date_end=$line->date_fin_reel;
4190
+        }
4191
+
4192
+        $this->tpl['label'] = '';
4193
+        if (! empty($line->fk_parent_line)) $this->tpl['label'].= img_picto('', 'rightarrow');
4194
+
4195
+        if (($line->info_bits & 2) == 2)  // TODO Not sure this is used for source object
4196
+        {
4197
+            $discount=new DiscountAbsolute($this->db);
4198
+            $discount->fk_soc = $this->socid;
4199
+            $this->tpl['label'].= $discount->getNomUrl(0,'discount');
4200
+        }
4201
+        else if (! empty($line->fk_product))
4202
+        {
4203
+            $productstatic = new Product($this->db);
4204
+            $productstatic->id = $line->fk_product;
4205
+            $productstatic->ref = $line->ref;
4206
+            $productstatic->type = $line->fk_product_type;
4207
+            if(empty($productstatic->ref)){
4208
+                $line->fetch_product();
4209
+                $productstatic = $line->product;
4210
+            }
4211
+			
4212
+            $this->tpl['label'].= $productstatic->getNomUrl(1);
4213
+            $this->tpl['label'].= ' - '.(! empty($line->label)?$line->label:$line->product_label);
4214
+            // Dates
4215
+            if ($line->product_type == 1 && ($date_start || $date_end))
4216
+            {
4217
+                $this->tpl['label'].= get_date_range($date_start,$date_end);
4218
+            }
4219
+        }
4220
+        else
4221
+        {
4222
+            $this->tpl['label'].= ($line->product_type == -1 ? '&nbsp;' : ($line->product_type == 1 ? img_object($langs->trans(''),'service') : img_object($langs->trans(''),'product')));
4223
+            if (!empty($line->desc)) {
4224
+                $this->tpl['label'].=$line->desc;
4225
+            }else {
4226
+                $this->tpl['label'].= ($line->label ? '&nbsp;'.$line->label : '');
4227
+            }
4228
+			
4229
+            // Dates
4230
+            if ($line->product_type == 1 && ($date_start || $date_end))
4231
+            {
4232
+                $this->tpl['label'].= get_date_range($date_start,$date_end);
4233
+            }
4234
+        }
4235
+
4236
+        if (! empty($line->desc))
4237
+        {
4238
+            if ($line->desc == '(CREDIT_NOTE)')  // TODO Not sure this is used for source object
4239
+            {
4240
+                $discount=new DiscountAbsolute($this->db);
4241
+                $discount->fetch($line->fk_remise_except);
4242
+                $this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote",$discount->getNomUrl(0));
4243
+            }
4244
+            elseif ($line->desc == '(DEPOSIT)')  // TODO Not sure this is used for source object
4245
+            {
4246
+                $discount=new DiscountAbsolute($this->db);
4247
+                $discount->fetch($line->fk_remise_except);
4248
+                $this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit",$discount->getNomUrl(0));
4249
+            }
4250
+            elseif ($line->desc == '(EXCESS RECEIVED)')
4251
+            {
4252
+                $discount=new DiscountAbsolute($this->db);
4253
+                $discount->fetch($line->fk_remise_except);
4254
+                $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessReceived",$discount->getNomUrl(0));
4255
+            }
4256
+            elseif ($line->desc == '(EXCESS PAID)')
4257
+            {
4258
+                $discount=new DiscountAbsolute($this->db);
4259
+                $discount->fetch($line->fk_remise_except);
4260
+                $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessPaid",$discount->getNomUrl(0));
4261
+            }
4262
+            else
4263
+            {
4264
+                $this->tpl['description'] = dol_trunc($line->desc,60);
4265
+            }
4266
+        }
4267
+        else
4268
+        {
4269
+            $this->tpl['description'] = '&nbsp;';
4270
+        }
4271
+
4272
+        // VAT Rate
4273
+        $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
4274
+        $this->tpl['vat_rate'] .= (($line->info_bits & 1) == 1) ? '*' : '';
4275
+        if (! empty($line->vat_src_code) && ! preg_match('/\(/', $this->tpl['vat_rate'])) $this->tpl['vat_rate'].=' ('.$line->vat_src_code.')';
4276
+
4277
+        $this->tpl['price'] = price($line->subprice);
4278
+        $this->tpl['multicurrency_price'] = price($line->multicurrency_subprice);
4279
+        $this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : '&nbsp;';
4280
+        if ($conf->global->PRODUCT_USE_UNITS) $this->tpl['unit'] = $langs->transnoentities($line->getLabelOfUnit('long'));
4281
+        $this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : '&nbsp;';
4282
+
4283
+        // Is the line strike or not
4284
+        $this->tpl['strike']=0;
4285
+        if ($restrictlist == 'services' && $line->product_type != Product::TYPE_SERVICE) $this->tpl['strike']=1;
4286
+
4287
+        // Output template part (modules that overwrite templates must declare this into descriptor)
4288
+        // Use global variables + $dateSelector + $seller and $buyer
4289
+        $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl'));
4290
+        foreach($dirtpls as $reldir)
4291
+        {
4292
+            $tpl = dol_buildpath($reldir.'/originproductline.tpl.php');
4293
+            if (empty($conf->file->strict_mode)) {
4294
+                $res=@include $tpl;
4295
+            } else {
4296
+                $res=include $tpl; // for debug
4297
+            }
4298
+            if ($res) break;
4299
+        }
4300
+    }
4301
+
4302
+
4303
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4304
+    /**
4305
+     *	Add resources to the current object : add entry into llx_element_resources
4306
+     *	Need $this->element & $this->id
4307
+     *
4308
+     *	@param		int		$resource_id		Resource id
4309
+     *	@param		string	$resource_type		'resource'
4310
+     *	@param		int		$busy				Busy or not
4311
+     *	@param		int		$mandatory			Mandatory or not
4312
+     *	@return		int							<=0 if KO, >0 if OK
4313
+     */
4314
+    function add_element_resource($resource_id, $resource_type, $busy=0, $mandatory=0)
4315
+    {
4316
+        // phpcs:enable
4317
+        $this->db->begin();
4318
+
4319
+        $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_resources (";
4320
+        $sql.= "resource_id";
4321
+        $sql.= ", resource_type";
4322
+        $sql.= ", element_id";
4323
+        $sql.= ", element_type";
4324
+        $sql.= ", busy";
4325
+        $sql.= ", mandatory";
4326
+        $sql.= ") VALUES (";
4327
+        $sql.= $resource_id;
4328
+        $sql.= ", '".$this->db->escape($resource_type)."'";
4329
+        $sql.= ", '".$this->db->escape($this->id)."'";
4330
+        $sql.= ", '".$this->db->escape($this->element)."'";
4331
+        $sql.= ", '".$this->db->escape($busy)."'";
4332
+        $sql.= ", '".$this->db->escape($mandatory)."'";
4333
+        $sql.= ")";
4334
+
4335
+        dol_syslog(get_class($this)."::add_element_resource", LOG_DEBUG);
4336
+        if ($this->db->query($sql))
4337
+        {
4338
+            $this->db->commit();
4339
+            return 1;
4340
+        }
4341
+        else
4342
+        {
4343
+            $this->error=$this->db->lasterror();
4344
+            $this->db->rollback();
4345
+            return  0;
4346
+        }
4347
+    }
4348
+
4349
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4350
+    /**
4351
+     *    Delete a link to resource line
4352
+     *
4353
+     *    @param	int		$rowid			Id of resource line to delete
4354
+     *    @param	int		$element		element name (for trigger) TODO: use $this->element into commonobject class
4355
+     *    @param	int		$notrigger		Disable all triggers
4356
+     *    @return   int						>0 if OK, <0 if KO
4357
+     */
4358
+    function delete_resource($rowid, $element, $notrigger=0)
4359
+    {
4360
+        // phpcs:enable
4361
+        global $user;
4362
+
4363
+        $this->db->begin();
4364
+
4365
+        $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_resources";
4366
+        $sql.= " WHERE rowid=".$rowid;
4367
+
4368
+        dol_syslog(get_class($this)."::delete_resource", LOG_DEBUG);
4369
+
4370
+        $resql=$this->db->query($sql);
4371
+        if (! $resql)
4372
+        {
4373
+            $this->error=$this->db->lasterror();
4374
+            $this->db->rollback();
4375
+            return -1;
4376
+        }
4377
+        else
4378
+        {
4379
+            if (! $notrigger)
4380
+            {
4381
+                $result=$this->call_trigger(strtoupper($element).'_DELETE_RESOURCE', $user);
4382
+                if ($result < 0) { $this->db->rollback(); return -1; }
4383
+            }
4384
+            $this->db->commit();
4385
+            return 1;
4386
+        }
4387
+    }
4388
+
4389
+
4390
+    /**
4391
+     * Overwrite magic function to solve problem of cloning object that are kept as references
4392
+     *
4393
+     * @return void
4394
+     */
4395
+    function __clone()
4396
+    {
4397
+        // Force a copy of this->lines, otherwise it will point to same object.
4398
+        if (isset($this->lines) && is_array($this->lines))
4399
+        {
4400
+            $nboflines=count($this->lines);
4401
+            for($i=0; $i < $nboflines; $i++)
4402
+            {
4403
+                $this->lines[$i] = clone $this->lines[$i];
4404
+            }
4405
+        }
4406
+    }
4407
+
4408
+    /**
4409
+     * Common function for all objects extending CommonObject for generating documents
4410
+     *
4411
+     * @param 	string 		$modelspath 	Relative folder where generators are placed
4412
+     * @param 	string 		$modele 		Generator to use. Caller must set it to obj->modelpdf or GETPOST('modelpdf') for example.
4413
+     * @param 	Translate 	$outputlangs 	Output language to use
4414
+     * @param 	int 		$hidedetails 	1 to hide details. 0 by default
4415
+     * @param 	int 		$hidedesc 		1 to hide product description. 0 by default
4416
+     * @param 	int 		$hideref 		1 to hide product reference. 0 by default
4417
+     * @param   null|array  $moreparams     Array to provide more information
4418
+     * @return 	int 						>0 if OK, <0 if KO
4419
+     * @see	addFileIntoDatabaseIndex
4420
+     */
4421
+    protected function commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
4422
+    {
4423
+        global $conf, $langs, $user;
4424
+
4425
+        $srctemplatepath='';
4426
+
4427
+        // Increase limit for PDF build
4428
+        $err=error_reporting();
4429
+        error_reporting(0);
4430
+        @set_time_limit(120);
4431
+        error_reporting($err);
4432
+
4433
+        // If selected model is a filename template (then $modele="modelname" or "modelname:filename")
4434
+        $tmp=explode(':',$modele,2);
4435
+        if (! empty($tmp[1]))
4436
+        {
4437
+            $modele=$tmp[0];
4438
+            $srctemplatepath=$tmp[1];
4439
+        }
4440
+
4441
+        // Search template files
4442
+        $file=''; $classname=''; $filefound=0;
4443
+        $dirmodels=array('/');
4444
+        if (is_array($conf->modules_parts['models'])) $dirmodels=array_merge($dirmodels,$conf->modules_parts['models']);
4445
+        foreach($dirmodels as $reldir)
4446
+        {
4447
+            foreach(array('doc','pdf') as $prefix)
4448
+            {
4449
+                if (in_array(get_class($this), array('Adherent'))) $file = $prefix."_".$modele.".class.php";     // Member module use prefix_module.class.php
4450
+                else $file = $prefix."_".$modele.".modules.php";
4451
+
4452
+                // On verifie l'emplacement du modele
4453
+                $file=dol_buildpath($reldir.$modelspath.$file,0);
4454
+                if (file_exists($file))
4455
+                {
4456
+                    $filefound=1;
4457
+                    $classname=$prefix.'_'.$modele;
4458
+                    break;
4459
+                }
4460
+            }
4461
+            if ($filefound) break;
4462
+        }
4463
+
4464
+        // If generator was found
4465
+        if ($filefound)
4466
+        {
4467
+            global $db;  // Required to solve a conception default in commonstickergenerator.class.php making an include of code using $db
4468
+
4469
+            require_once $file;
4470
+
4471
+            $obj = new $classname($this->db);
4472
+
4473
+            // If generator is ODT, we must have srctemplatepath defined, if not we set it.
4474
+            if ($obj->type == 'odt' && empty($srctemplatepath))
4475
+            {
4476
+                $varfortemplatedir=$obj->scandir;
4477
+                if ($varfortemplatedir && ! empty($conf->global->$varfortemplatedir))
4478
+                {
4479
+                    $dirtoscan=$conf->global->$varfortemplatedir;
4480
+
4481
+                    $listoffiles=array();
4482
+
4483
+                    // Now we add first model found in directories scanned
4484
+                    $listofdir=explode(',',$dirtoscan);
4485
+                    foreach($listofdir as $key => $tmpdir)
4486
+                    {
4487
+                        $tmpdir=trim($tmpdir);
4488
+                        $tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir);
4489
+                        if (! $tmpdir) { unset($listofdir[$key]); continue; }
4490
+                        if (is_dir($tmpdir))
4491
+                        {
4492
+                            $tmpfiles=dol_dir_list($tmpdir,'files',0,'\.od(s|t)$','','name',SORT_ASC,0);
4493
+                            if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles);
4494
+                        }
4495
+                    }
4496
+
4497
+                    if (count($listoffiles))
4498
+                    {
4499
+                        foreach($listoffiles as $record)
4500
+                        {
4501
+                            $srctemplatepath=$record['fullname'];
4502
+                            break;
4503
+                        }
4504
+                    }
4505
+                }
4506
+
4507
+                if (empty($srctemplatepath))
4508
+                {
4509
+                    $this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotDefined';
4510
+                    return -1;
4511
+                }
4512
+            }
4513
+
4514
+            if ($obj->type == 'odt' && ! empty($srctemplatepath))
4515
+            {
4516
+                if (! dol_is_file($srctemplatepath))
4517
+                {
4518
+                    $this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotFound';
4519
+                    return -1;
4520
+                }
4521
+            }
4522
+
4523
+            // We save charset_output to restore it because write_file can change it if needed for
4524
+            // output format that does not support UTF8.
4525
+            $sav_charset_output=$outputlangs->charset_output;
4526
+
4527
+            if (in_array(get_class($this), array('Adherent')))
4528
+            {
4529
+                $arrayofrecords = array();   // The write_file of templates of adherent class need this var
4530
+                $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, $moreparams);
4531
+            }
4532
+            else
4533
+            {
4534
+                $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams);
4535
+            }
4536
+            // After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index.
4537
+
4538
+            if ($resultwritefile > 0)
4539
+            {
4540
+                $outputlangs->charset_output=$sav_charset_output;
4541
+
4542
+                // We delete old preview
4543
+                require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
4544
+                dol_delete_preview($this);
4545
+
4546
+                // Index file in database
4547
+                if (! empty($obj->result['fullpath']))
4548
+                {
4549
+                    $destfull = $obj->result['fullpath'];
4550
+                    $upload_dir = dirname($destfull);
4551
+                    $destfile = basename($destfull);
4552
+                    $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $upload_dir);
4553
+
4554
+                    if (! preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir))     // If not a tmp dir
4555
+                    {
4556
+                        $filename = basename($destfile);
4557
+                        $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
4558
+                        $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
4559
+
4560
+                        include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
4561
+                        $ecmfile=new EcmFiles($this->db);
4562
+                        $result = $ecmfile->fetch(0, '', ($rel_dir?$rel_dir.'/':'').$filename);
4563
+
4564
+                        // Set the public "share" key
4565
+                        $setsharekey = false;
4566
+                        if ($this->element == 'propal')
4567
+                        {
4568
+                            $useonlinesignature = $conf->global->MAIN_FEATURES_LEVEL;	// Replace this with 1 when feature to make online signature is ok
4569
+                            if ($useonlinesignature) $setsharekey=true;
4570
+                            if (! empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4571
+                        }
4572
+                        if ($this->element == 'commande'     && ! empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD))        $setsharekey=true;
4573
+                        if ($this->element == 'facture'      && ! empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD))      $setsharekey=true;
4574
+                        if ($this->element == 'bank_account' && ! empty($conf->global->BANK_ACCOUNT_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true;
4575
+
4576
+                        if ($setsharekey)
4577
+                        {
4578
+                            if (empty($ecmfile->share))	// Because object not found or share not set yet
4579
+                            {
4580
+                                require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
4581
+                                $ecmfile->share = getRandomPassword(true);
4582
+                            }
4583
+                        }
4584
+
4585
+                        if ($result > 0)
4586
+                        {
4587
+                            $ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
4588
+                            $ecmfile->fullpath_orig = '';
4589
+                            $ecmfile->gen_or_uploaded = 'generated';
4590
+                            $ecmfile->description = '';    // indexed content
4591
+                            $ecmfile->keyword = '';        // keyword content
4592
+                            $result = $ecmfile->update($user);
4593
+                            if ($result < 0)
4594
+                            {
4595
+                                setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4596
+                            }
4597
+                        }
4598
+                        else
4599
+                        {
4600
+                            $ecmfile->entity = $conf->entity;
4601
+                            $ecmfile->filepath = $rel_dir;
4602
+                            $ecmfile->filename = $filename;
4603
+                            $ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
4604
+                            $ecmfile->fullpath_orig = '';
4605
+                            $ecmfile->gen_or_uploaded = 'generated';
4606
+                            $ecmfile->description = '';    // indexed content
4607
+                            $ecmfile->keyword = '';        // keyword content
4608
+                            $ecmfile->src_object_type = $this->table_element;
4609
+                            $ecmfile->src_object_id   = $this->id;
4610
+
4611
+                            $result = $ecmfile->create($user);
4612
+                            if ($result < 0)
4613
+                            {
4614
+                                setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4615
+                            }
4616
+                        }
4617
+
4618
+                        /*$this->result['fullname']=$destfull;
4619
+						$this->result['filepath']=$ecmfile->filepath;
4620
+						$this->result['filename']=$ecmfile->filename;*/
4621
+                        //var_dump($obj->update_main_doc_field);exit;
4622
+
4623
+                        // Update the last_main_doc field into main object (if documenent generator has property ->update_main_doc_field set)
4624
+                        $update_main_doc_field=0;
4625
+                        if (! empty($obj->update_main_doc_field)) $update_main_doc_field=1;
4626
+                        if ($update_main_doc_field && ! empty($this->table_element))
4627
+                        {
4628
+                            $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET last_main_doc = '".($ecmfile->filepath.'/'.$ecmfile->filename)."'";
4629
+                            $sql.= ' WHERE rowid = '.$this->id;
4630
+                            $resql = $this->db->query($sql);
4631
+                            if (! $resql) dol_print_error($this->db);
4632
+                        }
4633
+                    }
4634
+                }
4635
+                else
4636
+                {
4637
+                    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);
4638
+                }
4639
+
4640
+                // Success in building document. We build meta file.
4641
+                dol_meta_create($this);
4642
+
4643
+                return 1;
4644
+            }
4645
+            else
4646
+            {
4647
+                $outputlangs->charset_output=$sav_charset_output;
4648
+                dol_print_error($this->db, "Error generating document for ".__CLASS__.". Error: ".$obj->error, $obj->errors);
4649
+                return -1;
4650
+            }
4651
+        }
4652
+        else
4653
+        {
4654
+            $this->error=$langs->trans("Error")." ".$langs->trans("ErrorFileDoesNotExists",$file);
4655
+            dol_print_error('',$this->error);
4656
+            return -1;
4657
+        }
4658
+    }
4659
+
4660
+    /**
4661
+     *  Build thumb
4662
+     *  @TODO Move this into files.lib.php
4663
+     *
4664
+     *  @param      string	$file           Path file in UTF8 to original file to create thumbs from.
4665
+     *	@return		void
4666
+     */
4667
+    function addThumbs($file)
4668
+    {
4669
+        global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini, $quality;
4670
+
4671
+        require_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';		// This define also $maxwidthsmall, $quality, ...
4672
+
4673
+        $file_osencoded=dol_osencode($file);
4674
+        if (file_exists($file_osencoded))
4675
+        {
4676
+            // Create small thumbs for company (Ratio is near 16/9)
4677
+            // Used on logon for example
4678
+            vignette($file_osencoded, $maxwidthsmall, $maxheightsmall, '_small', $quality);
4679
+
4680
+            // Create mini thumbs for company (Ratio is near 16/9)
4681
+            // Used on menu or for setup page for example
4682
+            vignette($file_osencoded, $maxwidthmini, $maxheightmini, '_mini', $quality);
4683
+        }
4684
+    }
4685
+
4686
+
4687
+    /* Functions common to commonobject and commonobjectline */
4688
+
4689
+    /* For default values */
4690
+
4691
+    /**
4692
+     * Return the default value to use for a field when showing the create form of object.
4693
+     * Return values in this order:
4694
+     * 1) If parameter is available into POST, we return it first.
4695
+     * 2) If not but an alternate value was provided as parameter of function, we return it.
4696
+     * 3) If not but a constant $conf->global->OBJECTELEMENT_FIELDNAME is set, we return it (It is better to use the dedicated table).
4697
+     * 4) Return value found into database (TODO No yet implemented)
4698
+     *
4699
+     * @param   string              $fieldname          Name of field
4700
+     * @param   string              $alternatevalue     Alternate value to use
4701
+     * @return  string|string[]                         Default value (can be an array if the GETPOST return an array)
4702
+     **/
4703
+    function getDefaultCreateValueFor($fieldname, $alternatevalue=null)
4704
+    {
4705
+        global $conf, $_POST;
4706
+
4707
+        // If param here has been posted, we use this value first.
4708
+        if (isset($_POST[$fieldname])) return GETPOST($fieldname, 2);
4709
+
4710
+        if (isset($alternatevalue)) return $alternatevalue;
4711
+
4712
+        $newelement=$this->element;
4713
+        if ($newelement == 'facture') $newelement='invoice';
4714
+        if ($newelement == 'commande') $newelement='order';
4715
+        if (empty($newelement))
4716
+        {
4717
+            dol_syslog("Ask a default value using common method getDefaultCreateValueForField on an object with no property ->element defined. Return empty string.", LOG_WARNING);
4718
+            return '';
4719
+        }
4720
+
4721
+        $keyforfieldname=strtoupper($newelement.'_DEFAULT_'.$fieldname);
4722
+        //var_dump($keyforfieldname);
4723
+        if (isset($conf->global->$keyforfieldname)) return $conf->global->$keyforfieldname;
4724
+
4725
+        // TODO Ad here a scan into table llx_overwrite_default with a filter on $this->element and $fieldname
4726
+    }
4727
+
4728
+
4729
+    /* For triggers */
4730
+
4731
+
4732
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4733
+    /**
4734
+     * Call trigger based on this instance.
4735
+     * Some context information may also be provided into array property this->context.
4736
+     * NB:  Error from trigger are stacked in interface->errors
4737
+     * NB2: If return code of triggers are < 0, action calling trigger should cancel all transaction.
4738
+     *
4739
+     * @param   string    $trigger_name   trigger's name to execute
4740
+     * @param   User      $user           Object user
4741
+     * @return  int                       Result of run_triggers
4742
+     */
4743
+    function call_trigger($trigger_name, $user)
4744
+    {
4745
+        // phpcs:enable
4746
+        global $langs,$conf;
4747
+
4748
+        include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
4749
+        $interface=new Interfaces($this->db);
4750
+        $result=$interface->run_triggers($trigger_name,$this,$user,$langs,$conf);
4751
+
4752
+        if ($result < 0)
4753
+        {
4754
+            if (!empty($this->errors))
4755
+            {
4756
+                $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.
4757
+            }
4758
+            else
4759
+            {
4760
+                $this->errors=$interface->errors;
4761
+            }
4762
+        }
4763
+        return $result;
4764
+    }
4765
+
4766
+
4767
+    /* Functions for extrafields */
4768
+
4769
+
4770
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4771
+    /**
4772
+     *  Function to get extra fields of an object into $this->array_options
4773
+     *  This method is in most cases called by method fetch of objects but you can call it separately.
4774
+     *
4775
+     *  @param	int		$rowid			Id of line. Use the id of object if not defined. Deprecated. Function must be called without parameters.
4776
+     *  @param  array	$optionsArray   Array resulting of call of extrafields->fetch_name_optionals_label(). Deprecated. Function must be called without parameters.
4777
+     *  @return	int						<0 if error, 0 if no values of extrafield to find nor found, 1 if an attribute is found and value loaded
4778
+     */
4779
+    function fetch_optionals($rowid=null, $optionsArray=null)
4780
+    {
4781
+        // phpcs:enable
4782
+        if (empty($rowid)) $rowid=$this->id;
4783
+
4784
+        // To avoid SQL errors. Probably not the better solution though
4785
+        if (!$this->table_element) {
4786
+            return 0;
4787
+        }
4788
+
4789
+        $this->array_options=array();
4790
+
4791
+        if (! is_array($optionsArray))
4792
+        {
4793
+            // If $extrafields is not a known object, we initialize it. Best practice is to have $extrafields defined into card.php or list.php page.
4794
+            // TODO Use of existing $extrafield is not yet ready (must mutualize code that use extrafields in form first)
4795
+            // global $extrafields;
4796
+            //if (! is_object($extrafields))
4797
+            //{
4798
+                require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4799
+                $extrafields = new ExtraFields($this->db);
4800
+            //}
4801
+
4802
+            // Load array of extrafields for elementype = $this->table_element
4803
+            if (empty($extrafields->attributes[$this->table_element]['loaded']))
4804
+            {
4805
+                $extrafields->fetch_name_optionals_label($this->table_element);
4806
+            }
4807
+            $optionsArray = (! empty($extrafields->attributes[$this->table_element]['label'])?$extrafields->attributes[$this->table_element]['label']:null);
4808
+        }
4809
+        else
4810
+        {
4811
+            global $extrafields;
4812
+            dol_syslog("Warning: fetch_optionals was called with param optionsArray defined when you should pass null now", LOG_WARNING);
4813
+        }
4814
+
4815
+        $table_element = $this->table_element;
4816
+        if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4817
+
4818
+        // Request to get complementary values
4819
+        if (is_array($optionsArray) && count($optionsArray) > 0)
4820
+        {
4821
+            $sql = "SELECT rowid";
4822
+            foreach ($optionsArray as $name => $label)
4823
+            {
4824
+                if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] != 'separate')
4825
+                {
4826
+                    $sql.= ", ".$name;
4827
+                }
4828
+            }
4829
+            $sql.= " FROM ".MAIN_DB_PREFIX.$table_element."_extrafields";
4830
+            $sql.= " WHERE fk_object = ".$rowid;
4831
+
4832
+            //dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG);		// Too verbose
4833
+            $resql=$this->db->query($sql);
4834
+            if ($resql)
4835
+            {
4836
+                $this->array_options = array();
4837
+                $numrows=$this->db->num_rows($resql);
4838
+                if ($numrows)
4839
+                {
4840
+                    $tab = $this->db->fetch_array($resql);
4841
+
4842
+                    foreach ($tab as $key => $value)
4843
+                    {
4844
+                        // 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)
4845
+                        if ($key != 'rowid' && $key != 'tms' && $key != 'fk_member' && ! is_int($key))
4846
+                        {
4847
+                            // we can add this attribute to object
4848
+                            if (! empty($extrafields) && in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date','datetime')))
4849
+                            {
4850
+                                //var_dump($extrafields->attributes[$this->table_element]['type'][$key]);
4851
+                                $this->array_options["options_".$key]=$this->db->jdate($value);
4852
+                            }
4853
+                            else
4854
+                            {
4855
+                                $this->array_options["options_".$key]=$value;
4856
+                            }
4857
+
4858
+                            //var_dump('key '.$key.' '.$value.' type='.$extrafields->attributes[$this->table_element]['type'][$key].' '.$this->array_options["options_".$key]);
4859
+                        }
4860
+                    }
4861
+                }
4862
+
4863
+                $this->db->free($resql);
4864
+
4865
+                if ($numrows) return $numrows;
4866
+                else return 0;
4867
+            }
4868
+            else
4869
+            {
4870
+                dol_print_error($this->db);
4871
+                return -1;
4872
+            }
4873
+        }
4874
+        return 0;
4875
+    }
4876
+
4877
+    /**
4878
+     *	Delete all extra fields values for the current object.
4879
+     *
4880
+     *  @return	int		<0 if KO, >0 if OK
4881
+     */
4882
+    function deleteExtraFields()
4883
+    {
4884
+        $this->db->begin();
4885
+
4886
+        $table_element = $this->table_element;
4887
+        if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4888
+
4889
+        $sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
4890
+        dol_syslog(get_class($this)."::deleteExtraFields delete", LOG_DEBUG);
4891
+        $resql=$this->db->query($sql_del);
4892
+        if (! $resql)
4893
+        {
4894
+            $this->error=$this->db->lasterror();
4895
+            $this->db->rollback();
4896
+            return -1;
4897
+        }
4898
+        else
4899
+        {
4900
+            $this->db->commit();
4901
+            return 1;
4902
+        }
4903
+    }
4904
+
4905
+    /**
4906
+     *	Add/Update all extra fields values for the current object.
4907
+     *  Data to describe values to insert/update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
4908
+     *  This function delete record with all extrafields and insert them again from the array $this->array_options.
4909
+     *
4910
+     *  @param	string		$trigger		If defined, call also the trigger (for example COMPANY_MODIFY)
4911
+     *  @param	User		$userused		Object user
4912
+     *  @return int 						-1=error, O=did nothing, 1=OK
4913
+     *  @see updateExtraField, setValueFrom
4914
+     */
4915
+    function insertExtraFields($trigger='', $userused=null)
4916
+    {
4917
+        global $conf,$langs,$user;
4918
+
4919
+        if (empty($userused)) $userused=$user;
4920
+
4921
+        $error=0;
4922
+
4923
+        if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0;	// For avoid conflicts if trigger used
4924
+
4925
+        if (! empty($this->array_options))
4926
+        {
4927
+            // Check parameters
4928
+            $langs->load('admin');
4929
+            require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4930
+            $extrafields = new ExtraFields($this->db);
4931
+            $target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
4932
+
4933
+            //Eliminate copied source object extra_fields that do not exist in target object
4934
+            $new_array_options=array();
4935
+            foreach ($this->array_options as $key => $value) {
4936
+                if (in_array(substr($key,8), array_keys($target_extrafields)))	// We remove the 'options_' from $key for test
4937
+                    $new_array_options[$key] = $value;
4938
+                elseif (in_array($key, array_keys($target_extrafields)))		// We test on $key that does not contains the 'options_' prefix
4939
+                    $new_array_options['options_'.$key] = $value;
4940
+            }
4941
+
4942
+            foreach($new_array_options as $key => $value)
4943
+            {
4944
+                    $attributeKey      = substr($key,8);   // Remove 'options_' prefix
4945
+                    $attributeType     = $extrafields->attributes[$this->table_element]['type'][$attributeKey];
4946
+                    $attributeLabel    = $extrafields->attributes[$this->table_element]['label'][$attributeKey];
4947
+                    $attributeParam    = $extrafields->attributes[$this->table_element]['param'][$attributeKey];
4948
+                    $attributeRequired = $extrafields->attributes[$this->table_element]['required'][$attributeKey];
4949
+
4950
+                    if ($attributeRequired)
4951
+                    {
4952
+                        $mandatorypb=false;
4953
+                        if ($attributeType == 'link' && $this->array_options[$key] == '-1') $mandatorypb=true;
4954
+                        if ($this->array_options[$key] === '') $mandatorypb=true;
4955
+                        if ($mandatorypb)
4956
+                        {
4957
+                            dol_syslog($this->error);
4958
+                            $this->errors[]=$langs->trans('ErrorFieldRequired', $attributeLabel);
4959
+                            return -1;
4960
+                        }
4961
+                    }
4962
+
4963
+                //dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
4964
+                //dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
4965
+
4966
+                    switch ($attributeType)
4967
+                    {
4968
+                        case 'int':
4969
+                          if (!is_numeric($value) && $value!='')
4970
+                            {
4971
+                                $this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4972
+                                return -1;
4973
+                            }
4974
+                            elseif ($value=='')
4975
+                            {
4976
+                                $new_array_options[$key] = null;
4977
+                            }
4978
+                            break;
4979
+                    case 'double':
4980
+                        $value = price2num($value);
4981
+                        if (!is_numeric($value) && $value!='')
4982
+                        {
4983
+                            dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
4984
+                            $this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4985
+                            return -1;
4986
+                        }
4987
+                        elseif ($value=='')
4988
+                        {
4989
+                            $new_array_options[$key] = null;
4990
+                        }
4991
+                        //dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
4992
+                        $new_array_options[$key] = $value;
4993
+                        break;
4994
+                        /*case 'select':	// Not required, we chosed value='0' for undefined values
4995
+             			if ($value=='-1')
4996
+             			{
4997
+             				$this->array_options[$key] = null;
4998
+             			}
4999
+             			break;*/
5000
+                        case 'password':
5001
+                           $algo='';
5002
+                            if ($this->array_options[$key] != '' && is_array($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']))
5003
+                            {
5004
+                                // If there is an encryption choice, we use it to crypt data before insert
5005
+                                $tmparrays = array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']);
5006
+                                $algo=reset($tmparrays);
5007
+                                if ($algo != '')
5008
+                                {
5009
+                                    //global $action;		// $action may be 'create', 'update', 'update_extras'...
5010
+                                    //var_dump($action);
5011
+                                    //var_dump($this->oldcopy);exit;
5012
+                                    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
5013
+                                    {
5014
+                                        //var_dump($this->oldcopy->array_options[$key]); var_dump($this->array_options[$key]);
5015
+                                        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.
5016
+                                        {
5017
+                                            $new_array_options[$key] = $this->array_options[$key];	// Value is kept
5018
+                                        }
5019
+                                    else
5020
+                                    {
5021
+                                        // var_dump($algo);
5022
+                                        $newvalue = dol_hash($this->array_options[$key], $algo);
5023
+                                        $new_array_options[$key] = $newvalue;
5024
+                                    }
5025
+                                    }
5026
+                                    else
5027
+                                    {
5028
+                                        $new_array_options[$key] = $this->array_options[$key];	// Value is kept
5029
+                                    }
5030
+                                }
5031
+                            }
5032
+                            else	// Common usage
5033
+                            {
5034
+                                $new_array_options[$key] = $this->array_options[$key];
5035
+                            }
5036
+                            break;
5037
+                        case 'price':
5038
+                        $new_array_options[$key] = price2num($this->array_options[$key]);
5039
+                        break;
5040
+                    case 'date':
5041
+                        $new_array_options[$key] = $this->db->idate($this->array_options[$key]);
5042
+                        break;
5043
+                    case 'datetime':
5044
+                        // If data is a string instead of a timestamp, we convert it
5045
+                        if (! is_int($this->array_options[$key])) {
5046
+                            $this->array_options[$key] = strtotime($this->array_options[$key]);
5047
+                        }
5048
+                        $new_array_options[$key] = $this->db->idate($this->array_options[$key]);
5049
+                        break;
5050
+                        case 'link':
5051
+                        $param_list=array_keys($attributeParam['options']);
5052
+                        // 0 : ObjectName
5053
+                        // 1 : classPath
5054
+                        $InfoFieldList = explode(":", $param_list[0]);
5055
+                        dol_include_once($InfoFieldList[1]);
5056
+                        if ($InfoFieldList[0] && class_exists($InfoFieldList[0]))
5057
+                        {
5058
+                            if ($value == '-1')	// -1 is key for no defined in combo list of objects
5059
+                            {
5060
+                                $new_array_options[$key]='';
5061
+                            }
5062
+                            elseif ($value)
5063
+                            {
5064
+                                $object = new $InfoFieldList[0]($this->db);
5065
+                                if (is_numeric($value)) $res=$object->fetch($value);
5066
+                                else $res=$object->fetch('',$value);
5067
+
5068
+                                if ($res > 0) $new_array_options[$key]=$object->id;
5069
+                                else
5070
+                                {
5071
+                                    $this->error="Id/Ref '".$value."' for object '".$object->element."' not found";
5072
+                                    $this->db->rollback();
5073
+                                    return -1;
5074
+                                }
5075
+                            }
5076
+                        }
5077
+                        else
5078
+                        {
5079
+                            dol_syslog('Error bad setup of extrafield', LOG_WARNING);
5080
+                        }
5081
+                        break;
5082
+                    }
5083
+            }
5084
+
5085
+            $this->db->begin();
5086
+
5087
+            $table_element = $this->table_element;
5088
+            if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
5089
+
5090
+            $sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
5091
+            dol_syslog(get_class($this)."::insertExtraFields delete", LOG_DEBUG);
5092
+            $this->db->query($sql_del);
5093
+
5094
+            $sql = "INSERT INTO ".MAIN_DB_PREFIX.$table_element."_extrafields (fk_object";
5095
+            foreach($new_array_options as $key => $value)
5096
+            {
5097
+                $attributeKey = substr($key,8);   // Remove 'options_' prefix
5098
+                // Add field of attribut
5099
+                if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator
5100
+                    $sql.=",".$attributeKey;
5101
+            }
5102
+            $sql .= ") VALUES (".$this->id;
5103
+
5104
+            foreach($new_array_options as $key => $value)
5105
+            {
5106
+                $attributeKey = substr($key,8);   // Remove 'options_' prefix
5107
+                // Add field of attribute
5108
+                if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator)
5109
+                {
5110
+                    if ($new_array_options[$key] != '')
5111
+                    {
5112
+                        $sql.=",'".$this->db->escape($new_array_options[$key])."'";
5113
+                    }
5114
+                    else
5115
+                    {
5116
+                        $sql.=",null";
5117
+                    }
5118
+                }
5119
+            }
5120
+            $sql.=")";
5121
+
5122
+            dol_syslog(get_class($this)."::insertExtraFields insert", LOG_DEBUG);
5123
+            $resql = $this->db->query($sql);
5124
+            if (! $resql)
5125
+            {
5126
+                $this->error=$this->db->lasterror();
5127
+                $error++;
5128
+            }
5129
+
5130
+            if (! $error && $trigger)
5131
+            {
5132
+                // Call trigger
5133
+                $this->context=array('extrafieldaddupdate'=>1);
5134
+                $result=$this->call_trigger($trigger, $userused);
5135
+                if ($result < 0) $error++;
5136
+                // End call trigger
5137
+            }
5138
+
5139
+            if ($error)
5140
+            {
5141
+                $this->db->rollback();
5142
+                return -1;
5143
+            }
5144
+            else
5145
+            {
5146
+                $this->db->commit();
5147
+                return 1;
5148
+            }
5149
+        }
5150
+        else return 0;
5151
+    }
5152
+
5153
+    /**
5154
+     *	Update an extra field value for the current object.
5155
+     *  Data to describe values to update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
5156
+     *
5157
+     *  @param  string      $key    		Key of the extrafield (without starting 'options_')
5158
+     *  @param	string		$trigger		If defined, call also the trigger (for example COMPANY_MODIFY)
5159
+     *  @param	User		$userused		Object user
5160
+     *  @return int                 		-1=error, O=did nothing, 1=OK
5161
+     *  @see setValueFrom, insertExtraFields
5162
+     */
5163
+    function updateExtraField($key, $trigger=null, $userused=null)
5164
+    {
5165
+        global $conf,$langs,$user;
5166
+
5167
+        if (empty($userused)) $userused=$user;
5168
+
5169
+        $error=0;
5170
+
5171
+        if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0;	// For avoid conflicts if trigger used
5172
+
5173
+        if (! empty($this->array_options) && isset($this->array_options["options_".$key]))
5174
+        {
5175
+            // Check parameters
5176
+            $langs->load('admin');
5177
+            require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
5178
+            $extrafields = new ExtraFields($this->db);
5179
+            $target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
5180
+
5181
+            $value=$this->array_options["options_".$key];
5182
+
5183
+            $attributeType     = $extrafields->attributes[$this->table_element]['type'][$key];
5184
+            $attributeLabel    = $extrafields->attributes[$this->table_element]['label'][$key];
5185
+            $attributeParam    = $extrafields->attributes[$this->table_element]['param'][$key];
5186
+            $attributeRequired = $extrafields->attributes[$this->table_element]['required'][$key];
5187
+
5188
+            //dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
5189
+            //dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
5190
+
5191
+            switch ($attributeType)
5192
+            {
5193
+                case 'int':
5194
+                    if (!is_numeric($value) && $value!='')
5195
+                    {
5196
+                        $this->errors[]=$langs->trans("ExtraFieldHasWrongValue",$attributeLabel);
5197
+                        return -1;
5198
+                    }
5199
+                    elseif ($value=='')
5200
+                    {
5201
+                        $this->array_options["options_".$key] = null;
5202
+                    }
5203
+                    break;
5204
+                case 'double':
5205
+                    $value = price2num($value);
5206
+                    if (!is_numeric($value) && $value!='')
5207
+                    {
5208
+                        dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
5209
+                        $this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
5210
+                        return -1;
5211
+                    }
5212
+                    elseif ($value=='')
5213
+                    {
5214
+                        $this->array_options["options_".$key] = null;
5215
+                    }
5216
+                    //dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
5217
+                    $this->array_options["options_".$key] = $value;
5218
+                    break;
5219
+                    /*case 'select':	// Not required, we chosed value='0' for undefined values
5220
+             		if ($value=='-1')
5221
+             		{
5222
+             			$this->array_options[$key] = null;
5223
+             		}
5224
+             		break;*/
5225
+                case 'price':
5226
+                    $this->array_options["options_".$key] = price2num($this->array_options["options_".$key]);
5227
+                    break;
5228
+                case 'date':
5229
+                    $this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
5230
+                    break;
5231
+                case 'datetime':
5232
+                    $this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
5233
+                    break;
5234
+                case 'link':
5235
+                    $param_list=array_keys($attributeParam['options']);
5236
+                    // 0 : ObjectName
5237
+                    // 1 : classPath
5238
+                    $InfoFieldList = explode(":", $param_list[0]);
5239
+                    dol_include_once($InfoFieldList[1]);
5240
+                    if ($value)
5241
+                    {
5242
+                        $object = new $InfoFieldList[0]($this->db);
5243
+                        $object->fetch(0,$value);
5244
+                        $this->array_options["options_".$key]=$object->id;
5245
+                    }
5246
+                    break;
5247
+            }
5248
+
5249
+            $this->db->begin();
5250
+            $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element."_extrafields SET ".$key."='".$this->db->escape($this->array_options["options_".$key])."'";
5251
+            $sql .= " WHERE fk_object = ".$this->id;
5252
+            $resql = $this->db->query($sql);
5253
+            if (! $resql)
5254
+            {
5255
+                $error++;
5256
+                $this->error=$this->db->lasterror();
5257
+            }
5258
+
5259
+            if (! $error && $trigger)
5260
+            {
5261
+                // Call trigger
5262
+                $this->context=array('extrafieldupdate'=>1);
5263
+                $result=$this->call_trigger($trigger, $userused);
5264
+                if ($result < 0) $error++;
5265
+                // End call trigger
5266
+            }
5267
+
5268
+            if ($error)
5269
+            {
5270
+                dol_syslog(get_class($this) . "::".__METHOD__ . $this->error, LOG_ERR);
5271
+                $this->db->rollback();
5272
+                return -1;
5273
+            }
5274
+            else
5275
+            {
5276
+                $this->db->commit();
5277
+                return 1;
5278
+            }
5279
+        }
5280
+        else return 0;
5281
+    }
5282
+
5283
+
5284
+    /**
5285
+     * Return HTML string to put an input field into a page
5286
+     * Code very similar with showInputField of extra fields
5287
+     *
5288
+     * @param  array   		$val	       Array of properties for field to show
5289
+     * @param  string  		$key           Key of attribute
5290
+     * @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)
5291
+     * @param  string  		$moreparam     To add more parameters on html input tag
5292
+     * @param  string  		$keysuffix     Prefix string to add into name and id of field (can be used to avoid duplicate names)
5293
+     * @param  string  		$keyprefix     Suffix string to add into name and id of field (can be used to avoid duplicate names)
5294
+     * @param  string|int		$morecss       Value for css to define style/length of field. May also be a numeric.
5295
+     * @return string
5296
+     */
5297
+    function showInputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $morecss=0)
5298
+    {
5299
+        global $conf,$langs,$form;
5300
+
5301
+        if (! is_object($form))
5302
+        {
5303
+            require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5304
+            $form=new Form($this->db);
5305
+        }
5306
+
5307
+        $val=$this->fields[$key];
5308
+
5309
+        $out='';
5310
+        $type='';
5311
+        $param = array();
5312
+        $param['options']=array();
5313
+        $size =$this->fields[$key]['size'];
5314
+        // Because we work on extrafields
5315
+        if(preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)){
5316
+            $param['options']=array($reg[1].':'.$reg[2]=>'N');
5317
+            $type ='link';
5318
+        } elseif(preg_match('/^link:(.*):(.*)/i', $val['type'], $reg)) {
5319
+            $param['options']=array($reg[1].':'.$reg[2]=>'N');
5320
+            $type ='link';
5321
+        } elseif(preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
5322
+            $param['options']=array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4]=>'N');
5323
+            $type ='sellist';
5324
+        } elseif(preg_match('/varchar\((\d+)\)/', $val['type'],$reg)) {
5325
+            $param['options']=array();
5326
+            $type ='varchar';
5327
+            $size=$reg[1];
5328
+        } elseif(preg_match('/varchar/', $val['type'])) {
5329
+            $param['options']=array();
5330
+            $type ='varchar';
5331
+        } elseif(is_array($this->fields[$key]['arrayofkeyval'])) {
5332
+            $param['options']=$this->fields[$key]['arrayofkeyval'];
5333
+            $type ='select';
5334
+        } else {
5335
+            $param['options']=array();
5336
+            $type =$this->fields[$key]['type'];
5337
+        }
5338
+
5339
+        $label=$this->fields[$key]['label'];
5340
+        //$elementtype=$this->fields[$key]['elementtype'];	// Seems not used
5341
+        $default=$this->fields[$key]['default'];
5342
+        $computed=$this->fields[$key]['computed'];
5343
+        $unique=$this->fields[$key]['unique'];
5344
+        $required=$this->fields[$key]['required'];
5345
+
5346
+        $langfile=$this->fields[$key]['langfile'];
5347
+        $list=$this->fields[$key]['list'];
5348
+        $hidden=abs($this->fields[$key]['visible'])!=1?1:0;
5349
+
5350
+        $objectid = $this->id;
5351
+
5352
+
5353
+        if ($computed)
5354
+        {
5355
+            if (! preg_match('/^search_/', $keyprefix)) return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
5356
+            else return '';
5357
+        }
5358
+
5359
+
5360
+        // Use in priority showsize from parameters, then $val['css'] then autodefine
5361
+        if (empty($morecss) && ! empty($val['css']))
5362
+        {
5363
+            $showsize = $val['css'];
5364
+        }
5365
+        if (empty($morecss))
5366
+        {
5367
+            if ($type == 'date')
5368
+            {
5369
+                $morecss = 'minwidth100imp';
5370
+            }
5371
+            elseif ($type == 'datetime')
5372
+            {
5373
+                $morecss = 'minwidth200imp';
5374
+            }
5375
+            elseif (in_array($type,array('int','integer','price')) || preg_match('/^double(\([0-9],[0-9]\)){0,1}/',$type))
5376
+            {
5377
+                $morecss = 'maxwidth75';
5378
+                        }elseif ($type == 'url')
5379
+            {
5380
+                $morecss='minwidth400';
5381
+            }
5382
+            elseif ($type == 'boolean')
5383
+            {
5384
+                $morecss='';
5385
+            }
5386
+            else
5387
+            {
5388
+                if (round($size) < 12)
5389
+                {
5390
+                    $morecss = 'minwidth100';
5391
+                }
5392
+                else if (round($size) <= 48)
5393
+                {
5394
+                    $morecss = 'minwidth200';
5395
+                }
5396
+                else
5397
+                {
5398
+                    $morecss = 'minwidth400';
5399
+                }
5400
+            }
5401
+        }
5402
+
5403
+        if (in_array($type,array('date','datetime')))
5404
+        {
5405
+            $tmp=explode(',',$size);
5406
+            $newsize=$tmp[0];
5407
+
5408
+            $showtime = in_array($type,array('datetime')) ? 1 : 0;
5409
+
5410
+            // Do not show current date when field not required (see selectDate() method)
5411
+            if (!$required && $value == '') $value = '-1';
5412
+
5413
+            // TODO Must also support $moreparam
5414
+            $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
5415
+        }
5416
+        elseif (in_array($type,array('int','integer')))
5417
+        {
5418
+            $tmp=explode(',',$size);
5419
+            $newsize=$tmp[0];
5420
+            $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:'').'>';
5421
+        }
5422
+        elseif (preg_match('/varchar/', $type))
5423
+        {
5424
+            $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:'').'>';
5425
+        }
5426
+        elseif (in_array($type, array('mail', 'phone', 'url')))
5427
+        {
5428
+            $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5429
+        }
5430
+        elseif ($type == 'text')
5431
+        {
5432
+            if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
5433
+            {
5434
+                require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
5435
+                $doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,false,ROWS_5,'90%');
5436
+                $out=$doleditor->Create(1);
5437
+            }
5438
+            else
5439
+            {
5440
+                $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5441
+            }
5442
+        }
5443
+        elseif ($type == 'html')
5444
+        {
5445
+            if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
5446
+            {
5447
+                require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
5448
+                $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%');
5449
+                $out=$doleditor->Create(1);
5450
+            }
5451
+            else
5452
+            {
5453
+                $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5454
+            }
5455
+        }
5456
+        elseif ($type == 'boolean')
5457
+        {
5458
+            $checked='';
5459
+            if (!empty($value)) {
5460
+                $checked=' checked value="1" ';
5461
+            } else {
5462
+                $checked=' value="1" ';
5463
+            }
5464
+            $out='<input type="checkbox" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam?$moreparam:'').'>';
5465
+        }
5466
+        elseif ($type == 'price')
5467
+        {
5468
+            if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
5469
+                $value=price($value);
5470
+            }
5471
+            $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> '.$langs->getCurrencySymbol($conf->currency);
5472
+        }
5473
+        elseif (preg_match('/^double(\([0-9],[0-9]\)){0,1}/',$type))
5474
+        {
5475
+            if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
5476
+                $value=price($value);
5477
+            }
5478
+            $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> ';
5479
+        }
5480
+        elseif ($type == 'select')
5481
+        {
5482
+            $out = '';
5483
+            if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
5484
+            {
5485
+                include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5486
+                $out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
5487
+            }
5488
+
5489
+            $out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
5490
+                if((! isset($this->fields[$key]['default'])) ||($this->fields[$key]['notnull']!=1))$out.='<option value="0">&nbsp;</option>';
5491
+            foreach ($param['options'] as $key => $val)
5492
+            {
5493
+                if ((string) $key == '') continue;
5494
+                list($val, $parent) = explode('|', $val);
5495
+                $out.='<option value="'.$key.'"';
5496
+                $out.= (((string) $value == (string) $key)?' selected':'');
5497
+                $out.= (!empty($parent)?' parent="'.$parent.'"':'');
5498
+                $out.='>'.$val.'</option>';
5499
+            }
5500
+            $out.='</select>';
5501
+        }
5502
+        elseif ($type == 'sellist')
5503
+        {
5504
+            $out = '';
5505
+            if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
5506
+            {
5507
+                include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5508
+                $out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
5509
+            }
5510
+
5511
+            $out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
5512
+            if (is_array($param['options']))
5513
+            {
5514
+                $param_list=array_keys($param['options']);
5515
+                $InfoFieldList = explode(":", $param_list[0]);
5516
+                $parentName='';
5517
+                $parentField='';
5518
+                // 0 : tableName
5519
+                // 1 : label field name
5520
+                // 2 : key fields name (if differ of rowid)
5521
+                // 3 : key field parent (for dependent lists)
5522
+                // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5523
+                $keyList=(empty($InfoFieldList[2])?'rowid':$InfoFieldList[2].' as rowid');
5524
+
5525
+
5526
+                if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4]))
5527
+                {
5528
+                    if (strpos($InfoFieldList[4], 'extra.') !== false)
5529
+                    {
5530
+                        $keyList='main.'.$InfoFieldList[2].' as rowid';
5531
+                    } else {
5532
+                        $keyList=$InfoFieldList[2].' as rowid';
5533
+                    }
5534
+                }
5535
+                if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3]))
5536
+                {
5537
+                    list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
5538
+                    $keyList.= ', '.$parentField;
5539
+                }
5540
+
5541
+                $fields_label = explode('|',$InfoFieldList[1]);
5542
+                if (is_array($fields_label))
5543
+                {
5544
+                    $keyList .=', ';
5545
+                    $keyList .= implode(', ', $fields_label);
5546
+                }
5547
+
5548
+                $sqlwhere='';
5549
+                $sql = 'SELECT '.$keyList;
5550
+                $sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
5551
+                if (!empty($InfoFieldList[4]))
5552
+                {
5553
+                    // can use SELECT request
5554
+                    if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5555
+                        $InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5556
+                    }
5557
+
5558
+                    // current object id can be use into filter
5559
+                    if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5560
+                        $InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5561
+                    } else {
5562
+                        $InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5563
+                    }
5564
+                    //We have to join on extrafield table
5565
+                    if (strpos($InfoFieldList[4], 'extra')!==false)
5566
+                    {
5567
+                        $sql.= ' as main, '.MAIN_DB_PREFIX .$InfoFieldList[0].'_extrafields as extra';
5568
+                        $sqlwhere.= ' WHERE extra.fk_object=main.'.$InfoFieldList[2]. ' AND '.$InfoFieldList[4];
5569
+                    }
5570
+                    else
5571
+                    {
5572
+                        $sqlwhere.= ' WHERE '.$InfoFieldList[4];
5573
+                    }
5574
+                }
5575
+                else
5576
+                {
5577
+                    $sqlwhere.= ' WHERE 1=1';
5578
+                }
5579
+                // Some tables may have field, some other not. For the moment we disable it.
5580
+                if (in_array($InfoFieldList[0],array('tablewithentity')))
5581
+                {
5582
+                    $sqlwhere.= ' AND entity = '.$conf->entity;
5583
+                }
5584
+                $sql.=$sqlwhere;
5585
+                //print $sql;
5586
+
5587
+                $sql .= ' ORDER BY ' . implode(', ', $fields_label);
5588
+
5589
+                dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
5590
+                $resql = $this->db->query($sql);
5591
+                if ($resql)
5592
+                {
5593
+                    $out.='<option value="0">&nbsp;</option>';
5594
+                    $num = $this->db->num_rows($resql);
5595
+                    $i = 0;
5596
+                    while ($i < $num)
5597
+                    {
5598
+                        $labeltoshow='';
5599
+                        $obj = $this->db->fetch_object($resql);
5600
+
5601
+                        // Several field into label (eq table:code|libelle:rowid)
5602
+                        $notrans = false;
5603
+                        $fields_label = explode('|',$InfoFieldList[1]);
5604
+                        if (is_array($fields_label))
5605
+                        {
5606
+                            $notrans = true;
5607
+                            foreach ($fields_label as $field_toshow)
5608
+                            {
5609
+                                $labeltoshow.= $obj->$field_toshow.' ';
5610
+                            }
5611
+                        }
5612
+                        else
5613
+                        {
5614
+                            $labeltoshow=$obj->{$InfoFieldList[1]};
5615
+                        }
5616
+                        $labeltoshow=dol_trunc($labeltoshow,45);
5617
+
5618
+                        if ($value == $obj->rowid)
5619
+                        {
5620
+                            foreach ($fields_label as $field_toshow)
5621
+                            {
5622
+                                $translabel=$langs->trans($obj->$field_toshow);
5623
+                                if ($translabel!=$obj->$field_toshow) {
5624
+                                    $labeltoshow=dol_trunc($translabel,18).' ';
5625
+                                }else {
5626
+                                    $labeltoshow=dol_trunc($obj->$field_toshow,18).' ';
5627
+                                }
5628
+                            }
5629
+                            $out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5630
+                        }
5631
+                        else
5632
+                        {
5633
+                            if (! $notrans)
5634
+                            {
5635
+                                $translabel=$langs->trans($obj->{$InfoFieldList[1]});
5636
+                                if ($translabel!=$obj->{$InfoFieldList[1]}) {
5637
+                                    $labeltoshow=dol_trunc($translabel,18);
5638
+                                }
5639
+                                else {
5640
+                                    $labeltoshow=dol_trunc($obj->{$InfoFieldList[1]},18);
5641
+                                }
5642
+                            }
5643
+                            if (empty($labeltoshow)) $labeltoshow='(not defined)';
5644
+                            if ($value==$obj->rowid)
5645
+                            {
5646
+                                $out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5647
+                            }
5648
+
5649
+                            if (!empty($InfoFieldList[3]) && $parentField)
5650
+                            {
5651
+                                $parent = $parentName.':'.$obj->{$parentField};
5652
+                            }
5653
+
5654
+                            $out.='<option value="'.$obj->rowid.'"';
5655
+                            $out.= ($value==$obj->rowid?' selected':'');
5656
+                            $out.= (!empty($parent)?' parent="'.$parent.'"':'');
5657
+                            $out.='>'.$labeltoshow.'</option>';
5658
+                        }
5659
+
5660
+                        $i++;
5661
+                    }
5662
+                    $this->db->free($resql);
5663
+                }
5664
+                else {
5665
+                    print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
5666
+                }
5667
+            }
5668
+            $out.='</select>';
5669
+        }
5670
+        elseif ($type == 'checkbox')
5671
+        {
5672
+            $value_arr=explode(',',$value);
5673
+            $out=$form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options'])?null:$param['options']), $value_arr, '', 0, '', 0, '100%');
5674
+        }
5675
+        elseif ($type == 'radio')
5676
+        {
5677
+            $out='';
5678
+            foreach ($param['options'] as $keyopt => $val)
5679
+            {
5680
+                $out.='<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'');
5681
+                $out.=' value="'.$keyopt.'"';
5682
+                $out.=' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
5683
+                $out.= ($value==$keyopt?'checked':'');
5684
+                $out.='/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$val.'</label><br>';
5685
+            }
5686
+        }
5687
+        elseif ($type == 'chkbxlst')
5688
+        {
5689
+            if (is_array($value)) {
5690
+                $value_arr = $value;
5691
+            }
5692
+            else {
5693
+                $value_arr = explode(',', $value);
5694
+            }
5695
+
5696
+            if (is_array($param['options'])) {
5697
+                $param_list = array_keys($param['options']);
5698
+                $InfoFieldList = explode(":", $param_list[0]);
5699
+                $parentName='';
5700
+                $parentField='';
5701
+                // 0 : tableName
5702
+                // 1 : label field name
5703
+                // 2 : key fields name (if differ of rowid)
5704
+                // 3 : key field parent (for dependent lists)
5705
+                // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5706
+                $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
5707
+
5708
+                if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3])) {
5709
+                    list ( $parentName, $parentField ) = explode('|', $InfoFieldList[3]);
5710
+                    $keyList .= ', ' . $parentField;
5711
+                }
5712
+                if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4])) {
5713
+                    if (strpos($InfoFieldList[4], 'extra.') !== false) {
5714
+                        $keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
5715
+                    } else {
5716
+                        $keyList = $InfoFieldList[2] . ' as rowid';
5717
+                    }
5718
+                }
5719
+
5720
+                $fields_label = explode('|', $InfoFieldList[1]);
5721
+                if (is_array($fields_label)) {
5722
+                    $keyList .= ', ';
5723
+                    $keyList .= implode(', ', $fields_label);
5724
+                }
5725
+
5726
+                $sqlwhere = '';
5727
+                $sql = 'SELECT ' . $keyList;
5728
+                $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
5729
+                if (! empty($InfoFieldList[4])) {
5730
+
5731
+                    // can use SELECT request
5732
+                    if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5733
+                        $InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5734
+                    }
5735
+
5736
+                    // current object id can be use into filter
5737
+                    if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5738
+                        $InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5739
+                    } else {
5740
+                        $InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5741
+                    }
5742
+
5743
+                    // We have to join on extrafield table
5744
+                    if (strpos($InfoFieldList[4], 'extra') !== false) {
5745
+                        $sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
5746
+                        $sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
5747
+                    } else {
5748
+                        $sqlwhere .= ' WHERE ' . $InfoFieldList[4];
5749
+                    }
5750
+                } else {
5751
+                    $sqlwhere .= ' WHERE 1=1';
5752
+                }
5753
+                // Some tables may have field, some other not. For the moment we disable it.
5754
+                if (in_array($InfoFieldList[0], array ('tablewithentity')))
5755
+                {
5756
+                    $sqlwhere .= ' AND entity = ' . $conf->entity;
5757
+                }
5758
+                // $sql.=preg_replace('/^ AND /','',$sqlwhere);
5759
+                // print $sql;
5760
+
5761
+                $sql .= $sqlwhere;
5762
+                dol_syslog(get_class($this) . '::showInputField type=chkbxlst',LOG_DEBUG);
5763
+                $resql = $this->db->query($sql);
5764
+                if ($resql) {
5765
+                    $num = $this->db->num_rows($resql);
5766
+                    $i = 0;
5767
+
5768
+                    $data=array();
5769
+
5770
+                    while ( $i < $num ) {
5771
+                        $labeltoshow = '';
5772
+                        $obj = $this->db->fetch_object($resql);
5773
+
5774
+                        $notrans = false;
5775
+                        // Several field into label (eq table:code|libelle:rowid)
5776
+                        $fields_label = explode('|', $InfoFieldList[1]);
5777
+                        if (is_array($fields_label)) {
5778
+                            $notrans = true;
5779
+                            foreach ( $fields_label as $field_toshow ) {
5780
+                                $labeltoshow .= $obj->$field_toshow . ' ';
5781
+                            }
5782
+                        } else {
5783
+                            $labeltoshow = $obj->{$InfoFieldList[1]};
5784
+                        }
5785
+                        $labeltoshow = dol_trunc($labeltoshow, 45);
5786
+
5787
+                        if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5788
+                            foreach ( $fields_label as $field_toshow ) {
5789
+                                $translabel = $langs->trans($obj->$field_toshow);
5790
+                                if ($translabel != $obj->$field_toshow) {
5791
+                                    $labeltoshow = dol_trunc($translabel, 18) . ' ';
5792
+                                } else {
5793
+                                    $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
5794
+                                }
5795
+                            }
5796
+
5797
+                            $data[$obj->rowid]=$labeltoshow;
5798
+                        } else {
5799
+                            if (! $notrans) {
5800
+                                $translabel = $langs->trans($obj->{$InfoFieldList[1]});
5801
+                                if ($translabel != $obj->{$InfoFieldList[1]}) {
5802
+                                    $labeltoshow = dol_trunc($translabel, 18);
5803
+                                } else {
5804
+                                    $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
5805
+                                }
5806
+                            }
5807
+                            if (empty($labeltoshow))
5808
+                                $labeltoshow = '(not defined)';
5809
+
5810
+                                if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5811
+                                    $data[$obj->rowid]=$labeltoshow;
5812
+                                }
5813
+
5814
+                                if (! empty($InfoFieldList[3]) && $parentField) {
5815
+                                    $parent = $parentName . ':' . $obj->{$parentField};
5816
+                                }
5817
+
5818
+                                $data[$obj->rowid]=$labeltoshow;
5819
+                        }
5820
+
5821
+                        $i ++;
5822
+                    }
5823
+                    $this->db->free($resql);
5824
+
5825
+                    $out=$form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
5826
+                } else {
5827
+                    print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
5828
+                }
5829
+            }
5830
+        }
5831
+        elseif ($type == 'link')
5832
+        {
5833
+            $param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
5834
+            $showempty=(($required && $default != '')?0:1);
5835
+            $out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty);
5836
+            if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
5837
+            {
5838
+                        list($class,$classfile)=explode(':',$param_list[0]);
5839
+                        if (file_exists(dol_buildpath(dirname(dirname($classfile)).'/card.php'))) $url_path=dol_buildpath(dirname(dirname($classfile)).'/card.php',1);
5840
+                        else $url_path=dol_buildpath(dirname(dirname($classfile)).'/'.$class.'_card.php',1);
5841
+                        $out.='<a class="butActionNew" href="'.$url_path.'?action=create&backtopage='.$_SERVER['PHP_SELF'].'"><span class="fa fa-plus-circle valignmiddle"></span></a>';
5842
+                        // TODO Add Javascript code to add input fields contents to new elements urls
5843
+            }
5844
+        }
5845
+        elseif ($type == 'password')
5846
+        {
5847
+            // If prefix is 'search_', field is used as a filter, we use a common text field.
5848
+            $out='<input type="'.($keyprefix=='search_'?'text':'password').'" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'>';
5849
+        }
5850
+        elseif ($type == 'array')
5851
+        {
5852
+            $newval = $val;
5853
+            $newval['type'] = 'varchar(256)';
5854
+
5855
+            $out='';
5856
+
5857
+            $inputs = array();
5858
+            if(! empty($value)) {
5859
+                foreach($value as $option) {
5860
+                    $out.= '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
5861
+                    $out.= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', $option, $moreparam, '', '', $showsize).'<br></span>';
5862
+                }
5863
+            }
5864
+
5865
+            $out.= '<a id="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_add" href="javascript:;"><span class="fa fa-plus-circle valignmiddle"></span></a>';
5866
+
5867
+            $newInput = '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
5868
+            $newInput.= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', '', $moreparam, '', '', $showsize).'<br></span>';
5869
+
5870
+            if(! empty($conf->use_javascript_ajax)) {
5871
+                $out.= '
5872
+					<script type="text/javascript">
5873
+					$(document).ready(function() {
5874
+						$("a#'.dol_escape_js($keyprefix.$key.$keysuffix).'_add").click(function() {
5875
+							$("'.dol_escape_js($newInput).'").insertBefore(this);
5876
+						});
5877
+
5878
+						$(document).on("click", "a.'.dol_escape_js($keyprefix.$key.$keysuffix).'_del", function() {
5879
+							$(this).parent().remove();
5880
+						});
5881
+					});
5882
+					</script>';
5883
+            }
5884
+        }
5885
+        if (!empty($hidden)) {
5886
+            $out='<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
5887
+        }
5888
+        /* Add comments
5889
+		 if ($type == 'date') $out.=' (YYYY-MM-DD)';
5890
+		 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
5891
+		 */
5892
+        return $out;
5893
+    }
5894
+
5895
+    /**
5896
+     * Return HTML string to show a field into a page
5897
+     * Code very similar with showOutputField of extra fields
5898
+     *
5899
+     * @param  array   $val		       Array of properties of field to show
5900
+     * @param  string  $key            Key of attribute
5901
+     * @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)
5902
+     * @param  string  $moreparam      To add more parametes on html input tag
5903
+     * @param  string  $keysuffix      Prefix string to add into name and id of field (can be used to avoid duplicate names)
5904
+     * @param  string  $keyprefix      Suffix string to add into name and id of field (can be used to avoid duplicate names)
5905
+     * @param  mixed   $showsize       Value for css to define size. May also be a numeric.
5906
+     * @return string
5907
+     */
5908
+    function showOutputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $showsize=0)
5909
+    {
5910
+        global $conf,$langs,$form;
5911
+
5912
+        if (! is_object($form))
5913
+        {
5914
+            require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5915
+            $form=new Form($this->db);
5916
+        }
5917
+
5918
+        $objectid = $this->id;
5919
+        $label = $val['label'];
5920
+        $type  = $val['type'];
5921
+        $size  = $val['css'];
5922
+
5923
+        // Convert var to be able to share same code than showOutputField of extrafields
5924
+        if (preg_match('/varchar\((\d+)\)/', $type, $reg))
5925
+        {
5926
+            $type = 'varchar';		// convert varchar(xx) int varchar
5927
+            $size = $reg[1];
5928
+        }
5929
+        elseif (preg_match('/varchar/', $type)) $type = 'varchar';		// convert varchar(xx) int varchar
5930
+        if (is_array($val['arrayofkeyval'])) $type='select';
5931
+        if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) $type='link';
5932
+
5933
+        $default=$val['default'];
5934
+        $computed=$val['computed'];
5935
+        $unique=$val['unique'];
5936
+        $required=$val['required'];
5937
+        $param=$val['param'];
5938
+        if (is_array($val['arrayofkeyval'])) $param['options'] = $val['arrayofkeyval'];
5939
+        if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg))
5940
+        {
5941
+            $type='link';
5942
+            $param['options']=array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
5943
+        }
5944
+        $langfile=$val['langfile'];
5945
+        $list=$val['list'];
5946
+        $help=$val['help'];
5947
+        $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)
5948
+
5949
+        if ($hidden) return '';
5950
+
5951
+        // If field is a computed field, value must become result of compute
5952
+        if ($computed)
5953
+        {
5954
+            // Make the eval of compute string
5955
+            //var_dump($computed);
5956
+            $value = dol_eval($computed, 1, 0);
5957
+        }
5958
+
5959
+        if (empty($showsize))
5960
+        {
5961
+            if ($type == 'date')
5962
+            {
5963
+                //$showsize=10;
5964
+                $showsize = 'minwidth100imp';
5965
+            }
5966
+            elseif ($type == 'datetime')
5967
+            {
5968
+                //$showsize=19;
5969
+                $showsize = 'minwidth200imp';
5970
+            }
5971
+            elseif (in_array($type,array('int','double','price')))
5972
+            {
5973
+                //$showsize=10;
5974
+                $showsize = 'maxwidth75';
5975
+            }
5976
+            elseif ($type == 'url')
5977
+            {
5978
+                $showsize='minwidth400';
5979
+            }
5980
+            elseif ($type == 'boolean')
5981
+            {
5982
+                $showsize='';
5983
+            }
5984
+            else
5985
+            {
5986
+                if (round($size) < 12)
5987
+                {
5988
+                    $showsize = 'minwidth100';
5989
+                }
5990
+                else if (round($size) <= 48)
5991
+                {
5992
+                    $showsize = 'minwidth200';
5993
+                }
5994
+                else
5995
+                {
5996
+                    //$showsize=48;
5997
+                    $showsize = 'minwidth400';
5998
+                }
5999
+            }
6000
+        }
6001
+
6002
+        // Format output value differently according to properties of field
6003
+        if ($key == 'ref' && method_exists($this, 'getNomUrl')) $value=$this->getNomUrl(1, '', 0, '', 1);
6004
+        elseif ($key == 'status' && method_exists($this, 'getLibStatut')) $value=$this->getLibStatut(3);
6005
+        elseif ($type == 'date')
6006
+        {
6007
+            if(! empty($value)) {
6008
+                $value=dol_print_date($value,'day');
6009
+            } else {
6010
+                $value='';
6011
+            }
6012
+        }
6013
+        elseif ($type == 'datetime')
6014
+        {
6015
+            if(! empty($value)) {
6016
+                $value=dol_print_date($value,'dayhour');
6017
+            } else {
6018
+                $value='';
6019
+            }
6020
+        }
6021
+        elseif ($type == 'double')
6022
+        {
6023
+            if (!empty($value)) {
6024
+                $value=price($value);
6025
+            }
6026
+        }
6027
+        elseif ($type == 'boolean')
6028
+        {
6029
+            $checked='';
6030
+            if (!empty($value)) {
6031
+                $checked=' checked ';
6032
+            }
6033
+            $value='<input type="checkbox" '.$checked.' '.($moreparam?$moreparam:'').' readonly disabled>';
6034
+        }
6035
+        elseif ($type == 'mail')
6036
+        {
6037
+            $value=dol_print_email($value,0,0,0,64,1,1);
6038
+        }
6039
+        elseif ($type == 'url')
6040
+        {
6041
+            $value=dol_print_url($value,'_blank',32,1);
6042
+        }
6043
+        elseif ($type == 'phone')
6044
+        {
6045
+            $value=dol_print_phone($value, '', 0, 0, '', '&nbsp;', 1);
6046
+        }
6047
+        elseif ($type == 'price')
6048
+        {
6049
+            $value=price($value,0,$langs,0,0,-1,$conf->currency);
6050
+        }
6051
+        elseif ($type == 'select')
6052
+        {
6053
+            $value=$param['options'][$value];
6054
+        }
6055
+        elseif ($type == 'sellist')
6056
+        {
6057
+            $param_list=array_keys($param['options']);
6058
+            $InfoFieldList = explode(":", $param_list[0]);
6059
+
6060
+            $selectkey="rowid";
6061
+            $keyList='rowid';
6062
+
6063
+            if (count($InfoFieldList)>=3)
6064
+            {
6065
+                $selectkey = $InfoFieldList[2];
6066
+                $keyList=$InfoFieldList[2].' as rowid';
6067
+            }
6068
+
6069
+            $fields_label = explode('|',$InfoFieldList[1]);
6070
+            if(is_array($fields_label)) {
6071
+                $keyList .=', ';
6072
+                $keyList .= implode(', ', $fields_label);
6073
+            }
6074
+
6075
+            $sql = 'SELECT '.$keyList;
6076
+            $sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
6077
+            if (strpos($InfoFieldList[4], 'extra')!==false)
6078
+            {
6079
+                $sql.= ' as main';
6080
+            }
6081
+            if ($selectkey=='rowid' && empty($value)) {
6082
+                $sql.= " WHERE ".$selectkey."=0";
6083
+            } elseif ($selectkey=='rowid') {
6084
+                $sql.= " WHERE ".$selectkey."=".$this->db->escape($value);
6085
+            }else {
6086
+                $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
6087
+            }
6088
+
6089
+            //$sql.= ' AND entity = '.$conf->entity;
6090
+
6091
+            dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
6092
+            $resql = $this->db->query($sql);
6093
+            if ($resql)
6094
+            {
6095
+                $value='';	// value was used, so now we reste it to use it to build final output
6096
+
6097
+                $obj = $this->db->fetch_object($resql);
6098
+
6099
+                // Several field into label (eq table:code|libelle:rowid)
6100
+                $fields_label = explode('|',$InfoFieldList[1]);
6101
+
6102
+                if(is_array($fields_label) && count($fields_label)>1)
6103
+                {
6104
+                    foreach ($fields_label as $field_toshow)
6105
+                    {
6106
+                        $translabel='';
6107
+                        if (!empty($obj->$field_toshow)) {
6108
+                            $translabel=$langs->trans($obj->$field_toshow);
6109
+                        }
6110
+                        if ($translabel!=$field_toshow) {
6111
+                            $value.=dol_trunc($translabel,18).' ';
6112
+                        }else {
6113
+                            $value.=$obj->$field_toshow.' ';
6114
+                        }
6115
+                    }
6116
+                }
6117
+                else
6118
+                {
6119
+                    $translabel='';
6120
+                    if (!empty($obj->{$InfoFieldList[1]})) {
6121
+                        $translabel=$langs->trans($obj->{$InfoFieldList[1]});
6122
+                    }
6123
+                    if ($translabel!=$obj->{$InfoFieldList[1]}) {
6124
+                        $value=dol_trunc($translabel,18);
6125
+                    }else {
6126
+                        $value=$obj->{$InfoFieldList[1]};
6127
+                    }
6128
+                }
6129
+            }
6130
+            else dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
6131
+        }
6132
+        elseif ($type == 'radio')
6133
+        {
6134
+            $value=$param['options'][$value];
6135
+        }
6136
+        elseif ($type == 'checkbox')
6137
+        {
6138
+            $value_arr=explode(',',$value);
6139
+            $value='';
6140
+            if (is_array($value_arr) && count($value_arr)>0)
6141
+            {
6142
+                foreach ($value_arr as $keyval=>$valueval) {
6143
+                    $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$param['options'][$valueval].'</li>';
6144
+                }
6145
+                $value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6146
+            }
6147
+        }
6148
+        elseif ($type == 'chkbxlst')
6149
+        {
6150
+            $value_arr = explode(',', $value);
6151
+
6152
+            $param_list = array_keys($param['options']);
6153
+            $InfoFieldList = explode(":", $param_list[0]);
6154
+
6155
+            $selectkey = "rowid";
6156
+            $keyList = 'rowid';
6157
+
6158
+            if (count($InfoFieldList) >= 3) {
6159
+                $selectkey = $InfoFieldList[2];
6160
+                $keyList = $InfoFieldList[2] . ' as rowid';
6161
+            }
6162
+
6163
+            $fields_label = explode('|', $InfoFieldList[1]);
6164
+            if (is_array($fields_label)) {
6165
+                $keyList .= ', ';
6166
+                $keyList .= implode(', ', $fields_label);
6167
+            }
6168
+
6169
+            $sql = 'SELECT ' . $keyList;
6170
+            $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
6171
+            if (strpos($InfoFieldList[4], 'extra') !== false) {
6172
+                $sql .= ' as main';
6173
+            }
6174
+            // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
6175
+            // $sql.= ' AND entity = '.$conf->entity;
6176
+
6177
+            dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst',LOG_DEBUG);
6178
+            $resql = $this->db->query($sql);
6179
+            if ($resql) {
6180
+                $value = ''; // value was used, so now we reste it to use it to build final output
6181
+                $toprint=array();
6182
+                while ( $obj = $this->db->fetch_object($resql) ) {
6183
+
6184
+                    // Several field into label (eq table:code|libelle:rowid)
6185
+                    $fields_label = explode('|', $InfoFieldList[1]);
6186
+                    if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
6187
+                        if (is_array($fields_label) && count($fields_label) > 1) {
6188
+                            foreach ( $fields_label as $field_toshow ) {
6189
+                                $translabel = '';
6190
+                                if (! empty($obj->$field_toshow)) {
6191
+                                    $translabel = $langs->trans($obj->$field_toshow);
6192
+                                }
6193
+                                if ($translabel != $field_toshow) {
6194
+                                    $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
6195
+                                } else {
6196
+                                    $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->$field_toshow.'</li>';
6197
+                                }
6198
+                            }
6199
+                        } else {
6200
+                            $translabel = '';
6201
+                            if (! empty($obj->{$InfoFieldList[1]})) {
6202
+                                $translabel = $langs->trans($obj->{$InfoFieldList[1]});
6203
+                            }
6204
+                            if ($translabel != $obj->{$InfoFieldList[1]}) {
6205
+                                $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
6206
+                            } else {
6207
+                                $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->{$InfoFieldList[1]}.'</li>';
6208
+                            }
6209
+                        }
6210
+                    }
6211
+                }
6212
+                $value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6213
+            } else {
6214
+                dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING);
6215
+            }
6216
+        }
6217
+        elseif ($type == 'link')
6218
+        {
6219
+            $out='';
6220
+
6221
+            // only if something to display (perf)
6222
+            if ($value)
6223
+            {
6224
+                $param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
6225
+
6226
+                $InfoFieldList = explode(":", $param_list[0]);
6227
+                $classname=$InfoFieldList[0];
6228
+                $classpath=$InfoFieldList[1];
6229
+                $getnomurlparam=(empty($InfoFieldList[2]) ? 3 : $InfoFieldList[2]);
6230
+                if (! empty($classpath))
6231
+                {
6232
+                    dol_include_once($InfoFieldList[1]);
6233
+                    if ($classname && class_exists($classname))
6234
+                    {
6235
+                        $object = new $classname($this->db);
6236
+                        $object->fetch($value);
6237
+                        $value=$object->getNomUrl($getnomurlparam);
6238
+                    }
6239
+                }
6240
+                else
6241
+                {
6242
+                    dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6243
+                    return 'Error bad setup of extrafield';
6244
+                }
6245
+            }
6246
+            else $value='';
6247
+        }
6248
+        elseif ($type == 'text' || $type == 'html')
6249
+        {
6250
+            $value=dol_htmlentitiesbr($value);
6251
+        }
6252
+        elseif ($type == 'password')
6253
+        {
6254
+            $value=preg_replace('/./i','*',$value);
6255
+        }
6256
+        elseif ($type == 'array')
6257
+        {
6258
+            $value = implode('<br>', $value);
6259
+        }
6260
+
6261
+        //print $type.'-'.$size;
6262
+        $out=$value;
6263
+
6264
+        return $out;
6265
+    }
6266
+
6267
+
6268
+    /**
6269
+     * Function to show lines of extrafields with output datas
6270
+     *
6271
+     * @param 	Extrafields $extrafields    Extrafield Object
6272
+     * @param 	string      $mode           Show output (view) or input (edit) for extrafield
6273
+     * @param 	array       $params         Optional parameters. Example: array('style'=>'class="oddeven"', 'colspan'=>$colspan)
6274
+     * @param 	string      $keysuffix      Suffix string to add after name and id of field (can be used to avoid duplicate names)
6275
+     * @param 	string      $keyprefix      Prefix string to add before name and id of field (can be used to avoid duplicate names)
6276
+     * @param	string		$onetrtd		All fields in same tr td
6277
+     * @return 	string
6278
+     */
6279
+    function showOptionals($extrafields, $mode='view', $params=null, $keysuffix='', $keyprefix='', $onetrtd=0)
6280
+    {
6281
+        global $db, $conf, $langs, $action, $form;
6282
+
6283
+        if (! is_object($form)) $form=new Form($db);
6284
+
6285
+        $out = '';
6286
+
6287
+        if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label']) > 0)
6288
+        {
6289
+            $out .= "\n";
6290
+            $out .= '<!-- showOptionalsInput --> ';
6291
+            $out .= "\n";
6292
+
6293
+            $e = 0;
6294
+            foreach($extrafields->attributes[$this->table_element]['label'] as $key=>$label)
6295
+            {
6296
+                // Show only the key field in params
6297
+                if (is_array($params) && array_key_exists('onlykey',$params) && $key != $params['onlykey']) continue;
6298
+
6299
+                $enabled = 1;
6300
+                if ($enabled && isset($extrafields->attributes[$this->table_element]['list'][$key]))
6301
+                {
6302
+                    $enabled = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1);
6303
+                }
6304
+
6305
+                $perms = 1;
6306
+                if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key]))
6307
+                {
6308
+                    $perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1);
6309
+                }
6310
+
6311
+                if (($mode == 'create' || $mode == 'edit') && abs($enabled) != 1 && abs($enabled) != 3) continue;	// <> -1 and <> 1 and <> 3 = not visible on forms, only on list
6312
+                if (empty($perms)) continue;
6313
+
6314
+                // Load language if required
6315
+                if (! empty($extrafields->attributes[$this->table_element]['langfile'][$key])) $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
6316
+
6317
+                $colspan='3';
6318
+                if (is_array($params) && count($params)>0) {
6319
+                    if (array_key_exists('colspan',$params)) {
6320
+                        $colspan=$params['colspan'];
6321
+                    }
6322
+                }
6323
+
6324
+                switch($mode) {
6325
+                    case "view":
6326
+                        $value=$this->array_options["options_".$key.$keysuffix];
6327
+                        break;
6328
+                    case "edit":
6329
+                        $getposttemp = GETPOST($keyprefix.'options_'.$key.$keysuffix, 'none');				// GETPOST can get value from GET, POST or setup of default values.
6330
+                        // GETPOST("options_" . $key) can be 'abc' or array(0=>'abc')
6331
+                        if (is_array($getposttemp) || $getposttemp != '' || GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix))
6332
+                        {
6333
+                            if (is_array($getposttemp)) {
6334
+                                // $getposttemp is an array but following code expects a comma separated string
6335
+                                $value = implode(",", $getposttemp);
6336
+                            } else {
6337
+                                $value = $getposttemp;
6338
+                            }
6339
+                        } else {
6340
+                            $value = $this->array_options["options_" . $key];			// No GET, no POST, no default value, so we take value of object.
6341
+                        }
6342
+                        //var_dump($keyprefix.' - '.$key.' - '.$keysuffix.' - '.$keyprefix.'options_'.$key.$keysuffix.' - '.$this->array_options["options_".$key.$keysuffix].' - '.$getposttemp.' - '.$value);
6343
+                        break;
6344
+                }
6345
+
6346
+                if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate')
6347
+                {
6348
+                    $out .= $extrafields->showSeparator($key, $this);
6349
+                }
6350
+                else
6351
+                {
6352
+                    $csstyle='';
6353
+                    $class=(!empty($extrafields->attributes[$this->table_element]['hidden'][$key]) ? 'hideobject ' : '');
6354
+                    if (is_array($params) && count($params)>0) {
6355
+                        if (array_key_exists('style',$params)) {
6356
+                            $csstyle=$params['style'];
6357
+                        }
6358
+                    }
6359
+
6360
+                    // add html5 elements
6361
+                    $domData  = ' data-element="extrafield"';
6362
+                    $domData .= ' data-targetelement="'.$this->element.'"';
6363
+                    $domData .= ' data-targetid="'.$this->id.'"';
6364
+
6365
+                    $html_id = !empty($this->id) ? 'extrarow-'.$this->element.'_'.$key.'_'.$this->id : '';
6366
+
6367
+                    $out .= '<tr id="'.$html_id.'" '.$csstyle.' class="'.$class.$this->element.'_extras_'.$key.'" '.$domData.' >';
6368
+
6369
+                    if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0)
6370
+                    {
6371
+                        if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) { $colspan='0'; }
6372
+                    }
6373
+
6374
+                    if ($action == 'selectlines') { $colspan++; }
6375
+
6376
+                    // Convert date into timestamp format (value in memory must be a timestamp)
6377
+                    if (in_array($extrafields->attributes[$this->table_element]['type'][$key],array('date','datetime')))
6378
+                    {
6379
+                        $datenotinstring = $this->array_options['options_' . $key];
6380
+                        if (! is_numeric($this->array_options['options_' . $key]))	// For backward compatibility
6381
+                        {
6382
+                            $datenotinstring = $this->db->jdate($datenotinstring);
6383
+                        }
6384
+                        $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;
6385
+                    }
6386
+                    // Convert float submited string into real php numeric (value in memory must be a php numeric)
6387
+                    if (in_array($extrafields->attributes[$this->table_element]['type'][$key],array('price','double')))
6388
+                    {
6389
+                        $value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?price2num(GETPOST($keyprefix.'options_'.$key.$keysuffix, 'alpha', 3)):$this->array_options['options_'.$key];
6390
+                    }
6391
+
6392
+                    $labeltoshow = $langs->trans($label);
6393
+
6394
+                    $out .= '<td class="titlefield';
6395
+                    if (GETPOST('action','none') == 'create') $out.='create';
6396
+                    if ($mode != 'view' && ! empty($extrafields->attributes[$this->table_element]['required'][$key])) $out .= ' fieldrequired';
6397
+                    $out .= '">';
6398
+                    if (! empty($extrafields->attributes[$object->table_element]['help'][$key])) $out .= $form->textwithpicto($labeltoshow, $extrafields->attributes[$object->table_element]['help'][$key]);
6399
+                    else $out .= $labeltoshow;
6400
+                    $out .= '</td>';
6401
+
6402
+                    $html_id = !empty($this->id) ? $this->element.'_extras_'.$key.'_'.$this->id : '';
6403
+                    $out .='<td id="'.$html_id.'" class="'.$this->element.'_extras_'.$key.'" '.($colspan?' colspan="'.$colspan.'"':'').'>';
6404
+
6405
+                    switch($mode) {
6406
+                        case "view":
6407
+                            $out .= $extrafields->showOutputField($key, $value);
6408
+                            break;
6409
+                        case "edit":
6410
+                            $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id);
6411
+                            break;
6412
+                    }
6413
+
6414
+                    $out .= '</td>';
6415
+
6416
+                    if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && (($e % 2) == 1)) $out .= '</tr>';
6417
+                    else $out .= '</tr>';
6418
+                    $e++;
6419
+                }
6420
+            }
6421
+            $out .= "\n";
6422
+            // Add code to manage list depending on others
6423
+            if (! empty($conf->use_javascript_ajax)) {
6424
+                $out .= '
6425
+				<script type="text/javascript">
6426
+				    jQuery(document).ready(function() {
6427
+				    	function showOptions(child_list, parent_list)
6428
+				    	{
6429
+				    		var val = $("select[name=\"options_"+parent_list+"\"]").val();
6430
+				    		var parentVal = parent_list + ":" + val;
6431
+							if(val > 0) {
6432
+					    		$("select[name=\""+child_list+"\"] option[parent]").hide();
6433
+					    		$("select[name=\""+child_list+"\"] option[parent=\""+parentVal+"\"]").show();
6434
+							} else {
6435
+								$("select[name=\""+child_list+"\"] option").show();
5647 6436
 							}
6437
+				    	}
6438
+						function setListDependencies() {
6439
+					    	jQuery("select option[parent]").parent().each(function() {
6440
+					    		var child_list = $(this).attr("name");
6441
+								var parent = $(this).find("option[parent]:first").attr("parent");
6442
+								var infos = parent.split(":");
6443
+								var parent_list = infos[0];
6444
+								$("select[name=\""+parent_list+"\"]").change(function() {
6445
+									showOptions(child_list, parent_list);
6446
+								});
6447
+					    	});
6448
+						}
5648 6449
 
5649
-							if (!empty($InfoFieldList[3]) && $parentField)
5650
-							{
5651
-								$parent = $parentName.':'.$obj->{$parentField};
5652
-							}
6450
+						setListDependencies();
6451
+				    });
6452
+				</script>'."\n";
6453
+                $out .= '<!-- /showOptionalsInput --> '."\n";
6454
+            }
6455
+        }
6456
+        return $out;
6457
+    }
5653 6458
 
5654
-							$out.='<option value="'.$obj->rowid.'"';
5655
-							$out.= ($value==$obj->rowid?' selected':'');
5656
-							$out.= (!empty($parent)?' parent="'.$parent.'"':'');
5657
-							$out.='>'.$labeltoshow.'</option>';
5658
-						}
5659 6459
 
5660
-						$i++;
5661
-					}
5662
-					$this->db->free($resql);
5663
-				}
5664
-				else {
5665
-					print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
5666
-				}
5667
-			}
5668
-			$out.='</select>';
5669
-		}
5670
-		elseif ($type == 'checkbox')
5671
-		{
5672
-			$value_arr=explode(',',$value);
5673
-			$out=$form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options'])?null:$param['options']), $value_arr, '', 0, '', 0, '100%');
5674
-		}
5675
-		elseif ($type == 'radio')
5676
-		{
5677
-			$out='';
5678
-			foreach ($param['options'] as $keyopt => $val)
5679
-			{
5680
-				$out.='<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'');
5681
-				$out.=' value="'.$keyopt.'"';
5682
-				$out.=' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
5683
-				$out.= ($value==$keyopt?'checked':'');
5684
-				$out.='/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$val.'</label><br>';
5685
-			}
5686
-		}
5687
-		elseif ($type == 'chkbxlst')
5688
-		{
5689
-			if (is_array($value)) {
5690
-				$value_arr = $value;
5691
-			}
5692
-			else {
5693
-				$value_arr = explode(',', $value);
5694
-			}
5695
-
5696
-			if (is_array($param['options'])) {
5697
-				$param_list = array_keys($param['options']);
5698
-				$InfoFieldList = explode(":", $param_list[0]);
5699
-				$parentName='';
5700
-				$parentField='';
5701
-				// 0 : tableName
5702
-				// 1 : label field name
5703
-				// 2 : key fields name (if differ of rowid)
5704
-				// 3 : key field parent (for dependent lists)
5705
-				// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5706
-				$keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
5707
-
5708
-				if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3])) {
5709
-					list ( $parentName, $parentField ) = explode('|', $InfoFieldList[3]);
5710
-					$keyList .= ', ' . $parentField;
5711
-				}
5712
-				if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4])) {
5713
-					if (strpos($InfoFieldList[4], 'extra.') !== false) {
5714
-						$keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
5715
-					} else {
5716
-						$keyList = $InfoFieldList[2] . ' as rowid';
5717
-					}
5718
-				}
6460
+    /**
6461
+     * Returns the rights used for this class
6462
+     * @return stdClass
6463
+     */
6464
+    public function getRights()
6465
+    {
6466
+        global $user;
5719 6467
 
5720
-				$fields_label = explode('|', $InfoFieldList[1]);
5721
-				if (is_array($fields_label)) {
5722
-					$keyList .= ', ';
5723
-					$keyList .= implode(', ', $fields_label);
5724
-				}
6468
+        $element = $this->element;
6469
+        if ($element == 'facturerec') $element='facture';
5725 6470
 
5726
-				$sqlwhere = '';
5727
-				$sql = 'SELECT ' . $keyList;
5728
-				$sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
5729
-				if (! empty($InfoFieldList[4])) {
5730
-
5731
-					// can use SELECT request
5732
-					if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5733
-						$InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5734
-					}
5735
-
5736
-					// current object id can be use into filter
5737
-					if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5738
-						$InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5739
-					} else {
5740
-						$InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5741
-					}
5742
-
5743
-					// We have to join on extrafield table
5744
-					if (strpos($InfoFieldList[4], 'extra') !== false) {
5745
-						$sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
5746
-						$sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
5747
-					} else {
5748
-						$sqlwhere .= ' WHERE ' . $InfoFieldList[4];
5749
-					}
5750
-				} else {
5751
-					$sqlwhere .= ' WHERE 1=1';
5752
-				}
5753
-				// Some tables may have field, some other not. For the moment we disable it.
5754
-				if (in_array($InfoFieldList[0], array ('tablewithentity')))
5755
-				{
5756
-					$sqlwhere .= ' AND entity = ' . $conf->entity;
5757
-				}
5758
-				// $sql.=preg_replace('/^ AND /','',$sqlwhere);
5759
-				// print $sql;
5760
-
5761
-				$sql .= $sqlwhere;
5762
-				dol_syslog(get_class($this) . '::showInputField type=chkbxlst',LOG_DEBUG);
5763
-				$resql = $this->db->query($sql);
5764
-				if ($resql) {
5765
-					$num = $this->db->num_rows($resql);
5766
-					$i = 0;
5767
-
5768
-					$data=array();
5769
-
5770
-					while ( $i < $num ) {
5771
-						$labeltoshow = '';
5772
-						$obj = $this->db->fetch_object($resql);
5773
-
5774
-						$notrans = false;
5775
-						// Several field into label (eq table:code|libelle:rowid)
5776
-						$fields_label = explode('|', $InfoFieldList[1]);
5777
-						if (is_array($fields_label)) {
5778
-							$notrans = true;
5779
-							foreach ( $fields_label as $field_toshow ) {
5780
-								$labeltoshow .= $obj->$field_toshow . ' ';
5781
-							}
5782
-						} else {
5783
-							$labeltoshow = $obj->{$InfoFieldList[1]};
5784
-						}
5785
-						$labeltoshow = dol_trunc($labeltoshow, 45);
5786
-
5787
-						if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5788
-							foreach ( $fields_label as $field_toshow ) {
5789
-								$translabel = $langs->trans($obj->$field_toshow);
5790
-								if ($translabel != $obj->$field_toshow) {
5791
-									$labeltoshow = dol_trunc($translabel, 18) . ' ';
5792
-								} else {
5793
-									$labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
5794
-								}
5795
-							}
6471
+        return $user->rights->{$element};
6472
+    }
5796 6473
 
5797
-							$data[$obj->rowid]=$labeltoshow;
5798
-						} else {
5799
-							if (! $notrans) {
5800
-								$translabel = $langs->trans($obj->{$InfoFieldList[1]});
5801
-								if ($translabel != $obj->{$InfoFieldList[1]}) {
5802
-									$labeltoshow = dol_trunc($translabel, 18);
5803
-								} else {
5804
-									$labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
5805
-								}
5806
-							}
5807
-							if (empty($labeltoshow))
5808
-								$labeltoshow = '(not defined)';
6474
+    /**
6475
+     * Function used to replace a thirdparty id with another one.
6476
+     * This function is meant to be called from replaceThirdparty with the appropiate tables
6477
+     * Column name fk_soc MUST be used to identify thirdparties
6478
+     *
6479
+     * @param  DoliDB 	   $db 			  Database handler
6480
+     * @param  int 		   $origin_id     Old thirdparty id (the thirdparty to delete)
6481
+     * @param  int 		   $dest_id       New thirdparty id (the thirdparty that will received element of the other)
6482
+     * @param  string[]    $tables        Tables that need to be changed
6483
+     * @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)
6484
+     * @return bool						  True if success, False if error
6485
+     */
6486
+    public static function commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
6487
+    {
6488
+        foreach ($tables as $table)
6489
+        {
6490
+            $sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_soc = '.$dest_id.' WHERE fk_soc = '.$origin_id;
5809 6491
 
5810
-								if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5811
-									$data[$obj->rowid]=$labeltoshow;
5812
-								}
6492
+            if (! $db->query($sql))
6493
+            {
6494
+                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.
6495
+                //$this->errors = $db->lasterror();
6496
+                return false;
6497
+            }
6498
+        }
5813 6499
 
5814
-								if (! empty($InfoFieldList[3]) && $parentField) {
5815
-									$parent = $parentName . ':' . $obj->{$parentField};
5816
-								}
6500
+        return true;
6501
+    }
5817 6502
 
5818
-								$data[$obj->rowid]=$labeltoshow;
5819
-						}
6503
+    /**
6504
+     * Get buy price to use for margin calculation. This function is called when buy price is unknown.
6505
+     *	 Set buy price = sell price if ForceBuyingPriceIfNull configured,
6506
+     *   else if calculation MARGIN_TYPE = 'costprice' and costprice is defined, use costprice as buyprice
6507
+     *	 else if calculation MARGIN_TYPE = 'pmp' and pmp is calculated, use pmp as buyprice
6508
+     *	 else set min buy price as buy price
6509
+     *
6510
+     * @param float		$unitPrice		 Product unit price
6511
+     * @param float		$discountPercent Line discount percent
6512
+     * @param int		$fk_product		 Product id
6513
+     * @return	float                    <0 if KO, buyprice if OK
6514
+     */
6515
+    public function defineBuyPrice($unitPrice = 0.0, $discountPercent = 0.0, $fk_product = 0)
6516
+    {
6517
+        global $conf;
5820 6518
 
5821
-						$i ++;
5822
-					}
5823
-					$this->db->free($resql);
6519
+        $buyPrice = 0;
5824 6520
 
5825
-					$out=$form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
5826
-				} else {
5827
-					print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
5828
-				}
5829
-			}
5830
-		}
5831
-		elseif ($type == 'link')
5832
-		{
5833
-			$param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
5834
-			$showempty=(($required && $default != '')?0:1);
5835
-			$out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty);
5836
-			if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
5837
-			{
5838
-            			list($class,$classfile)=explode(':',$param_list[0]);
5839
-            			if (file_exists(dol_buildpath(dirname(dirname($classfile)).'/card.php'))) $url_path=dol_buildpath(dirname(dirname($classfile)).'/card.php',1);
5840
-            			else $url_path=dol_buildpath(dirname(dirname($classfile)).'/'.$class.'_card.php',1);
5841
-            			$out.='<a class="butActionNew" href="'.$url_path.'?action=create&backtopage='.$_SERVER['PHP_SELF'].'"><span class="fa fa-plus-circle valignmiddle"></span></a>';
5842
-            			// TODO Add Javascript code to add input fields contents to new elements urls
5843
-			}
5844
-		}
5845
-		elseif ($type == 'password')
5846
-		{
5847
-			// If prefix is 'search_', field is used as a filter, we use a common text field.
5848
-			$out='<input type="'.($keyprefix=='search_'?'text':'password').'" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'>';
5849
-		}
5850
-		elseif ($type == 'array')
5851
-		{
5852
-			$newval = $val;
5853
-			$newval['type'] = 'varchar(256)';
5854
-
5855
-			$out='';
5856
-
5857
-			$inputs = array();
5858
-			if(! empty($value)) {
5859
-				foreach($value as $option) {
5860
-					$out.= '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
5861
-					$out.= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', $option, $moreparam, '', '', $showsize).'<br></span>';
5862
-				}
5863
-			}
6521
+        if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) // In most cases, test here is false
6522
+        {
6523
+            $buyPrice = $unitPrice * (1 - $discountPercent / 100);
6524
+        }
6525
+        else
6526
+        {
6527
+            // Get cost price for margin calculation
6528
+            if (! empty($fk_product))
6529
+            {
6530
+                if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'costprice')
6531
+                {
6532
+                    require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6533
+                    $product = new Product($this->db);
6534
+                    $result = $product->fetch($fk_product);
6535
+                    if ($result <= 0)
6536
+                    {
6537
+                        $this->errors[] = 'ErrorProductIdDoesNotExists';
6538
+                        return -1;
6539
+                    }
6540
+                    if ($product->cost_price > 0)
6541
+                    {
6542
+                        $buyPrice = $product->cost_price;
6543
+                    }
6544
+                    else if ($product->pmp > 0)
6545
+                    {
6546
+                        $buyPrice = $product->pmp;
6547
+                    }
6548
+                }
6549
+                else if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'pmp')
6550
+                {
6551
+                    require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6552
+                    $product = new Product($this->db);
6553
+                    $result = $product->fetch($fk_product);
6554
+                    if ($result <= 0)
6555
+                    {
6556
+                        $this->errors[] = 'ErrorProductIdDoesNotExists';
6557
+                        return -1;
6558
+                    }
6559
+                    if ($product->pmp > 0)
6560
+                    {
6561
+                        $buyPrice = $product->pmp;
6562
+                    }
6563
+                }
6564
+
6565
+                if (empty($buyPrice) && isset($conf->global->MARGIN_TYPE) && in_array($conf->global->MARGIN_TYPE, array('1','pmp','costprice')))
6566
+                {
6567
+                    require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
6568
+                    $productFournisseur = new ProductFournisseur($this->db);
6569
+                    if (($result = $productFournisseur->find_min_price_product_fournisseur($fk_product)) > 0)
6570
+                    {
6571
+                        $buyPrice = $productFournisseur->fourn_unitprice;
6572
+                    }
6573
+                    else if ($result < 0)
6574
+                    {
6575
+                        $this->errors[] = $productFournisseur->error;
6576
+                        return -2;
6577
+                    }
6578
+                }
6579
+            }
6580
+        }
6581
+        return $buyPrice;
6582
+    }
5864 6583
 
5865
-			$out.= '<a id="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_add" href="javascript:;"><span class="fa fa-plus-circle valignmiddle"></span></a>';
6584
+    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
6585
+    /**
6586
+     *  Show photos of an object (nbmax maximum), into several columns
6587
+     *
6588
+     *  @param		string	$modulepart		'product', 'ticket', ...
6589
+     *  @param      string	$sdir        	Directory to scan (full absolute path)
6590
+     *  @param      int		$size        	0=original size, 1='small' use thumbnail if possible
6591
+     *  @param      int		$nbmax       	Nombre maximum de photos (0=pas de max)
6592
+     *  @param      int		$nbbyrow     	Number of image per line or -1 to use div. Used only if size=1.
6593
+     * 	@param		int		$showfilename	1=Show filename
6594
+     * 	@param		int		$showaction		1=Show icon with action links (resize, delete)
6595
+     * 	@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.
6596
+     * 	@param		int		$maxWidth		Max width of original image when size='small'
6597
+     *  @param      int     $nolink         Do not add a href link to view enlarged imaged into a new tab
6598
+     *  @param      int     $notitle        Do not add title tag on image
6599
+     *  @param		int		$usesharelink	Use the public shared link of image (if not available, the 'nophoto' image will be shown instead)
6600
+     *  @return     string					Html code to show photo. Number of photos shown is saved in this->nbphoto
6601
+     */
6602
+    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)
6603
+    {
6604
+        // phpcs:enable
6605
+        global $conf,$user,$langs;
5866 6606
 
5867
-			$newInput = '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
5868
-			$newInput.= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', '', $moreparam, '', '', $showsize).'<br></span>';
6607
+        include_once DOL_DOCUMENT_ROOT .'/core/lib/files.lib.php';
6608
+        include_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';
5869 6609
 
5870
-			if(! empty($conf->use_javascript_ajax)) {
5871
-				$out.= '
5872
-					<script type="text/javascript">
5873
-					$(document).ready(function() {
5874
-						$("a#'.dol_escape_js($keyprefix.$key.$keysuffix).'_add").click(function() {
5875
-							$("'.dol_escape_js($newInput).'").insertBefore(this);
5876
-						});
6610
+        $sortfield='position_name';
6611
+        $sortorder='asc';
5877 6612
 
5878
-						$(document).on("click", "a.'.dol_escape_js($keyprefix.$key.$keysuffix).'_del", function() {
5879
-							$(this).parent().remove();
5880
-						});
5881
-					});
5882
-					</script>';
5883
-			}
5884
-		}
5885
-		if (!empty($hidden)) {
5886
-			$out='<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
5887
-		}
5888
-		/* Add comments
5889
-		 if ($type == 'date') $out.=' (YYYY-MM-DD)';
5890
-		 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
5891
-		 */
5892
-		return $out;
5893
-	}
5894
-
5895
-	/**
5896
-	 * Return HTML string to show a field into a page
5897
-	 * Code very similar with showOutputField of extra fields
5898
-	 *
5899
-	 * @param  array   $val		       Array of properties of field to show
5900
-	 * @param  string  $key            Key of attribute
5901
-	 * @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)
5902
-	 * @param  string  $moreparam      To add more parametes on html input tag
5903
-	 * @param  string  $keysuffix      Prefix string to add into name and id of field (can be used to avoid duplicate names)
5904
-	 * @param  string  $keyprefix      Suffix string to add into name and id of field (can be used to avoid duplicate names)
5905
-	 * @param  mixed   $showsize       Value for css to define size. May also be a numeric.
5906
-	 * @return string
5907
-	 */
5908
-	function showOutputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $showsize=0)
5909
-	{
5910
-		global $conf,$langs,$form;
5911
-
5912
-		if (! is_object($form))
5913
-		{
5914
-			require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5915
-			$form=new Form($this->db);
5916
-		}
5917
-
5918
-		$objectid = $this->id;
5919
-		$label = $val['label'];
5920
-		$type  = $val['type'];
5921
-		$size  = $val['css'];
5922
-
5923
-		// Convert var to be able to share same code than showOutputField of extrafields
5924
-		if (preg_match('/varchar\((\d+)\)/', $type, $reg))
5925
-		{
5926
-			$type = 'varchar';		// convert varchar(xx) int varchar
5927
-			$size = $reg[1];
5928
-		}
5929
-		elseif (preg_match('/varchar/', $type)) $type = 'varchar';		// convert varchar(xx) int varchar
5930
-		if (is_array($val['arrayofkeyval'])) $type='select';
5931
-		if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) $type='link';
5932
-
5933
-		$default=$val['default'];
5934
-		$computed=$val['computed'];
5935
-		$unique=$val['unique'];
5936
-		$required=$val['required'];
5937
-		$param=$val['param'];
5938
-		if (is_array($val['arrayofkeyval'])) $param['options'] = $val['arrayofkeyval'];
5939
-		if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg))
5940
-		{
5941
-			$type='link';
5942
-			$param['options']=array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
5943
-		}
5944
-		$langfile=$val['langfile'];
5945
-		$list=$val['list'];
5946
-		$help=$val['help'];
5947
-		$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)
5948
-
5949
-		if ($hidden) return '';
5950
-
5951
-		// If field is a computed field, value must become result of compute
5952
-		if ($computed)
5953
-		{
5954
-			// Make the eval of compute string
5955
-			//var_dump($computed);
5956
-			$value = dol_eval($computed, 1, 0);
5957
-		}
5958
-
5959
-		if (empty($showsize))
5960
-		{
5961
-			if ($type == 'date')
5962
-			{
5963
-				//$showsize=10;
5964
-				$showsize = 'minwidth100imp';
5965
-			}
5966
-			elseif ($type == 'datetime')
5967
-			{
5968
-				//$showsize=19;
5969
-				$showsize = 'minwidth200imp';
5970
-			}
5971
-			elseif (in_array($type,array('int','double','price')))
5972
-			{
5973
-				//$showsize=10;
5974
-				$showsize = 'maxwidth75';
5975
-			}
5976
-			elseif ($type == 'url')
5977
-			{
5978
-				$showsize='minwidth400';
5979
-			}
5980
-			elseif ($type == 'boolean')
5981
-			{
5982
-				$showsize='';
5983
-			}
5984
-			else
5985
-			{
5986
-				if (round($size) < 12)
5987
-				{
5988
-					$showsize = 'minwidth100';
5989
-				}
5990
-				else if (round($size) <= 48)
5991
-				{
5992
-					$showsize = 'minwidth200';
5993
-				}
5994
-				else
5995
-				{
5996
-					//$showsize=48;
5997
-					$showsize = 'minwidth400';
5998
-				}
5999
-			}
6000
-		}
6001
-
6002
-		// Format output value differently according to properties of field
6003
-		if ($key == 'ref' && method_exists($this, 'getNomUrl')) $value=$this->getNomUrl(1, '', 0, '', 1);
6004
-		elseif ($key == 'status' && method_exists($this, 'getLibStatut')) $value=$this->getLibStatut(3);
6005
-		elseif ($type == 'date')
6006
-		{
6007
-			if(! empty($value)) {
6008
-				$value=dol_print_date($value,'day');
6009
-			} else {
6010
-				$value='';
6011
-			}
6012
-		}
6013
-		elseif ($type == 'datetime')
6014
-		{
6015
-			if(! empty($value)) {
6016
-				$value=dol_print_date($value,'dayhour');
6017
-			} else {
6018
-				$value='';
6019
-			}
6020
-		}
6021
-		elseif ($type == 'double')
6022
-		{
6023
-			if (!empty($value)) {
6024
-				$value=price($value);
6025
-			}
6026
-		}
6027
-		elseif ($type == 'boolean')
6028
-		{
6029
-			$checked='';
6030
-			if (!empty($value)) {
6031
-				$checked=' checked ';
6032
-			}
6033
-			$value='<input type="checkbox" '.$checked.' '.($moreparam?$moreparam:'').' readonly disabled>';
6034
-		}
6035
-		elseif ($type == 'mail')
6036
-		{
6037
-			$value=dol_print_email($value,0,0,0,64,1,1);
6038
-		}
6039
-		elseif ($type == 'url')
6040
-		{
6041
-			$value=dol_print_url($value,'_blank',32,1);
6042
-		}
6043
-		elseif ($type == 'phone')
6044
-		{
6045
-			$value=dol_print_phone($value, '', 0, 0, '', '&nbsp;', 1);
6046
-		}
6047
-		elseif ($type == 'price')
6048
-		{
6049
-			$value=price($value,0,$langs,0,0,-1,$conf->currency);
6050
-		}
6051
-		elseif ($type == 'select')
6052
-		{
6053
-			$value=$param['options'][$value];
6054
-		}
6055
-		elseif ($type == 'sellist')
6056
-		{
6057
-			$param_list=array_keys($param['options']);
6058
-			$InfoFieldList = explode(":", $param_list[0]);
6059
-
6060
-			$selectkey="rowid";
6061
-			$keyList='rowid';
6062
-
6063
-			if (count($InfoFieldList)>=3)
6064
-			{
6065
-				$selectkey = $InfoFieldList[2];
6066
-				$keyList=$InfoFieldList[2].' as rowid';
6067
-			}
6068
-
6069
-			$fields_label = explode('|',$InfoFieldList[1]);
6070
-			if(is_array($fields_label)) {
6071
-				$keyList .=', ';
6072
-				$keyList .= implode(', ', $fields_label);
6073
-			}
6074
-
6075
-			$sql = 'SELECT '.$keyList;
6076
-			$sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
6077
-			if (strpos($InfoFieldList[4], 'extra')!==false)
6078
-			{
6079
-				$sql.= ' as main';
6080
-			}
6081
-			if ($selectkey=='rowid' && empty($value)) {
6082
-				$sql.= " WHERE ".$selectkey."=0";
6083
-			} elseif ($selectkey=='rowid') {
6084
-				$sql.= " WHERE ".$selectkey."=".$this->db->escape($value);
6085
-			}else {
6086
-				$sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
6087
-			}
6088
-
6089
-			//$sql.= ' AND entity = '.$conf->entity;
6090
-
6091
-			dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
6092
-			$resql = $this->db->query($sql);
6093
-			if ($resql)
6094
-			{
6095
-				$value='';	// value was used, so now we reste it to use it to build final output
6613
+        $dir = $sdir . '/';
6614
+        $pdir = '/';
6615
+        if ($modulepart == 'ticket')
6616
+        {
6617
+            $dir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->track_id.'/';
6618
+            $pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->track_id.'/';
6619
+        }
6620
+        else
6621
+        {
6622
+            $dir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->ref.'/';
6623
+            $pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->ref.'/';
6624
+        }
6625
+
6626
+        // For backward compatibility
6627
+        if ($modulepart == 'product' && ! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))
6628
+        {
6629
+            $dir = $sdir . '/'. get_exdir($this->id,2,0,0,$this,$modulepart) . $this->id ."/photos/";
6630
+            $pdir = '/' . get_exdir($this->id,2,0,0,$this,$modulepart) . $this->id ."/photos/";
6631
+        }
6632
+
6633
+        // Defined relative dir to DOL_DATA_ROOT
6634
+        $relativedir = '';
6635
+        if ($dir)
6636
+        {
6637
+            $relativedir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $dir);
6638
+            $relativedir = preg_replace('/^[\\/]/','',$relativedir);
6639
+            $relativedir = preg_replace('/[\\/]$/','',$relativedir);
6640
+        }
6641
+
6642
+        $dirthumb = $dir.'thumbs/';
6643
+        $pdirthumb = $pdir.'thumbs/';
6644
+
6645
+        $return ='<!-- Photo -->'."\n";
6646
+        $nbphoto=0;
6647
+
6648
+        $filearray=dol_dir_list($dir,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
6649
+
6650
+        /*if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))    // For backward compatiblity, we scan also old dirs
6651
+		 {
6652
+		 $filearrayold=dol_dir_list($dirold,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
6653
+		 $filearray=array_merge($filearray, $filearrayold);
6654
+		 }*/
6655
+
6656
+        completeFileArrayWithDatabaseInfo($filearray, $relativedir);
6657
+
6658
+        if (count($filearray))
6659
+        {
6660
+            if ($sortfield && $sortorder)
6661
+            {
6662
+                $filearray=dol_sort_array($filearray, $sortfield, $sortorder);
6663
+            }
6664
+
6665
+            foreach($filearray as $key => $val)
6666
+            {
6667
+                $photo='';
6668
+                $file = $val['name'];
6669
+
6670
+                //if (! utf8_check($file)) $file=utf8_encode($file);	// To be sure file is stored in UTF8 in memory
6671
+
6672
+                //if (dol_is_file($dir.$file) && image_format_supported($file) >= 0)
6673
+                if (image_format_supported($file) >= 0)
6674
+                {
6675
+                    $nbphoto++;
6676
+                    $photo = $file;
6677
+                    $viewfilename = $file;
6678
+
6679
+                    if ($size == 1 || $size == 'small') {   // Format vignette
6680
+
6681
+                        // Find name of thumb file
6682
+                        $photo_vignette=basename(getImageFileNameForSize($dir.$file, '_small'));
6683
+                        if (! dol_is_file($dirthumb.$photo_vignette)) $photo_vignette='';
6684
+
6685
+                        // Get filesize of original file
6686
+                        $imgarray=dol_getImageSize($dir.$photo);
6687
+
6688
+                        if ($nbbyrow > 0)
6689
+                        {
6690
+                            if ($nbphoto == 1) $return.= '<table width="100%" valign="top" align="center" border="0" cellpadding="2" cellspacing="2">';
6691
+
6692
+                            if ($nbphoto % $nbbyrow == 1) $return.= '<tr align=center valign=middle border=1>';
6693
+                            $return.= '<td width="'.ceil(100/$nbbyrow).'%" class="photo">';
6694
+                        }
6695
+                        else if ($nbbyrow < 0) $return .= '<div class="inline-block">';
6696
+
6697
+                        $return.= "\n";
6698
+
6699
+                        $relativefile=preg_replace('/^\//', '', $pdir.$photo);
6700
+                        if (empty($nolink))
6701
+                        {
6702
+                            $urladvanced=getAdvancedPreviewUrl($modulepart, $relativefile, 0, 'entity='.$this->entity);
6703
+                            if ($urladvanced) $return.='<a href="'.$urladvanced.'">';
6704
+                            else $return.= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'" class="aphoto" target="_blank">';
6705
+                        }
6706
+
6707
+                        // Show image (width height=$maxHeight)
6708
+                        // Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine
6709
+                        $alt=$langs->transnoentitiesnoconv('File').': '.$relativefile;
6710
+                        $alt.=' - '.$langs->transnoentitiesnoconv('Size').': '.$imgarray['width'].'x'.$imgarray['height'];
6711
+                        if ($notitle) $alt='';
6712
+
6713
+                        if ($usesharelink)
6714
+                        {
6715
+                            if ($val['share'])
6716
+                            {
6717
+                                if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight)
6718
+                                {
6719
+                                    $return.= '<!-- Show original file (thumb not yet available with shared links) -->';
6720
+                                    $return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).'" title="'.dol_escape_htmltag($alt).'">';
6721
+                                }
6722
+                                else {
6723
+                                    $return.= '<!-- Show original file -->';
6724
+                                    $return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).'" title="'.dol_escape_htmltag($alt).'">';
6725
+                                }
6726
+                            }
6727
+                            else
6728
+                            {
6729
+                                $return.= '<!-- Show nophoto file (because file is not shared) -->';
6730
+                                $return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/public/theme/common/nophoto.png" title="'.dol_escape_htmltag($alt).'">';
6731
+                            }
6732
+                        }
6733
+                        else
6734
+                        {
6735
+                            if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight)
6736
+                            {
6737
+                                $return.= '<!-- Show thumb -->';
6738
+                                $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).'">';
6739
+                            }
6740
+                            else {
6741
+                                $return.= '<!-- Show original file -->';
6742
+                                $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).'">';
6743
+                            }
6744
+                        }
6745
+
6746
+                        if (empty($nolink)) $return.= '</a>';
6747
+                        $return.="\n";
6748
+
6749
+                        if ($showfilename) $return.= '<br>'.$viewfilename;
6750
+                        if ($showaction)
6751
+                        {
6752
+                            $return.= '<br>';
6753
+                            // On propose la generation de la vignette si elle n'existe pas et si la taille est superieure aux limites
6754
+                            if ($photo_vignette && (image_format_supported($photo) > 0) && ($this->imgWidth > $maxWidth || $this->imgHeight > $maxHeight))
6755
+                            {
6756
+                                $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>';
6757
+                            }
6758
+                            // Special cas for product
6759
+                            if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer))
6760
+                            {
6761
+                                // Link to resize
6762
+                                $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; ';
6763
+
6764
+                                // Link to delete
6765
+                                $return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=delete&amp;file='.urlencode($pdir.$viewfilename).'">';
6766
+                                $return.= img_delete().'</a>';
6767
+                            }
6768
+                        }
6769
+                        $return.= "\n";
6770
+
6771
+                        if ($nbbyrow > 0)
6772
+                        {
6773
+                            $return.= '</td>';
6774
+                            if (($nbphoto % $nbbyrow) == 0) $return.= '</tr>';
6775
+                        }
6776
+                        else if ($nbbyrow < 0) $return.='</div>';
6777
+                    }
6778
+
6779
+                    if (empty($size)) {     // Format origine
6780
+                        $return.= '<img class="photo photowithmargin" border="0" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'">';
6781
+
6782
+                        if ($showfilename) $return.= '<br>'.$viewfilename;
6783
+                        if ($showaction)
6784
+                        {
6785
+                            // Special case for product
6786
+                            if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer))
6787
+                            {
6788
+                                // Link to resize
6789
+                                $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; ';
6790
+
6791
+                                // Link to delete
6792
+                                $return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=delete&amp;file='.urlencode($pdir.$viewfilename).'">';
6793
+                                $return.= img_delete().'</a>';
6794
+                            }
6795
+                        }
6796
+                    }
6797
+
6798
+                    // On continue ou on arrete de boucler ?
6799
+                    if ($nbmax && $nbphoto >= $nbmax) break;
6800
+                }
6801
+            }
6802
+
6803
+            if ($size==1 || $size=='small')
6804
+            {
6805
+                if ($nbbyrow > 0)
6806
+                {
6807
+                    // Ferme tableau
6808
+                    while ($nbphoto % $nbbyrow)
6809
+                    {
6810
+                        $return.= '<td width="'.ceil(100/$nbbyrow).'%">&nbsp;</td>';
6811
+                        $nbphoto++;
6812
+                    }
6813
+
6814
+                    if ($nbphoto) $return.= '</table>';
6815
+                }
6816
+            }
6817
+        }
6818
+
6819
+        $this->nbphoto = $nbphoto;
6820
+
6821
+        return $return;
6822
+    }
6823
+
6824
+
6825
+    /**
6826
+     * Function test if type is array
6827
+     *
6828
+     * @param   array   $info   content informations of field
6829
+     * @return                  bool
6830
+     */
6831
+    protected function isArray($info)
6832
+    {
6833
+        if(is_array($info))
6834
+        {
6835
+            if(isset($info['type']) && $info['type']=='array') return true;
6836
+            else return false;
6837
+        }
6838
+        else return false;
6839
+    }
6840
+
6841
+    /**
6842
+     * Function test if type is null
6843
+     *
6844
+     * @param   array   $info   content informations of field
6845
+     * @return                  bool
6846
+     */
6847
+    protected function isNull($info)
6848
+    {
6849
+        if(is_array($info))
6850
+        {
6851
+            if(isset($info['type']) && $info['type']=='null') return true;
6852
+            else return false;
6853
+        }
6854
+        else return false;
6855
+    }
6856
+
6857
+    /**
6858
+     * Function test if type is date
6859
+     *
6860
+     * @param   array   $info   content informations of field
6861
+     * @return                  bool
6862
+     */
6863
+    public function isDate($info)
6864
+    {
6865
+        if(isset($info['type']) && ($info['type']=='date' || $info['type']=='datetime' || $info['type']=='timestamp')) return true;
6866
+        else return false;
6867
+    }
6868
+
6869
+    /**
6870
+     * Function test if type is integer
6871
+     *
6872
+     * @param   array   $info   content informations of field
6873
+     * @return                  bool
6874
+     */
6875
+    public function isInt($info)
6876
+    {
6877
+        if(is_array($info))
6878
+        {
6879
+            if(isset($info['type']) && ($info['type']=='int' || preg_match('/^integer/i',$info['type']) ) ) return true;
6880
+            else return false;
6881
+        }
6882
+        else return false;
6883
+    }
6884
+
6885
+    /**
6886
+     * Function test if type is float
6887
+     *
6888
+     * @param   array   $info   content informations of field
6889
+     * @return                  bool
6890
+     */
6891
+    public function isFloat($info)
6892
+    {
6893
+        if(is_array($info))
6894
+        {
6895
+            if (isset($info['type']) && (preg_match('/^(double|real)/i', $info['type']))) return true;
6896
+            else return false;
6897
+        }
6898
+        else return false;
6899
+    }
6900
+
6901
+    /**
6902
+     * Function test if type is text
6903
+     *
6904
+     * @param   array   $info   content informations of field
6905
+     * @return                  bool
6906
+     */
6907
+    public function isText($info)
6908
+    {
6909
+        if(is_array($info))
6910
+        {
6911
+            if(isset($info['type']) && $info['type']=='text') return true;
6912
+            else return false;
6913
+        }
6914
+        else return false;
6915
+    }
6916
+
6917
+    /**
6918
+     * Function test if is indexed
6919
+     *
6920
+     * @param   array   $info   content informations of field
6921
+     * @return                  bool
6922
+     */
6923
+    protected function isIndex($info)
6924
+    {
6925
+        if(is_array($info))
6926
+        {
6927
+            if(isset($info['index']) && $info['index']==true) return true;
6928
+            else return false;
6929
+        }
6930
+        else return false;
6931
+    }
6932
+
6933
+    /**
6934
+     * Function to prepare the values to insert.
6935
+     * Note $this->${field} are set by the page that make the createCommon or the updateCommon.
6936
+     *
6937
+     * @return array
6938
+     */
6939
+    protected function setSaveQuery()
6940
+    {
6941
+        global $conf;
6942
+
6943
+        $queryarray=array();
6944
+        foreach ($this->fields as $field=>$info)	// Loop on definition of fields
6945
+        {
6946
+            // Depending on field type ('datetime', ...)
6947
+            if($this->isDate($info))
6948
+            {
6949
+                if(empty($this->{$field}))
6950
+                {
6951
+                    $queryarray[$field] = null;
6952
+                }
6953
+                else
6954
+                {
6955
+                    $queryarray[$field] = $this->db->idate($this->{$field});
6956
+                }
6957
+            }
6958
+            else if($this->isArray($info))
6959
+            {
6960
+                if(! empty($this->{$field})) {
6961
+                    if(! is_array($this->{$field})) {
6962
+                        $this->{$field} = array($this->{$field});
6963
+                    }
6964
+                    $queryarray[$field] = serialize($this->{$field});
6965
+                } else {
6966
+                    $queryarray[$field] = null;
6967
+                }
6968
+            }
6969
+            else if($this->isInt($info))
6970
+            {
6971
+                if ($field == 'entity' && is_null($this->{$field})) $queryarray[$field]=$conf->entity;
6972
+                else
6973
+                {
6974
+                    $queryarray[$field] = (int) price2num($this->{$field});
6975
+                    if (empty($queryarray[$field])) $queryarray[$field]=0;		// May be reset to null later if property 'notnull' is -1 for this field.
6976
+                }
6977
+            }
6978
+            else if($this->isFloat($info))
6979
+            {
6980
+                $queryarray[$field] = (double) price2num($this->{$field});
6981
+                if (empty($queryarray[$field])) $queryarray[$field]=0;
6982
+            }
6983
+            else
6984
+            {
6985
+                $queryarray[$field] = $this->{$field};
6986
+            }
6987
+
6988
+            if ($info['type'] == 'timestamp' && empty($queryarray[$field])) unset($queryarray[$field]);
6989
+            if (! empty($info['notnull']) && $info['notnull'] == -1 && empty($queryarray[$field])) $queryarray[$field] = null;
6990
+        }
6991
+
6992
+        return $queryarray;
6993
+    }
6994
+
6995
+    /**
6996
+     * Function to load data from a SQL pointer into properties of current object $this
6997
+     *
6998
+     * @param   stdClass    $obj    Contain data of object from database
6999
+     * @return void
7000
+     */
7001
+    protected function setVarsFromFetchObj(&$obj)
7002
+    {
7003
+        foreach ($this->fields as $field => $info)
7004
+        {
7005
+            if($this->isDate($info))
7006
+            {
7007
+                if(empty($obj->{$field}) || $obj->{$field} === '0000-00-00 00:00:00' || $obj->{$field} === '1000-01-01 00:00:00') $this->{$field} = 0;
7008
+                else $this->{$field} = strtotime($obj->{$field});
7009
+            }
7010
+            elseif($this->isArray($info))
7011
+            {
7012
+                if(! empty($obj->{$field})) {
7013
+                    $this->{$field} = @unserialize($obj->{$field});
7014
+                    // Hack for data not in UTF8
7015
+                    if($this->{$field } === false) @unserialize(utf8_decode($obj->{$field}));
7016
+                } else {
7017
+                    $this->{$field} = array();
7018
+                }
7019
+            }
7020
+            elseif($this->isInt($info))
7021
+            {
7022
+                if ($field == 'rowid') $this->id = (int) $obj->{$field};
7023
+                else $this->{$field} = (int) $obj->{$field};
7024
+            }
7025
+            elseif($this->isFloat($info))
7026
+            {
7027
+                $this->{$field} = (double) $obj->{$field};
7028
+            }
7029
+            elseif($this->isNull($info))
7030
+            {
7031
+                $val = $obj->{$field};
7032
+                // zero is not null
7033
+                $this->{$field} = (is_null($val) || (empty($val) && $val!==0 && $val!=='0') ? null : $val);
7034
+            }
7035
+            else
7036
+            {
7037
+                $this->{$field} = $obj->{$field};
7038
+            }
7039
+        }
7040
+
7041
+        // If there is no 'ref' field, we force property ->ref to ->id for a better compatibility with common functions.
7042
+        if (! isset($this->fields['ref']) && isset($this->id)) $this->ref = $this->id;
7043
+    }
7044
+
7045
+    /**
7046
+     * Function to concat keys of fields
7047
+     *
7048
+     * @return string
7049
+     */
7050
+    protected function getFieldList()
7051
+    {
7052
+        $keys = array_keys($this->fields);
7053
+        return implode(',', $keys);
7054
+    }
7055
+
7056
+    /**
7057
+     * Add quote to field value if necessary
7058
+     *
7059
+     * @param 	string|int	$value			Value to protect
7060
+     * @param	array		$fieldsentry	Properties of field
7061
+     * @return 	string
7062
+     */
7063
+    protected function quote($value, $fieldsentry)
7064
+    {
7065
+        if (is_null($value)) return 'NULL';
7066
+        else if (preg_match('/^(int|double|real)/i', $fieldsentry['type'])) return $this->db->escape("$value");
7067
+        else return "'".$this->db->escape($value)."'";
7068
+    }
7069
+
7070
+
7071
+    /**
7072
+     * Create object into database
7073
+     *
7074
+     * @param  User $user      User that creates
7075
+     * @param  bool $notrigger false=launch triggers after, true=disable triggers
7076
+     * @return int             <0 if KO, Id of created object if OK
7077
+     */
7078
+    public function createCommon(User $user, $notrigger = false)
7079
+    {
7080
+        global $langs;
6096 7081
 
6097
-				$obj = $this->db->fetch_object($resql);
7082
+        $error = 0;
6098 7083
 
6099
-				// Several field into label (eq table:code|libelle:rowid)
6100
-				$fields_label = explode('|',$InfoFieldList[1]);
7084
+        $now=dol_now();
6101 7085
 
6102
-				if(is_array($fields_label) && count($fields_label)>1)
6103
-				{
6104
-					foreach ($fields_label as $field_toshow)
6105
-					{
6106
-						$translabel='';
6107
-						if (!empty($obj->$field_toshow)) {
6108
-							$translabel=$langs->trans($obj->$field_toshow);
6109
-						}
6110
-						if ($translabel!=$field_toshow) {
6111
-							$value.=dol_trunc($translabel,18).' ';
6112
-						}else {
6113
-							$value.=$obj->$field_toshow.' ';
6114
-						}
6115
-					}
6116
-				}
6117
-				else
6118
-				{
6119
-					$translabel='';
6120
-					if (!empty($obj->{$InfoFieldList[1]})) {
6121
-						$translabel=$langs->trans($obj->{$InfoFieldList[1]});
6122
-					}
6123
-					if ($translabel!=$obj->{$InfoFieldList[1]}) {
6124
-						$value=dol_trunc($translabel,18);
6125
-					}else {
6126
-						$value=$obj->{$InfoFieldList[1]};
6127
-					}
6128
-				}
6129
-			}
6130
-			else dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
6131
-		}
6132
-		elseif ($type == 'radio')
6133
-		{
6134
-			$value=$param['options'][$value];
6135
-		}
6136
-		elseif ($type == 'checkbox')
6137
-		{
6138
-			$value_arr=explode(',',$value);
6139
-			$value='';
6140
-			if (is_array($value_arr) && count($value_arr)>0)
6141
-			{
6142
-				foreach ($value_arr as $keyval=>$valueval) {
6143
-					$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$param['options'][$valueval].'</li>';
6144
-				}
6145
-				$value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6146
-			}
6147
-		}
6148
-		elseif ($type == 'chkbxlst')
6149
-		{
6150
-			$value_arr = explode(',', $value);
6151
-
6152
-			$param_list = array_keys($param['options']);
6153
-			$InfoFieldList = explode(":", $param_list[0]);
6154
-
6155
-			$selectkey = "rowid";
6156
-			$keyList = 'rowid';
6157
-
6158
-			if (count($InfoFieldList) >= 3) {
6159
-				$selectkey = $InfoFieldList[2];
6160
-				$keyList = $InfoFieldList[2] . ' as rowid';
6161
-			}
6162
-
6163
-			$fields_label = explode('|', $InfoFieldList[1]);
6164
-			if (is_array($fields_label)) {
6165
-				$keyList .= ', ';
6166
-				$keyList .= implode(', ', $fields_label);
6167
-			}
6168
-
6169
-			$sql = 'SELECT ' . $keyList;
6170
-			$sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
6171
-			if (strpos($InfoFieldList[4], 'extra') !== false) {
6172
-				$sql .= ' as main';
6173
-			}
6174
-			// $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
6175
-			// $sql.= ' AND entity = '.$conf->entity;
6176
-
6177
-			dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst',LOG_DEBUG);
6178
-			$resql = $this->db->query($sql);
6179
-			if ($resql) {
6180
-				$value = ''; // value was used, so now we reste it to use it to build final output
6181
-				$toprint=array();
6182
-				while ( $obj = $this->db->fetch_object($resql) ) {
6183
-
6184
-					// Several field into label (eq table:code|libelle:rowid)
6185
-					$fields_label = explode('|', $InfoFieldList[1]);
6186
-					if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
6187
-						if (is_array($fields_label) && count($fields_label) > 1) {
6188
-							foreach ( $fields_label as $field_toshow ) {
6189
-								$translabel = '';
6190
-								if (! empty($obj->$field_toshow)) {
6191
-									$translabel = $langs->trans($obj->$field_toshow);
6192
-								}
6193
-								if ($translabel != $field_toshow) {
6194
-									$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
6195
-								} else {
6196
-									$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->$field_toshow.'</li>';
6197
-								}
6198
-							}
6199
-						} else {
6200
-							$translabel = '';
6201
-							if (! empty($obj->{$InfoFieldList[1]})) {
6202
-								$translabel = $langs->trans($obj->{$InfoFieldList[1]});
6203
-							}
6204
-							if ($translabel != $obj->{$InfoFieldList[1]}) {
6205
-								$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
6206
-							} else {
6207
-								$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->{$InfoFieldList[1]}.'</li>';
6208
-							}
6209
-						}
6210
-					}
6211
-				}
6212
-				$value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6213
-			} else {
6214
-				dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING);
6215
-			}
6216
-		}
6217
-		elseif ($type == 'link')
6218
-		{
6219
-			$out='';
6220
-
6221
-			// only if something to display (perf)
6222
-			if ($value)
6223
-			{
6224
-				$param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
7086
+        $fieldvalues = $this->setSaveQuery();
7087
+        if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) $fieldvalues['date_creation']=$this->db->idate($now);
7088
+        if (array_key_exists('fk_user_creat', $fieldvalues) && ! ($fieldvalues['fk_user_creat'] > 0)) $fieldvalues['fk_user_creat']=$user->id;
7089
+        unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into insert.
6225 7090
 
6226
-				$InfoFieldList = explode(":", $param_list[0]);
6227
-				$classname=$InfoFieldList[0];
6228
-				$classpath=$InfoFieldList[1];
6229
-				$getnomurlparam=(empty($InfoFieldList[2]) ? 3 : $InfoFieldList[2]);
6230
-				if (! empty($classpath))
6231
-				{
6232
-					dol_include_once($InfoFieldList[1]);
6233
-					if ($classname && class_exists($classname))
6234
-					{
6235
-						$object = new $classname($this->db);
6236
-						$object->fetch($value);
6237
-						$value=$object->getNomUrl($getnomurlparam);
6238
-					}
6239
-				}
6240
-				else
6241
-				{
6242
-					dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6243
-					return 'Error bad setup of extrafield';
6244
-				}
6245
-			}
6246
-			else $value='';
6247
-		}
6248
-		elseif ($type == 'text' || $type == 'html')
6249
-		{
6250
-			$value=dol_htmlentitiesbr($value);
6251
-		}
6252
-		elseif ($type == 'password')
6253
-		{
6254
-			$value=preg_replace('/./i','*',$value);
6255
-		}
6256
-		elseif ($type == 'array')
6257
-		{
6258
-			$value = implode('<br>', $value);
6259
-		}
6260
-
6261
-		//print $type.'-'.$size;
6262
-		$out=$value;
6263
-
6264
-		return $out;
6265
-	}
6266
-
6267
-
6268
-	/**
6269
-	 * Function to show lines of extrafields with output datas
6270
-	 *
6271
-	 * @param 	Extrafields $extrafields    Extrafield Object
6272
-	 * @param 	string      $mode           Show output (view) or input (edit) for extrafield
6273
-	 * @param 	array       $params         Optional parameters. Example: array('style'=>'class="oddeven"', 'colspan'=>$colspan)
6274
-	 * @param 	string      $keysuffix      Suffix string to add after name and id of field (can be used to avoid duplicate names)
6275
-	 * @param 	string      $keyprefix      Prefix string to add before name and id of field (can be used to avoid duplicate names)
6276
-	 * @param	string		$onetrtd		All fields in same tr td
6277
-	 * @return 	string
6278
-	 */
6279
-	function showOptionals($extrafields, $mode='view', $params=null, $keysuffix='', $keyprefix='', $onetrtd=0)
6280
-	{
6281
-		global $db, $conf, $langs, $action, $form;
6282
-
6283
-		if (! is_object($form)) $form=new Form($db);
6284
-
6285
-		$out = '';
6286
-
6287
-		if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label']) > 0)
6288
-		{
6289
-			$out .= "\n";
6290
-			$out .= '<!-- showOptionalsInput --> ';
6291
-			$out .= "\n";
6292
-
6293
-			$e = 0;
6294
-			foreach($extrafields->attributes[$this->table_element]['label'] as $key=>$label)
6295
-			{
6296
-				// Show only the key field in params
6297
-				if (is_array($params) && array_key_exists('onlykey',$params) && $key != $params['onlykey']) continue;
7091
+        $keys=array();
7092
+        $values = array();
7093
+        foreach ($fieldvalues as $k => $v) {
7094
+            $keys[$k] = $k;
7095
+            $value = $this->fields[$k];
7096
+            $values[$k] = $this->quote($v, $value);
7097
+        }
6298 7098
 
6299
-				$enabled = 1;
6300
-				if ($enabled && isset($extrafields->attributes[$this->table_element]['list'][$key]))
6301
-				{
6302
-					$enabled = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1);
6303
-				}
7099
+        // Clean and check mandatory
7100
+        foreach($keys as $key)
7101
+        {
7102
+            // If field is an implicit foreign key field
7103
+            if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';
7104
+            if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';
6304 7105
 
6305
-				$perms = 1;
6306
-				if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key]))
6307
-				{
6308
-					$perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1);
6309
-				}
7106
+            //var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7107
+            if (isset($this->fields[$key]['notnull']) && $this->fields[$key]['notnull'] == 1 && ! isset($values[$key]) && is_null($val['default']))
7108
+            {
7109
+                $error++;
7110
+                $this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7111
+            }
6310 7112
 
6311
-				if (($mode == 'create' || $mode == 'edit') && abs($enabled) != 1 && abs($enabled) != 3) continue;	// <> -1 and <> 1 and <> 3 = not visible on forms, only on list
6312
-				if (empty($perms)) continue;
7113
+            // If field is an implicit foreign key field
7114
+            if (preg_match('/^integer:/i', $this->fields[$key]['type']) && empty($values[$key])) $values[$key]='null';
7115
+            if (! empty($this->fields[$key]['foreignkey']) && empty($values[$key])) $values[$key]='null';
7116
+        }
6313 7117
 
6314
-				// Load language if required
6315
-				if (! empty($extrafields->attributes[$this->table_element]['langfile'][$key])) $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
7118
+        if ($error) return -1;
6316 7119
 
6317
-				$colspan='3';
6318
-				if (is_array($params) && count($params)>0) {
6319
-					if (array_key_exists('colspan',$params)) {
6320
-						$colspan=$params['colspan'];
6321
-					}
6322
-				}
7120
+        $this->db->begin();
6323 7121
 
6324
-				switch($mode) {
6325
-					case "view":
6326
-						$value=$this->array_options["options_".$key.$keysuffix];
6327
-						break;
6328
-					case "edit":
6329
-						$getposttemp = GETPOST($keyprefix.'options_'.$key.$keysuffix, 'none');				// GETPOST can get value from GET, POST or setup of default values.
6330
-						// GETPOST("options_" . $key) can be 'abc' or array(0=>'abc')
6331
-						if (is_array($getposttemp) || $getposttemp != '' || GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix))
6332
-						{
6333
-							if (is_array($getposttemp)) {
6334
-								// $getposttemp is an array but following code expects a comma separated string
6335
-								$value = implode(",", $getposttemp);
6336
-							} else {
6337
-								$value = $getposttemp;
6338
-							}
6339
-						} else {
6340
-							$value = $this->array_options["options_" . $key];			// No GET, no POST, no default value, so we take value of object.
6341
-						}
6342
-						//var_dump($keyprefix.' - '.$key.' - '.$keysuffix.' - '.$keyprefix.'options_'.$key.$keysuffix.' - '.$this->array_options["options_".$key.$keysuffix].' - '.$getposttemp.' - '.$value);
6343
-						break;
6344
-				}
7122
+        if (! $error)
7123
+        {
7124
+            $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
7125
+            $sql.= ' ('.implode( ", ", $keys ).')';
7126
+            $sql.= ' VALUES ('.implode( ", ", $values ).')';
7127
+
7128
+            $res = $this->db->query($sql);
7129
+            if ($res===false) {
7130
+                $error++;
7131
+                $this->errors[] = $this->db->lasterror();
7132
+            }
7133
+        }
6345 7134
 
6346
-				if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate')
6347
-				{
6348
-					$out .= $extrafields->showSeparator($key, $this);
6349
-				}
6350
-				else
6351
-				{
6352
-					$csstyle='';
6353
-					$class=(!empty($extrafields->attributes[$this->table_element]['hidden'][$key]) ? 'hideobject ' : '');
6354
-					if (is_array($params) && count($params)>0) {
6355
-						if (array_key_exists('style',$params)) {
6356
-							$csstyle=$params['style'];
6357
-						}
6358
-					}
7135
+        if (! $error)
7136
+        {
7137
+            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
7138
+        }
6359 7139
 
6360
-					// add html5 elements
6361
-					$domData  = ' data-element="extrafield"';
6362
-					$domData .= ' data-targetelement="'.$this->element.'"';
6363
-					$domData .= ' data-targetid="'.$this->id.'"';
7140
+        // Create extrafields
7141
+        if (! $error)
7142
+        {
7143
+            $result=$this->insertExtraFields();
7144
+            if ($result < 0) $error++;
7145
+        }
6364 7146
 
6365
-					$html_id = !empty($this->id) ? 'extrarow-'.$this->element.'_'.$key.'_'.$this->id : '';
7147
+        // Triggers
7148
+        if (! $error && ! $notrigger)
7149
+        {
7150
+            // Call triggers
7151
+            $result=$this->call_trigger(strtoupper(get_class($this)).'_CREATE',$user);
7152
+            if ($result < 0) { $error++; }
7153
+            // End call triggers
7154
+        }
6366 7155
 
6367
-					$out .= '<tr id="'.$html_id.'" '.$csstyle.' class="'.$class.$this->element.'_extras_'.$key.'" '.$domData.' >';
7156
+        // Commit or rollback
7157
+        if ($error) {
7158
+            $this->db->rollback();
7159
+            return -1;
7160
+        } else {
7161
+            $this->db->commit();
7162
+            return $this->id;
7163
+        }
7164
+    }
6368 7165
 
6369
-					if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0)
6370
-					{
6371
-						if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) { $colspan='0'; }
6372
-					}
6373 7166
 
6374
-					if ($action == 'selectlines') { $colspan++; }
7167
+    /**
7168
+     * Load object in memory from the database
7169
+     *
7170
+     * @param	int    $id				Id object
7171
+     * @param	string $ref				Ref
7172
+     * @param	string	$morewhere		More SQL filters (' AND ...')
7173
+     * @return 	int         			<0 if KO, 0 if not found, >0 if OK
7174
+     */
7175
+    public function fetchCommon($id, $ref = null, $morewhere = '')
7176
+    {
7177
+        if (empty($id) && empty($ref) && empty($morewhere)) return -1;
6375 7178
 
6376
-					// Convert date into timestamp format (value in memory must be a timestamp)
6377
-					if (in_array($extrafields->attributes[$this->table_element]['type'][$key],array('date','datetime')))
6378
-					{
6379
-						$datenotinstring = $this->array_options['options_' . $key];
6380
-						if (! is_numeric($this->array_options['options_' . $key]))	// For backward compatibility
6381
-						{
6382
-							$datenotinstring = $this->db->jdate($datenotinstring);
6383
-						}
6384
-						$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;
6385
-					}
6386
-					// Convert float submited string into real php numeric (value in memory must be a php numeric)
6387
-					if (in_array($extrafields->attributes[$this->table_element]['type'][$key],array('price','double')))
6388
-					{
6389
-						$value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?price2num(GETPOST($keyprefix.'options_'.$key.$keysuffix, 'alpha', 3)):$this->array_options['options_'.$key];
6390
-					}
6391
-
6392
-					$labeltoshow = $langs->trans($label);
6393
-
6394
-					$out .= '<td class="titlefield';
6395
-					if (GETPOST('action','none') == 'create') $out.='create';
6396
-					if ($mode != 'view' && ! empty($extrafields->attributes[$this->table_element]['required'][$key])) $out .= ' fieldrequired';
6397
-					$out .= '">';
6398
-					if (! empty($extrafields->attributes[$object->table_element]['help'][$key])) $out .= $form->textwithpicto($labeltoshow, $extrafields->attributes[$object->table_element]['help'][$key]);
6399
-					else $out .= $labeltoshow;
6400
-					$out .= '</td>';
6401
-
6402
-					$html_id = !empty($this->id) ? $this->element.'_extras_'.$key.'_'.$this->id : '';
6403
-					$out .='<td id="'.$html_id.'" class="'.$this->element.'_extras_'.$key.'" '.($colspan?' colspan="'.$colspan.'"':'').'>';
6404
-
6405
-					switch($mode) {
6406
-						case "view":
6407
-							$out .= $extrafields->showOutputField($key, $value);
6408
-							break;
6409
-						case "edit":
6410
-							$out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id);
6411
-							break;
6412
-					}
6413
-
6414
-					$out .= '</td>';
6415
-
6416
-					if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && (($e % 2) == 1)) $out .= '</tr>';
6417
-					else $out .= '</tr>';
6418
-					$e++;
6419
-				}
6420
-			}
6421
-			$out .= "\n";
6422
-			// Add code to manage list depending on others
6423
-			if (! empty($conf->use_javascript_ajax)) {
6424
-				$out .= '
6425
-				<script type="text/javascript">
6426
-				    jQuery(document).ready(function() {
6427
-				    	function showOptions(child_list, parent_list)
6428
-				    	{
6429
-				    		var val = $("select[name=\"options_"+parent_list+"\"]").val();
6430
-				    		var parentVal = parent_list + ":" + val;
6431
-							if(val > 0) {
6432
-					    		$("select[name=\""+child_list+"\"] option[parent]").hide();
6433
-					    		$("select[name=\""+child_list+"\"] option[parent=\""+parentVal+"\"]").show();
6434
-							} else {
6435
-								$("select[name=\""+child_list+"\"] option").show();
6436
-							}
6437
-				    	}
6438
-						function setListDependencies() {
6439
-					    	jQuery("select option[parent]").parent().each(function() {
6440
-					    		var child_list = $(this).attr("name");
6441
-								var parent = $(this).find("option[parent]:first").attr("parent");
6442
-								var infos = parent.split(":");
6443
-								var parent_list = infos[0];
6444
-								$("select[name=\""+parent_list+"\"]").change(function() {
6445
-									showOptions(child_list, parent_list);
6446
-								});
6447
-					    	});
6448
-						}
7179
+        $sql = 'SELECT '.$this->getFieldList();
7180
+        $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
6449 7181
 
6450
-						setListDependencies();
6451
-				    });
6452
-				</script>'."\n";
6453
-				$out .= '<!-- /showOptionalsInput --> '."\n";
6454
-			}
6455
-		}
6456
-		return $out;
6457
-	}
6458
-
6459
-
6460
-	/**
6461
-	 * Returns the rights used for this class
6462
-	 * @return stdClass
6463
-	 */
6464
-	public function getRights()
6465
-	{
6466
-		global $user;
6467
-
6468
-		$element = $this->element;
6469
-		if ($element == 'facturerec') $element='facture';
6470
-
6471
-		return $user->rights->{$element};
6472
-	}
6473
-
6474
-	/**
6475
-	 * Function used to replace a thirdparty id with another one.
6476
-	 * This function is meant to be called from replaceThirdparty with the appropiate tables
6477
-	 * Column name fk_soc MUST be used to identify thirdparties
6478
-	 *
6479
-	 * @param  DoliDB 	   $db 			  Database handler
6480
-	 * @param  int 		   $origin_id     Old thirdparty id (the thirdparty to delete)
6481
-	 * @param  int 		   $dest_id       New thirdparty id (the thirdparty that will received element of the other)
6482
-	 * @param  string[]    $tables        Tables that need to be changed
6483
-	 * @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)
6484
-	 * @return bool						  True if success, False if error
6485
-	 */
6486
-	public static function commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
6487
-	{
6488
-		foreach ($tables as $table)
6489
-		{
6490
-			$sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_soc = '.$dest_id.' WHERE fk_soc = '.$origin_id;
6491
-
6492
-			if (! $db->query($sql))
6493
-			{
6494
-				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.
6495
-				//$this->errors = $db->lasterror();
6496
-				return false;
6497
-			}
6498
-		}
6499
-
6500
-		return true;
6501
-	}
6502
-
6503
-	/**
6504
-	 * Get buy price to use for margin calculation. This function is called when buy price is unknown.
6505
-	 *	 Set buy price = sell price if ForceBuyingPriceIfNull configured,
6506
-	 *   else if calculation MARGIN_TYPE = 'costprice' and costprice is defined, use costprice as buyprice
6507
-	 *	 else if calculation MARGIN_TYPE = 'pmp' and pmp is calculated, use pmp as buyprice
6508
-	 *	 else set min buy price as buy price
6509
-	 *
6510
-	 * @param float		$unitPrice		 Product unit price
6511
-	 * @param float		$discountPercent Line discount percent
6512
-	 * @param int		$fk_product		 Product id
6513
-	 * @return	float                    <0 if KO, buyprice if OK
6514
-	 */
6515
-	public function defineBuyPrice($unitPrice = 0.0, $discountPercent = 0.0, $fk_product = 0)
6516
-	{
6517
-		global $conf;
6518
-
6519
-		$buyPrice = 0;
6520
-
6521
-		if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) // In most cases, test here is false
6522
-		{
6523
-			$buyPrice = $unitPrice * (1 - $discountPercent / 100);
6524
-		}
6525
-		else
6526
-		{
6527
-			// Get cost price for margin calculation
6528
-			if (! empty($fk_product))
6529
-			{
6530
-				if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'costprice')
6531
-				{
6532
-					require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6533
-					$product = new Product($this->db);
6534
-					$result = $product->fetch($fk_product);
6535
-					if ($result <= 0)
6536
-					{
6537
-						$this->errors[] = 'ErrorProductIdDoesNotExists';
6538
-						return -1;
6539
-					}
6540
-					if ($product->cost_price > 0)
6541
-					{
6542
-						$buyPrice = $product->cost_price;
6543
-					}
6544
-					else if ($product->pmp > 0)
6545
-					{
6546
-						$buyPrice = $product->pmp;
6547
-					}
6548
-				}
6549
-				else if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'pmp')
6550
-				{
6551
-					require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6552
-					$product = new Product($this->db);
6553
-					$result = $product->fetch($fk_product);
6554
-					if ($result <= 0)
6555
-					{
6556
-						$this->errors[] = 'ErrorProductIdDoesNotExists';
6557
-						return -1;
6558
-					}
6559
-					if ($product->pmp > 0)
6560
-					{
6561
-						$buyPrice = $product->pmp;
6562
-					}
6563
-				}
7182
+        if (!empty($id))  $sql.= ' WHERE rowid = '.$id;
7183
+        elseif (!empty($ref)) $sql.= " WHERE ref = ".$this->quote($ref, $this->fields['ref']);
7184
+        else $sql.=' WHERE 1 = 1';	// usage with empty id and empty ref is very rare
7185
+        if ($morewhere)   $sql.= $morewhere;
7186
+        $sql.=' LIMIT 1';	// This is a fetch, to be sure to get only one record
6564 7187
 
6565
-				if (empty($buyPrice) && isset($conf->global->MARGIN_TYPE) && in_array($conf->global->MARGIN_TYPE, array('1','pmp','costprice')))
6566
-				{
6567
-					require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
6568
-					$productFournisseur = new ProductFournisseur($this->db);
6569
-					if (($result = $productFournisseur->find_min_price_product_fournisseur($fk_product)) > 0)
6570
-					{
6571
-						$buyPrice = $productFournisseur->fourn_unitprice;
6572
-					}
6573
-					else if ($result < 0)
6574
-					{
6575
-						$this->errors[] = $productFournisseur->error;
6576
-						return -2;
6577
-					}
6578
-				}
6579
-			}
6580
-		}
6581
-		return $buyPrice;
6582
-	}
7188
+        $res = $this->db->query($sql);
7189
+        if ($res)
7190
+        {
7191
+            $obj = $this->db->fetch_object($res);
7192
+            if ($obj)
7193
+            {
7194
+                $this->setVarsFromFetchObj($obj);
7195
+                return $this->id;
7196
+            }
7197
+            else
7198
+            {
7199
+                return 0;
7200
+            }
7201
+        }
7202
+        else
7203
+        {
7204
+            $this->error = $this->db->lasterror();
7205
+            $this->errors[] = $this->error;
7206
+            return -1;
7207
+        }
7208
+    }
6583 7209
 
6584
-    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
6585
-	/**
6586
-	 *  Show photos of an object (nbmax maximum), into several columns
6587
-	 *
6588
-	 *  @param		string	$modulepart		'product', 'ticket', ...
6589
-	 *  @param      string	$sdir        	Directory to scan (full absolute path)
6590
-	 *  @param      int		$size        	0=original size, 1='small' use thumbnail if possible
6591
-	 *  @param      int		$nbmax       	Nombre maximum de photos (0=pas de max)
6592
-	 *  @param      int		$nbbyrow     	Number of image per line or -1 to use div. Used only if size=1.
6593
-	 * 	@param		int		$showfilename	1=Show filename
6594
-	 * 	@param		int		$showaction		1=Show icon with action links (resize, delete)
6595
-	 * 	@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.
6596
-	 * 	@param		int		$maxWidth		Max width of original image when size='small'
6597
-	 *  @param      int     $nolink         Do not add a href link to view enlarged imaged into a new tab
6598
-	 *  @param      int     $notitle        Do not add title tag on image
6599
-	 *  @param		int		$usesharelink	Use the public shared link of image (if not available, the 'nophoto' image will be shown instead)
6600
-	 *  @return     string					Html code to show photo. Number of photos shown is saved in this->nbphoto
6601
-	 */
6602
-	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)
6603
-	{
6604
-        // phpcs:enable
6605
-		global $conf,$user,$langs;
6606
-
6607
-		include_once DOL_DOCUMENT_ROOT .'/core/lib/files.lib.php';
6608
-		include_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';
6609
-
6610
-		$sortfield='position_name';
6611
-		$sortorder='asc';
6612
-
6613
-		$dir = $sdir . '/';
6614
-		$pdir = '/';
6615
-		if ($modulepart == 'ticket')
6616
-		{
6617
-			$dir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->track_id.'/';
6618
-			$pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->track_id.'/';
6619
-		}
6620
-		else
6621
-		{
6622
-			$dir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->ref.'/';
6623
-			$pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->ref.'/';
6624
-		}
6625
-
6626
-		// For backward compatibility
6627
-		if ($modulepart == 'product' && ! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))
6628
-		{
6629
-			$dir = $sdir . '/'. get_exdir($this->id,2,0,0,$this,$modulepart) . $this->id ."/photos/";
6630
-			$pdir = '/' . get_exdir($this->id,2,0,0,$this,$modulepart) . $this->id ."/photos/";
6631
-		}
6632
-
6633
-		// Defined relative dir to DOL_DATA_ROOT
6634
-		$relativedir = '';
6635
-		if ($dir)
6636
-		{
6637
-			$relativedir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $dir);
6638
-			$relativedir = preg_replace('/^[\\/]/','',$relativedir);
6639
-			$relativedir = preg_replace('/[\\/]$/','',$relativedir);
6640
-		}
6641
-
6642
-		$dirthumb = $dir.'thumbs/';
6643
-		$pdirthumb = $pdir.'thumbs/';
6644
-
6645
-		$return ='<!-- Photo -->'."\n";
6646
-		$nbphoto=0;
6647
-
6648
-		$filearray=dol_dir_list($dir,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
6649
-
6650
-		/*if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))    // For backward compatiblity, we scan also old dirs
6651
-		 {
6652
-		 $filearrayold=dol_dir_list($dirold,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
6653
-		 $filearray=array_merge($filearray, $filearrayold);
6654
-		 }*/
7210
+    /**
7211
+     * Update object into database
7212
+     *
7213
+     * @param  User $user      	User that modifies
7214
+     * @param  bool $notrigger 	false=launch triggers after, true=disable triggers
7215
+     * @return int             	<0 if KO, >0 if OK
7216
+     */
7217
+    public function updateCommon(User $user, $notrigger = false)
7218
+    {
7219
+        global $conf, $langs;
6655 7220
 
6656
-		completeFileArrayWithDatabaseInfo($filearray, $relativedir);
7221
+        $error = 0;
6657 7222
 
6658
-		if (count($filearray))
6659
-		{
6660
-			if ($sortfield && $sortorder)
6661
-			{
6662
-				$filearray=dol_sort_array($filearray, $sortfield, $sortorder);
6663
-			}
7223
+        $now=dol_now();
6664 7224
 
6665
-			foreach($filearray as $key => $val)
6666
-			{
6667
-				$photo='';
6668
-				$file = $val['name'];
7225
+        $fieldvalues = $this->setSaveQuery();
7226
+        if (array_key_exists('date_modification', $fieldvalues) && empty($fieldvalues['date_modification'])) $fieldvalues['date_modification']=$this->db->idate($now);
7227
+        if (array_key_exists('fk_user_modif', $fieldvalues) && ! ($fieldvalues['fk_user_modif'] > 0)) $fieldvalues['fk_user_modif']=$user->id;
7228
+        unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into update.
6669 7229
 
6670
-				//if (! utf8_check($file)) $file=utf8_encode($file);	// To be sure file is stored in UTF8 in memory
7230
+        $keys=array();
7231
+        $values = array();
7232
+        foreach ($fieldvalues as $k => $v) {
7233
+            $keys[$k] = $k;
7234
+            $value = $this->fields[$k];
7235
+            $values[$k] = $this->quote($v, $value);
7236
+            $tmp[] = $k.'='.$this->quote($v, $this->fields[$k]);
7237
+        }
6671 7238
 
6672
-				//if (dol_is_file($dir.$file) && image_format_supported($file) >= 0)
6673
-				if (image_format_supported($file) >= 0)
6674
-				{
6675
-					$nbphoto++;
6676
-					$photo = $file;
6677
-					$viewfilename = $file;
7239
+        // Clean and check mandatory
7240
+        foreach($keys as $key)
7241
+        {
7242
+            if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';		// This is an implicit foreign key field
7243
+            if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';					// This is an explicit foreign key field
7244
+
7245
+            //var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7246
+            /*
7247
+			if ($this->fields[$key]['notnull'] == 1 && empty($values[$key]))
7248
+			{
7249
+				$error++;
7250
+				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7251
+			}*/
7252
+        }
6678 7253
 
6679
-					if ($size == 1 || $size == 'small') {   // Format vignette
7254
+        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET '.implode( ',', $tmp ).' WHERE rowid='.$this->id ;
6680 7255
 
6681
-						// Find name of thumb file
6682
-						$photo_vignette=basename(getImageFileNameForSize($dir.$file, '_small'));
6683
-						if (! dol_is_file($dirthumb.$photo_vignette)) $photo_vignette='';
7256
+        $this->db->begin();
7257
+        if (! $error)
7258
+        {
7259
+            $res = $this->db->query($sql);
7260
+            if ($res===false)
7261
+            {
7262
+                $error++;
7263
+                $this->errors[] = $this->db->lasterror();
7264
+            }
7265
+        }
6684 7266
 
6685
-						// Get filesize of original file
6686
-						$imgarray=dol_getImageSize($dir.$photo);
7267
+        // Update extrafield
7268
+        if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options)>0)
7269
+        {
7270
+            $result=$this->insertExtraFields();
7271
+            if ($result < 0)
7272
+            {
7273
+                $error++;
7274
+            }
7275
+        }
6687 7276
 
6688
-						if ($nbbyrow > 0)
6689
-						{
6690
-							if ($nbphoto == 1) $return.= '<table width="100%" valign="top" align="center" border="0" cellpadding="2" cellspacing="2">';
7277
+        // Triggers
7278
+        if (! $error && ! $notrigger)
7279
+        {
7280
+            // Call triggers
7281
+            $result=$this->call_trigger(strtoupper(get_class($this)).'_MODIFY',$user);
7282
+            if ($result < 0) { $error++; } //Do also here what you must do to rollback action if trigger fail
7283
+            // End call triggers
7284
+        }
6691 7285
 
6692
-							if ($nbphoto % $nbbyrow == 1) $return.= '<tr align=center valign=middle border=1>';
6693
-							$return.= '<td width="'.ceil(100/$nbbyrow).'%" class="photo">';
6694
-						}
6695
-						else if ($nbbyrow < 0) $return .= '<div class="inline-block">';
7286
+        // Commit or rollback
7287
+        if ($error) {
7288
+            $this->db->rollback();
7289
+            return -1;
7290
+        } else {
7291
+            $this->db->commit();
7292
+            return $this->id;
7293
+        }
7294
+    }
6696 7295
 
6697
-						$return.= "\n";
7296
+    /**
7297
+     * Delete object in database
7298
+     *
7299
+     * @param 	User 	$user       			User that deletes
7300
+     * @param 	bool 	$notrigger  			false=launch triggers after, true=disable triggers
7301
+     * @param	int		$forcechilddeletion		0=no, 1=Force deletion of children
7302
+     * @return 	int             				<=0 if KO, >0 if OK
7303
+     */
7304
+    public function deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
7305
+    {
7306
+        $error=0;
6698 7307
 
6699
-						$relativefile=preg_replace('/^\//', '', $pdir.$photo);
6700
-						if (empty($nolink))
6701
-						{
6702
-							$urladvanced=getAdvancedPreviewUrl($modulepart, $relativefile, 0, 'entity='.$this->entity);
6703
-							if ($urladvanced) $return.='<a href="'.$urladvanced.'">';
6704
-							else $return.= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'" class="aphoto" target="_blank">';
6705
-						}
7308
+        $this->db->begin();
6706 7309
 
6707
-						// Show image (width height=$maxHeight)
6708
-						// Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine
6709
-						$alt=$langs->transnoentitiesnoconv('File').': '.$relativefile;
6710
-						$alt.=' - '.$langs->transnoentitiesnoconv('Size').': '.$imgarray['width'].'x'.$imgarray['height'];
6711
-						if ($notitle) $alt='';
6712
-
6713
-						if ($usesharelink)
6714
-						{
6715
-							if ($val['share'])
6716
-							{
6717
-								if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight)
6718
-								{
6719
-									$return.= '<!-- Show original file (thumb not yet available with shared links) -->';
6720
-									$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).'" title="'.dol_escape_htmltag($alt).'">';
6721
-								}
6722
-								else {
6723
-									$return.= '<!-- Show original file -->';
6724
-									$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).'" title="'.dol_escape_htmltag($alt).'">';
6725
-								}
6726
-							}
6727
-							else
6728
-							{
6729
-								$return.= '<!-- Show nophoto file (because file is not shared) -->';
6730
-								$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/public/theme/common/nophoto.png" title="'.dol_escape_htmltag($alt).'">';
6731
-							}
6732
-						}
6733
-						else
6734
-						{
6735
-							if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight)
6736
-							{
6737
-								$return.= '<!-- Show thumb -->';
6738
-								$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).'">';
6739
-							}
6740
-							else {
6741
-								$return.= '<!-- Show original file -->';
6742
-								$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).'">';
6743
-							}
6744
-						}
7310
+        if ($forcechilddeletion)
7311
+        {
7312
+            foreach($this->childtables as $table)
7313
+            {
7314
+                $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$table.' WHERE '.$this->fk_element.' = '.$this->id;
7315
+                $resql = $this->db->query($sql);
7316
+                if (! $resql)
7317
+                {
7318
+                    $this->error=$this->db->lasterror();
7319
+                    $this->errors[]=$this->error;
7320
+                    $this->db->rollback();
7321
+                    return -1;
7322
+                }
7323
+            }
7324
+        }
7325
+        elseif (! empty($this->fk_element) && ! empty($this->childtables))	// If object has childs linked with a foreign key field, we check all child tables.
7326
+        {
7327
+            $objectisused = $this->isObjectUsed($this->id);
7328
+            if (! empty($objectisused))
7329
+            {
7330
+                dol_syslog(get_class($this)."::deleteCommon Can't delete record as it has some child", LOG_WARNING);
7331
+                $this->error='ErrorRecordHasChildren';
7332
+                $this->errors[]=$this->error;
7333
+                $this->db->rollback();
7334
+                return 0;
7335
+            }
7336
+        }
6745 7337
 
6746
-						if (empty($nolink)) $return.= '</a>';
6747
-						$return.="\n";
6748
-
6749
-						if ($showfilename) $return.= '<br>'.$viewfilename;
6750
-						if ($showaction)
6751
-						{
6752
-							$return.= '<br>';
6753
-							// On propose la generation de la vignette si elle n'existe pas et si la taille est superieure aux limites
6754
-							if ($photo_vignette && (image_format_supported($photo) > 0) && ($this->imgWidth > $maxWidth || $this->imgHeight > $maxHeight))
6755
-							{
6756
-								$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>';
6757
-							}
6758
-							// Special cas for product
6759
-							if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer))
6760
-							{
6761
-								// Link to resize
6762
-								$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; ';
6763
-
6764
-								// Link to delete
6765
-								$return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=delete&amp;file='.urlencode($pdir.$viewfilename).'">';
6766
-								$return.= img_delete().'</a>';
6767
-							}
6768
-						}
6769
-						$return.= "\n";
7338
+        if (! $error) {
7339
+            if (! $notrigger) {
7340
+                // Call triggers
7341
+                $result=$this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user);
7342
+                if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
7343
+                // End call triggers
7344
+            }
7345
+        }
6770 7346
 
6771
-						if ($nbbyrow > 0)
6772
-						{
6773
-							$return.= '</td>';
6774
-							if (($nbphoto % $nbbyrow) == 0) $return.= '</tr>';
6775
-						}
6776
-						else if ($nbbyrow < 0) $return.='</div>';
6777
-					}
6778
-
6779
-					if (empty($size)) {     // Format origine
6780
-						$return.= '<img class="photo photowithmargin" border="0" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'">';
6781
-
6782
-						if ($showfilename) $return.= '<br>'.$viewfilename;
6783
-						if ($showaction)
6784
-						{
6785
-							// Special case for product
6786
-							if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer))
6787
-							{
6788
-								// Link to resize
6789
-								$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; ';
6790
-
6791
-								// Link to delete
6792
-								$return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=delete&amp;file='.urlencode($pdir.$viewfilename).'">';
6793
-								$return.= img_delete().'</a>';
6794
-							}
6795
-						}
6796
-					}
7347
+        if (! $error && ! empty($this->isextrafieldmanaged))
7348
+        {
7349
+            $sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element."_extrafields";
7350
+            $sql.= " WHERE fk_object=" . $this->id;
6797 7351
 
6798
-					// On continue ou on arrete de boucler ?
6799
-					if ($nbmax && $nbphoto >= $nbmax) break;
6800
-				}
6801
-			}
7352
+            $resql = $this->db->query($sql);
7353
+            if (! $resql)
7354
+            {
7355
+                $this->errors[] = $this->db->lasterror();
7356
+                $error++;
7357
+            }
7358
+        }
6802 7359
 
6803
-			if ($size==1 || $size=='small')
6804
-			{
6805
-				if ($nbbyrow > 0)
6806
-				{
6807
-					// Ferme tableau
6808
-					while ($nbphoto % $nbbyrow)
6809
-					{
6810
-						$return.= '<td width="'.ceil(100/$nbbyrow).'%">&nbsp;</td>';
6811
-						$nbphoto++;
6812
-					}
6813
-
6814
-					if ($nbphoto) $return.= '</table>';
6815
-				}
6816
-			}
6817
-		}
6818
-
6819
-		$this->nbphoto = $nbphoto;
6820
-
6821
-		return $return;
6822
-	}
6823
-
6824
-
6825
-	/**
6826
-	 * Function test if type is array
6827
-	 *
6828
-	 * @param   array   $info   content informations of field
6829
-	 * @return                  bool
6830
-	 */
6831
-	protected function isArray($info)
6832
-	{
6833
-		if(is_array($info))
6834
-		{
6835
-			if(isset($info['type']) && $info['type']=='array') return true;
6836
-			else return false;
6837
-		}
6838
-		else return false;
6839
-	}
6840
-
6841
-	/**
6842
-	 * Function test if type is null
6843
-	 *
6844
-	 * @param   array   $info   content informations of field
6845
-	 * @return                  bool
6846
-	 */
6847
-	protected function isNull($info)
6848
-	{
6849
-		if(is_array($info))
6850
-		{
6851
-			if(isset($info['type']) && $info['type']=='null') return true;
6852
-			else return false;
6853
-		}
6854
-		else return false;
6855
-	}
6856
-
6857
-	/**
6858
-	 * Function test if type is date
6859
-	 *
6860
-	 * @param   array   $info   content informations of field
6861
-	 * @return                  bool
6862
-	 */
6863
-	public function isDate($info)
6864
-	{
6865
-		if(isset($info['type']) && ($info['type']=='date' || $info['type']=='datetime' || $info['type']=='timestamp')) return true;
6866
-		else return false;
6867
-	}
6868
-
6869
-	/**
6870
-	 * Function test if type is integer
6871
-	 *
6872
-	 * @param   array   $info   content informations of field
6873
-	 * @return                  bool
6874
-	 */
6875
-	public function isInt($info)
6876
-	{
6877
-		if(is_array($info))
6878
-		{
6879
-			if(isset($info['type']) && ($info['type']=='int' || preg_match('/^integer/i',$info['type']) ) ) return true;
6880
-			else return false;
6881
-		}
6882
-		else return false;
6883
-	}
6884
-
6885
-	/**
6886
-	 * Function test if type is float
6887
-	 *
6888
-	 * @param   array   $info   content informations of field
6889
-	 * @return                  bool
6890
-	 */
6891
-	public function isFloat($info)
6892
-	{
6893
-		if(is_array($info))
6894
-		{
6895
-			if (isset($info['type']) && (preg_match('/^(double|real)/i', $info['type']))) return true;
6896
-			else return false;
6897
-		}
6898
-		else return false;
6899
-	}
6900
-
6901
-	/**
6902
-	 * Function test if type is text
6903
-	 *
6904
-	 * @param   array   $info   content informations of field
6905
-	 * @return                  bool
6906
-	 */
6907
-	public function isText($info)
6908
-	{
6909
-		if(is_array($info))
6910
-		{
6911
-			if(isset($info['type']) && $info['type']=='text') return true;
6912
-			else return false;
6913
-		}
6914
-		else return false;
6915
-	}
6916
-
6917
-	/**
6918
-	 * Function test if is indexed
6919
-	 *
6920
-	 * @param   array   $info   content informations of field
6921
-	 * @return                  bool
6922
-	 */
6923
-	protected function isIndex($info)
6924
-	{
6925
-		if(is_array($info))
6926
-		{
6927
-			if(isset($info['index']) && $info['index']==true) return true;
6928
-			else return false;
6929
-		}
6930
-		else return false;
6931
-	}
6932
-
6933
-	/**
6934
-	 * Function to prepare the values to insert.
6935
-	 * Note $this->${field} are set by the page that make the createCommon or the updateCommon.
6936
-	 *
6937
-	 * @return array
6938
-	 */
6939
-	protected function setSaveQuery()
6940
-	{
6941
-		global $conf;
6942
-
6943
-		$queryarray=array();
6944
-		foreach ($this->fields as $field=>$info)	// Loop on definition of fields
6945
-		{
6946
-			// Depending on field type ('datetime', ...)
6947
-			if($this->isDate($info))
6948
-			{
6949
-				if(empty($this->{$field}))
6950
-				{
6951
-					$queryarray[$field] = null;
6952
-				}
6953
-				else
6954
-				{
6955
-					$queryarray[$field] = $this->db->idate($this->{$field});
6956
-				}
6957
-			}
6958
-			else if($this->isArray($info))
6959
-			{
6960
-				if(! empty($this->{$field})) {
6961
-					if(! is_array($this->{$field})) {
6962
-						$this->{$field} = array($this->{$field});
6963
-					}
6964
-					$queryarray[$field] = serialize($this->{$field});
6965
-				} else {
6966
-					$queryarray[$field] = null;
6967
-				}
6968
-			}
6969
-			else if($this->isInt($info))
6970
-			{
6971
-				if ($field == 'entity' && is_null($this->{$field})) $queryarray[$field]=$conf->entity;
6972
-				else
6973
-				{
6974
-					$queryarray[$field] = (int) price2num($this->{$field});
6975
-					if (empty($queryarray[$field])) $queryarray[$field]=0;		// May be reset to null later if property 'notnull' is -1 for this field.
6976
-				}
6977
-			}
6978
-			else if($this->isFloat($info))
6979
-			{
6980
-				$queryarray[$field] = (double) price2num($this->{$field});
6981
-				if (empty($queryarray[$field])) $queryarray[$field]=0;
6982
-			}
6983
-			else
6984
-			{
6985
-				$queryarray[$field] = $this->{$field};
6986
-			}
7360
+        if (! $error)
7361
+        {
7362
+            $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
6987 7363
 
6988
-			if ($info['type'] == 'timestamp' && empty($queryarray[$field])) unset($queryarray[$field]);
6989
-			if (! empty($info['notnull']) && $info['notnull'] == -1 && empty($queryarray[$field])) $queryarray[$field] = null;
6990
-		}
7364
+            $res = $this->db->query($sql);
7365
+            if($res===false) {
7366
+                $error++;
7367
+                $this->errors[] = $this->db->lasterror();
7368
+            }
7369
+        }
6991 7370
 
6992
-		return $queryarray;
6993
-	}
7371
+        // Commit or rollback
7372
+        if ($error) {
7373
+            $this->db->rollback();
7374
+            return -1;
7375
+        } else {
7376
+            $this->db->commit();
7377
+            return 1;
7378
+        }
7379
+    }
6994 7380
 
6995
-	/**
6996
-	 * Function to load data from a SQL pointer into properties of current object $this
6997
-	 *
6998
-	 * @param   stdClass    $obj    Contain data of object from database
7381
+    /**
7382
+     * Initialise object with example values
7383
+     * Id must be 0 if object instance is a specimen
7384
+     *
6999 7385
      * @return void
7000
-	 */
7001
-	protected function setVarsFromFetchObj(&$obj)
7002
-	{
7003
-		foreach ($this->fields as $field => $info)
7004
-		{
7005
-			if($this->isDate($info))
7006
-			{
7007
-				if(empty($obj->{$field}) || $obj->{$field} === '0000-00-00 00:00:00' || $obj->{$field} === '1000-01-01 00:00:00') $this->{$field} = 0;
7008
-				else $this->{$field} = strtotime($obj->{$field});
7009
-			}
7010
-			elseif($this->isArray($info))
7011
-			{
7012
-				if(! empty($obj->{$field})) {
7013
-					$this->{$field} = @unserialize($obj->{$field});
7014
-					// Hack for data not in UTF8
7015
-					if($this->{$field } === false) @unserialize(utf8_decode($obj->{$field}));
7016
-				} else {
7017
-					$this->{$field} = array();
7018
-				}
7019
-			}
7020
-			elseif($this->isInt($info))
7021
-			{
7022
-				if ($field == 'rowid') $this->id = (int) $obj->{$field};
7023
-				else $this->{$field} = (int) $obj->{$field};
7024
-			}
7025
-			elseif($this->isFloat($info))
7026
-			{
7027
-				$this->{$field} = (double) $obj->{$field};
7028
-			}
7029
-			elseif($this->isNull($info))
7030
-			{
7031
-				$val = $obj->{$field};
7032
-				// zero is not null
7033
-				$this->{$field} = (is_null($val) || (empty($val) && $val!==0 && $val!=='0') ? null : $val);
7034
-			}
7035
-			else
7036
-			{
7037
-				$this->{$field} = $obj->{$field};
7038
-			}
7039
-		}
7040
-
7041
-		// If there is no 'ref' field, we force property ->ref to ->id for a better compatibility with common functions.
7042
-		if (! isset($this->fields['ref']) && isset($this->id)) $this->ref = $this->id;
7043
-	}
7044
-
7045
-	/**
7046
-	 * Function to concat keys of fields
7047
-	 *
7048
-	 * @return string
7049
-	 */
7050
-	protected function getFieldList()
7051
-	{
7052
-		$keys = array_keys($this->fields);
7053
-		return implode(',', $keys);
7054
-	}
7055
-
7056
-	/**
7057
-	 * Add quote to field value if necessary
7058
-	 *
7059
-	 * @param 	string|int	$value			Value to protect
7060
-	 * @param	array		$fieldsentry	Properties of field
7061
-	 * @return 	string
7062
-	 */
7063
-    protected function quote($value, $fieldsentry)
7386
+     */
7387
+    public function initAsSpecimenCommon()
7064 7388
     {
7065
-		if (is_null($value)) return 'NULL';
7066
-		else if (preg_match('/^(int|double|real)/i', $fieldsentry['type'])) return $this->db->escape("$value");
7067
-		else return "'".$this->db->escape($value)."'";
7068
-	}
7069
-
7070
-
7071
-	/**
7072
-	 * Create object into database
7073
-	 *
7074
-	 * @param  User $user      User that creates
7075
-	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
7076
-	 * @return int             <0 if KO, Id of created object if OK
7077
-	 */
7078
-	public function createCommon(User $user, $notrigger = false)
7079
-	{
7080
-		global $langs;
7081
-
7082
-		$error = 0;
7083
-
7084
-		$now=dol_now();
7085
-
7086
-		$fieldvalues = $this->setSaveQuery();
7087
-		if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) $fieldvalues['date_creation']=$this->db->idate($now);
7088
-		if (array_key_exists('fk_user_creat', $fieldvalues) && ! ($fieldvalues['fk_user_creat'] > 0)) $fieldvalues['fk_user_creat']=$user->id;
7089
-		unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into insert.
7090
-
7091
-		$keys=array();
7092
-		$values = array();
7093
-		foreach ($fieldvalues as $k => $v) {
7094
-			$keys[$k] = $k;
7095
-			$value = $this->fields[$k];
7096
-			$values[$k] = $this->quote($v, $value);
7097
-		}
7098
-
7099
-		// Clean and check mandatory
7100
-		foreach($keys as $key)
7101
-		{
7102
-			// If field is an implicit foreign key field
7103
-			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';
7104
-			if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';
7105
-
7106
-			//var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7107
-			if (isset($this->fields[$key]['notnull']) && $this->fields[$key]['notnull'] == 1 && ! isset($values[$key]) && is_null($val['default']))
7108
-			{
7109
-				$error++;
7110
-				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7111
-			}
7112
-
7113
-			// If field is an implicit foreign key field
7114
-			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && empty($values[$key])) $values[$key]='null';
7115
-			if (! empty($this->fields[$key]['foreignkey']) && empty($values[$key])) $values[$key]='null';
7116
-		}
7117
-
7118
-		if ($error) return -1;
7119
-
7120
-		$this->db->begin();
7389
+        $this->id = 0;
7121 7390
 
7122
-		if (! $error)
7123
-		{
7124
-			$sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
7125
-			$sql.= ' ('.implode( ", ", $keys ).')';
7126
-			$sql.= ' VALUES ('.implode( ", ", $values ).')';
7391
+        // TODO...
7392
+    }
7127 7393
 
7128
-			$res = $this->db->query($sql);
7129
-			if ($res===false) {
7130
-				$error++;
7131
-				$this->errors[] = $this->db->lasterror();
7132
-			}
7133
-		}
7134
-
7135
-		if (! $error)
7136
-		{
7137
-			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
7138
-		}
7139
-
7140
-		// Create extrafields
7141
-		if (! $error)
7142
-		{
7143
-			$result=$this->insertExtraFields();
7144
-			if ($result < 0) $error++;
7145
-		}
7146
-
7147
-		// Triggers
7148
-		if (! $error && ! $notrigger)
7149
-		{
7150
-			// Call triggers
7151
-			$result=$this->call_trigger(strtoupper(get_class($this)).'_CREATE',$user);
7152
-			if ($result < 0) { $error++; }
7153
-			// End call triggers
7154
-		}
7155
-
7156
-		// Commit or rollback
7157
-		if ($error) {
7158
-			$this->db->rollback();
7159
-			return -1;
7160
-		} else {
7161
-			$this->db->commit();
7162
-			return $this->id;
7163
-		}
7164
-	}
7165
-
7166
-
7167
-	/**
7168
-	 * Load object in memory from the database
7169
-	 *
7170
-	 * @param	int    $id				Id object
7171
-	 * @param	string $ref				Ref
7172
-	 * @param	string	$morewhere		More SQL filters (' AND ...')
7173
-	 * @return 	int         			<0 if KO, 0 if not found, >0 if OK
7174
-	 */
7175
-	public function fetchCommon($id, $ref = null, $morewhere = '')
7176
-	{
7177
-		if (empty($id) && empty($ref) && empty($morewhere)) return -1;
7178
-
7179
-		$sql = 'SELECT '.$this->getFieldList();
7180
-		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
7181
-
7182
-		if (!empty($id))  $sql.= ' WHERE rowid = '.$id;
7183
-		elseif (!empty($ref)) $sql.= " WHERE ref = ".$this->quote($ref, $this->fields['ref']);
7184
-		else $sql.=' WHERE 1 = 1';	// usage with empty id and empty ref is very rare
7185
-		if ($morewhere)   $sql.= $morewhere;
7186
-		$sql.=' LIMIT 1';	// This is a fetch, to be sure to get only one record
7187
-
7188
-		$res = $this->db->query($sql);
7189
-		if ($res)
7190
-		{
7191
-			$obj = $this->db->fetch_object($res);
7192
-			if ($obj)
7193
-			{
7194
-				$this->setVarsFromFetchObj($obj);
7195
-				return $this->id;
7196
-			}
7197
-			else
7198
-			{
7199
-				return 0;
7200
-			}
7201
-		}
7202
-		else
7203
-		{
7204
-			$this->error = $this->db->lasterror();
7205
-			$this->errors[] = $this->error;
7206
-			return -1;
7207
-		}
7208
-	}
7209
-
7210
-	/**
7211
-	 * Update object into database
7212
-	 *
7213
-	 * @param  User $user      	User that modifies
7214
-	 * @param  bool $notrigger 	false=launch triggers after, true=disable triggers
7215
-	 * @return int             	<0 if KO, >0 if OK
7216
-	 */
7217
-	public function updateCommon(User $user, $notrigger = false)
7218
-	{
7219
-		global $conf, $langs;
7220
-
7221
-		$error = 0;
7222
-
7223
-		$now=dol_now();
7224
-
7225
-		$fieldvalues = $this->setSaveQuery();
7226
-		if (array_key_exists('date_modification', $fieldvalues) && empty($fieldvalues['date_modification'])) $fieldvalues['date_modification']=$this->db->idate($now);
7227
-		if (array_key_exists('fk_user_modif', $fieldvalues) && ! ($fieldvalues['fk_user_modif'] > 0)) $fieldvalues['fk_user_modif']=$user->id;
7228
-		unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into update.
7229
-
7230
-		$keys=array();
7231
-		$values = array();
7232
-		foreach ($fieldvalues as $k => $v) {
7233
-			$keys[$k] = $k;
7234
-			$value = $this->fields[$k];
7235
-			$values[$k] = $this->quote($v, $value);
7236
-			$tmp[] = $k.'='.$this->quote($v, $this->fields[$k]);
7237
-		}
7238
-
7239
-		// Clean and check mandatory
7240
-		foreach($keys as $key)
7241
-		{
7242
-			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';		// This is an implicit foreign key field
7243
-			if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';					// This is an explicit foreign key field
7244
-
7245
-			//var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7246
-			/*
7247
-			if ($this->fields[$key]['notnull'] == 1 && empty($values[$key]))
7248
-			{
7249
-				$error++;
7250
-				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7251
-			}*/
7252
-		}
7253 7394
 
7254
-		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET '.implode( ',', $tmp ).' WHERE rowid='.$this->id ;
7395
+    /* Part for comments */
7255 7396
 
7256
-		$this->db->begin();
7257
-		if (! $error)
7258
-		{
7259
-			$res = $this->db->query($sql);
7260
-			if ($res===false)
7261
-			{
7262
-				$error++;
7263
-				$this->errors[] = $this->db->lasterror();
7264
-			}
7265
-		}
7266
-
7267
-		// Update extrafield
7268
-		if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options)>0)
7269
-		{
7270
-			$result=$this->insertExtraFields();
7271
-			if ($result < 0)
7272
-			{
7273
-				$error++;
7274
-			}
7275
-		}
7276
-
7277
-		// Triggers
7278
-		if (! $error && ! $notrigger)
7279
-		{
7280
-			// Call triggers
7281
-			$result=$this->call_trigger(strtoupper(get_class($this)).'_MODIFY',$user);
7282
-			if ($result < 0) { $error++; } //Do also here what you must do to rollback action if trigger fail
7283
-			// End call triggers
7284
-		}
7285
-
7286
-		// Commit or rollback
7287
-		if ($error) {
7288
-			$this->db->rollback();
7289
-			return -1;
7290
-		} else {
7291
-			$this->db->commit();
7292
-			return $this->id;
7293
-		}
7294
-	}
7295
-
7296
-	/**
7297
-	 * Delete object in database
7298
-	 *
7299
-	 * @param 	User 	$user       			User that deletes
7300
-	 * @param 	bool 	$notrigger  			false=launch triggers after, true=disable triggers
7301
-	 * @param	int		$forcechilddeletion		0=no, 1=Force deletion of children
7302
-	 * @return 	int             				<=0 if KO, >0 if OK
7303
-	 */
7304
-	public function deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
7305
-	{
7306
-		$error=0;
7307
-
7308
-		$this->db->begin();
7309
-
7310
-		if ($forcechilddeletion)
7311
-		{
7312
-			foreach($this->childtables as $table)
7313
-			{
7314
-				$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$table.' WHERE '.$this->fk_element.' = '.$this->id;
7315
-				$resql = $this->db->query($sql);
7316
-				if (! $resql)
7317
-				{
7318
-					$this->error=$this->db->lasterror();
7319
-					$this->errors[]=$this->error;
7320
-					$this->db->rollback();
7321
-					return -1;
7322
-				}
7323
-			}
7324
-		}
7325
-		elseif (! empty($this->fk_element) && ! empty($this->childtables))	// If object has childs linked with a foreign key field, we check all child tables.
7326
-		{
7327
-			$objectisused = $this->isObjectUsed($this->id);
7328
-			if (! empty($objectisused))
7329
-			{
7330
-				dol_syslog(get_class($this)."::deleteCommon Can't delete record as it has some child", LOG_WARNING);
7331
-				$this->error='ErrorRecordHasChildren';
7332
-				$this->errors[]=$this->error;
7333
-				$this->db->rollback();
7334
-				return 0;
7335
-			}
7336
-		}
7337
-
7338
-		if (! $error) {
7339
-			if (! $notrigger) {
7340
-				// Call triggers
7341
-				$result=$this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user);
7342
-				if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
7343
-				// End call triggers
7344
-			}
7345
-		}
7346
-
7347
-		if (! $error && ! empty($this->isextrafieldmanaged))
7348
-		{
7349
-			$sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element."_extrafields";
7350
-			$sql.= " WHERE fk_object=" . $this->id;
7351
-
7352
-			$resql = $this->db->query($sql);
7353
-			if (! $resql)
7354
-			{
7355
-				$this->errors[] = $this->db->lasterror();
7356
-				$error++;
7357
-			}
7358
-		}
7397
+    /**
7398
+     * Load comments linked with current task
7399
+     *	@return boolean	1 if ok
7400
+     */
7401
+    public function fetchComments()
7402
+    {
7403
+        require_once DOL_DOCUMENT_ROOT.'/core/class/comment.class.php';
7359 7404
 
7360
-		if (! $error)
7361
-		{
7362
-			$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
7405
+        $comment = new Comment($this->db);
7406
+        $result=$comment->fetchAllFor($this->element, $this->id);
7407
+        if ($result<0) {
7408
+            $this->errors=array_merge($this->errors, $comment->errors);
7409
+            return -1;
7410
+        } else {
7411
+            $this->comments = $comment->comments;
7412
+        }
7413
+        return count($this->comments);
7414
+    }
7363 7415
 
7364
-			$res = $this->db->query($sql);
7365
-			if($res===false) {
7366
-				$error++;
7367
-				$this->errors[] = $this->db->lasterror();
7368
-			}
7369
-		}
7370
-
7371
-		// Commit or rollback
7372
-		if ($error) {
7373
-			$this->db->rollback();
7374
-			return -1;
7375
-		} else {
7376
-			$this->db->commit();
7377
-			return 1;
7378
-		}
7379
-	}
7380
-
7381
-	/**
7382
-	 * Initialise object with example values
7383
-	 * Id must be 0 if object instance is a specimen
7384
-	 *
7385
-	 * @return void
7386
-	 */
7387
-	public function initAsSpecimenCommon()
7388
-	{
7389
-		$this->id = 0;
7390
-
7391
-		// TODO...
7392
-	}
7393
-
7394
-
7395
-	/* Part for comments */
7396
-
7397
-	/**
7398
-	 * Load comments linked with current task
7399
-	 *	@return boolean	1 if ok
7400
-	 */
7401
-	public function fetchComments()
7402
-	{
7403
-		require_once DOL_DOCUMENT_ROOT.'/core/class/comment.class.php';
7404
-
7405
-		$comment = new Comment($this->db);
7406
-		$result=$comment->fetchAllFor($this->element, $this->id);
7407
-		if ($result<0) {
7408
-			$this->errors=array_merge($this->errors, $comment->errors);
7409
-			return -1;
7410
-		} else {
7411
-			$this->comments = $comment->comments;
7412
-		}
7413
-		return count($this->comments);
7414
-	}
7415
-
7416
-	/**
7417
-	 * Return nb comments already posted
7418
-	 *
7419
-	 * @return int
7420
-	 */
7421
-	public function getNbComments()
7422
-	{
7423
-		return count($this->comments);
7424
-	}
7416
+    /**
7417
+     * Return nb comments already posted
7418
+     *
7419
+     * @return int
7420
+     */
7421
+    public function getNbComments()
7422
+    {
7423
+        return count($this->comments);
7424
+    }
7425 7425
 
7426 7426
     /**
7427 7427
      * Trim object parameters
Please login to merge, or discard this patch.
dolibarr/htdocs/core/class/dolgraph.class.php 1 patch
Indentation   +945 added lines, -945 removed lines patch added patch discarded remove patch
@@ -39,941 +39,941 @@  discard block
 block discarded – undo
39 39
  */
40 40
 class DolGraph
41 41
 {
42
-	public $type=array();			// Array with type of each series. Example: array('bars', 'lines', ...)
43
-	public $mode='side';		    // Mode bars graph: side, depth
44
-	private $_library='jflot';	// Graphic library to use (jflot, artichow)
45
-
46
-	//! Array of data
47
-	public $data;				// Data of graph: array(array('abs1',valA1,valB1), array('abs2',valA2,valB2), ...)
48
-	public $title;				// Title of graph
49
-	public $cssprefix='';		// To add into css styles
50
-	public $width=380;
51
-	public $height=200;
52
-	public $MaxValue=0;
53
-	public $MinValue=0;
54
-	public $SetShading=0;
55
-
56
-	public $PrecisionY=-1;
57
-
58
-	public $horizTickIncrement=-1;
59
-	public $SetNumXTicks=-1;
60
-	public $labelInterval=-1;
61
-
62
-	public $hideXGrid=false;
63
-	public $hideYGrid=false;
64
-
65
-	public $Legend=array();
66
-	public $LegendWidthMin=0;
67
-	public $showlegend=1;
68
-	public $showpointvalue=1;
69
-	public $showpercent=0;
70
-	public $combine=0;				// 0.05 if you want to combine records < 5% into "other"
71
-	public $graph;     			// Objet Graph (Artichow, Phplot...)
72
-
73
-	/**
74
-	 * @var string Error code (or message)
75
-	 */
76
-	public $error='';
77
-
78
-	public $bordercolor;			// array(R,G,B)
79
-	public $bgcolor;				// array(R,G,B)
80
-	public $bgcolorgrid=array(255,255,255);			// array(R,G,B)
81
-	public $datacolor;				// array(array(R,G,B),...)
82
-
83
-	private $stringtoshow;      // To store string to output graph into HTML page
84
-
85
-
86
-	/**
87
-	 * Constructor
88
-	 *
89
-	 * @param	string	$library		'jflot' (default) or 'artichow' (no more supported)
90
-	 */
91
-	function __construct($library='jflot')
92
-	{
93
-		global $conf;
94
-		global $theme_bordercolor, $theme_datacolor, $theme_bgcolor, $theme_bgcoloronglet;
95
-
96
-		// To use old feature
97
-		if ($library == 'artichow')
98
-		{
99
-			$this->_library='artichow';
100
-
101
-			// Test if module GD present
102
-			$modules_list = get_loaded_extensions();
103
-			$isgdinstalled=0;
104
-			foreach ($modules_list as $module)
105
-			{
106
-				if ($module == 'gd') $isgdinstalled=1;
107
-			}
108
-			if (! $isgdinstalled)
109
-			{
110
-				$this->error="Error: PHP GD module is not available. It is required to build graphics.";
111
-				return -1;
112
-			}
113
-		}
114
-
115
-		$this->bordercolor = array(235,235,224);
116
-		$this->datacolor = array(array(120,130,150), array(160,160,180), array(190,190,220));
117
-		$this->bgcolor = array(235,235,224);
118
-
119
-		$color_file = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/graph-color.php';
120
-		if (is_readable($color_file))
121
-		{
122
-			include_once $color_file;
123
-			if (isset($theme_bordercolor)) $this->bordercolor = $theme_bordercolor;
124
-			if (isset($theme_datacolor))   $this->datacolor   = $theme_datacolor;
125
-			if (isset($theme_bgcolor))     $this->bgcolor     = $theme_bgcolor;
126
-		}
127
-		//print 'bgcolor: '.join(',',$this->bgcolor).'<br>';
128
-	}
42
+    public $type=array();			// Array with type of each series. Example: array('bars', 'lines', ...)
43
+    public $mode='side';		    // Mode bars graph: side, depth
44
+    private $_library='jflot';	// Graphic library to use (jflot, artichow)
45
+
46
+    //! Array of data
47
+    public $data;				// Data of graph: array(array('abs1',valA1,valB1), array('abs2',valA2,valB2), ...)
48
+    public $title;				// Title of graph
49
+    public $cssprefix='';		// To add into css styles
50
+    public $width=380;
51
+    public $height=200;
52
+    public $MaxValue=0;
53
+    public $MinValue=0;
54
+    public $SetShading=0;
55
+
56
+    public $PrecisionY=-1;
57
+
58
+    public $horizTickIncrement=-1;
59
+    public $SetNumXTicks=-1;
60
+    public $labelInterval=-1;
61
+
62
+    public $hideXGrid=false;
63
+    public $hideYGrid=false;
64
+
65
+    public $Legend=array();
66
+    public $LegendWidthMin=0;
67
+    public $showlegend=1;
68
+    public $showpointvalue=1;
69
+    public $showpercent=0;
70
+    public $combine=0;				// 0.05 if you want to combine records < 5% into "other"
71
+    public $graph;     			// Objet Graph (Artichow, Phplot...)
72
+
73
+    /**
74
+     * @var string Error code (or message)
75
+     */
76
+    public $error='';
77
+
78
+    public $bordercolor;			// array(R,G,B)
79
+    public $bgcolor;				// array(R,G,B)
80
+    public $bgcolorgrid=array(255,255,255);			// array(R,G,B)
81
+    public $datacolor;				// array(array(R,G,B),...)
82
+
83
+    private $stringtoshow;      // To store string to output graph into HTML page
84
+
85
+
86
+    /**
87
+     * Constructor
88
+     *
89
+     * @param	string	$library		'jflot' (default) or 'artichow' (no more supported)
90
+     */
91
+    function __construct($library='jflot')
92
+    {
93
+        global $conf;
94
+        global $theme_bordercolor, $theme_datacolor, $theme_bgcolor, $theme_bgcoloronglet;
95
+
96
+        // To use old feature
97
+        if ($library == 'artichow')
98
+        {
99
+            $this->_library='artichow';
100
+
101
+            // Test if module GD present
102
+            $modules_list = get_loaded_extensions();
103
+            $isgdinstalled=0;
104
+            foreach ($modules_list as $module)
105
+            {
106
+                if ($module == 'gd') $isgdinstalled=1;
107
+            }
108
+            if (! $isgdinstalled)
109
+            {
110
+                $this->error="Error: PHP GD module is not available. It is required to build graphics.";
111
+                return -1;
112
+            }
113
+        }
114
+
115
+        $this->bordercolor = array(235,235,224);
116
+        $this->datacolor = array(array(120,130,150), array(160,160,180), array(190,190,220));
117
+        $this->bgcolor = array(235,235,224);
118
+
119
+        $color_file = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/graph-color.php';
120
+        if (is_readable($color_file))
121
+        {
122
+            include_once $color_file;
123
+            if (isset($theme_bordercolor)) $this->bordercolor = $theme_bordercolor;
124
+            if (isset($theme_datacolor))   $this->datacolor   = $theme_datacolor;
125
+            if (isset($theme_bgcolor))     $this->bgcolor     = $theme_bgcolor;
126
+        }
127
+        //print 'bgcolor: '.join(',',$this->bgcolor).'<br>';
128
+    }
129 129
 
130 130
 
131 131
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
132
-	/**
133
-	 * Set Y precision
134
-	 *
135
-	 * @param 	float	$which_prec		Precision
136
-	 * @return 	boolean
137
-	 */
138
-	function SetPrecisionY($which_prec)
139
-	{
132
+    /**
133
+     * Set Y precision
134
+     *
135
+     * @param 	float	$which_prec		Precision
136
+     * @return 	boolean
137
+     */
138
+    function SetPrecisionY($which_prec)
139
+    {
140 140
         // phpcs:enable
141
-		$this->PrecisionY = $which_prec;
142
-		return true;
143
-	}
141
+        $this->PrecisionY = $which_prec;
142
+        return true;
143
+    }
144 144
 
145 145
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
146
-	/**
147
-	 * Utiliser SetNumTicks ou SetHorizTickIncrement mais pas les 2
148
-	 *
149
-	 * @param 	float 		$xi		Xi
150
-	 * @return	boolean				True
151
-	 */
152
-	function SetHorizTickIncrement($xi)
153
-	{
146
+    /**
147
+     * Utiliser SetNumTicks ou SetHorizTickIncrement mais pas les 2
148
+     *
149
+     * @param 	float 		$xi		Xi
150
+     * @return	boolean				True
151
+     */
152
+    function SetHorizTickIncrement($xi)
153
+    {
154 154
         // phpcs:enable
155
-		$this->horizTickIncrement = $xi;
156
-		return true;
157
-	}
155
+        $this->horizTickIncrement = $xi;
156
+        return true;
157
+    }
158 158
 
159 159
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
160
-	/**
161
-	 * Utiliser SetNumTicks ou SetHorizTickIncrement mais pas les 2
162
-	 *
163
-	 * @param 	float 		$xt		Xt
164
-	 * @return	boolean				True
165
-	 */
166
-	function SetNumXTicks($xt)
167
-	{
160
+    /**
161
+     * Utiliser SetNumTicks ou SetHorizTickIncrement mais pas les 2
162
+     *
163
+     * @param 	float 		$xt		Xt
164
+     * @return	boolean				True
165
+     */
166
+    function SetNumXTicks($xt)
167
+    {
168 168
         // phpcs:enable
169
-		$this->SetNumXTicks = $xt;
170
-		return true;
171
-	}
169
+        $this->SetNumXTicks = $xt;
170
+        return true;
171
+    }
172 172
 
173 173
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
174
-	/**
175
-	 * Set label interval to reduce number of labels
176
-	 *
177
-	 * @param 	float 		$x		Label interval
178
-	 * @return	boolean				True
179
-	 */
180
-	function SetLabelInterval($x)
181
-	{
174
+    /**
175
+     * Set label interval to reduce number of labels
176
+     *
177
+     * @param 	float 		$x		Label interval
178
+     * @return	boolean				True
179
+     */
180
+    function SetLabelInterval($x)
181
+    {
182 182
         // phpcs:enable
183
-		$this->labelInterval = $x;
184
-		return true;
185
-	}
183
+        $this->labelInterval = $x;
184
+        return true;
185
+    }
186 186
 
187 187
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
188
-	/**
189
-	 * Hide X grid
190
-	 *
191
-	 * @param	boolean		$bool	XGrid or not
192
-	 * @return	boolean				true
193
-	 */
194
-	function SetHideXGrid($bool)
195
-	{
188
+    /**
189
+     * Hide X grid
190
+     *
191
+     * @param	boolean		$bool	XGrid or not
192
+     * @return	boolean				true
193
+     */
194
+    function SetHideXGrid($bool)
195
+    {
196 196
         // phpcs:enable
197
-		$this->hideXGrid = $bool;
198
-		return true;
199
-	}
197
+        $this->hideXGrid = $bool;
198
+        return true;
199
+    }
200 200
 
201 201
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
202
-	/**
203
-	 * Hide Y grid
204
-	 *
205
-	 * @param	boolean		$bool	YGrid or not
206
-	 * @return	boolean				true
207
-	 */
208
-	function SetHideYGrid($bool)
209
-	{
202
+    /**
203
+     * Hide Y grid
204
+     *
205
+     * @param	boolean		$bool	YGrid or not
206
+     * @return	boolean				true
207
+     */
208
+    function SetHideYGrid($bool)
209
+    {
210 210
         // phpcs:enable
211
-		$this->hideYGrid = $bool;
212
-		return true;
213
-	}
211
+        $this->hideYGrid = $bool;
212
+        return true;
213
+    }
214 214
 
215 215
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
216
-	/**
217
-	 * Set y label
218
-	 *
219
-	 * @param 	string	$label		Y label
220
-	 * @return	boolean|null				True
221
-	 */
222
-	function SetYLabel($label)
223
-	{
216
+    /**
217
+     * Set y label
218
+     *
219
+     * @param 	string	$label		Y label
220
+     * @return	boolean|null				True
221
+     */
222
+    function SetYLabel($label)
223
+    {
224 224
         // phpcs:enable
225
-		$this->YLabel = $label;
226
-	}
225
+        $this->YLabel = $label;
226
+    }
227 227
 
228 228
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
229
-	/**
230
-	 * Set width
231
-	 *
232
-	 * @param 	int		$w			Width
233
-	 * @return	boolean|null				True
234
-	 */
235
-	function SetWidth($w)
236
-	{
229
+    /**
230
+     * Set width
231
+     *
232
+     * @param 	int		$w			Width
233
+     * @return	boolean|null				True
234
+     */
235
+    function SetWidth($w)
236
+    {
237 237
         // phpcs:enable
238
-		$this->width = $w;
239
-	}
238
+        $this->width = $w;
239
+    }
240 240
 
241 241
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
242
-	/**
243
-	 * Set title
244
-	 *
245
-	 * @param 	string	$title		Title
246
-	 * @return	void
247
-	 */
248
-	function SetTitle($title)
249
-	{
242
+    /**
243
+     * Set title
244
+     *
245
+     * @param 	string	$title		Title
246
+     * @return	void
247
+     */
248
+    function SetTitle($title)
249
+    {
250 250
         // phpcs:enable
251
-		$this->title = $title;
252
-	}
251
+        $this->title = $title;
252
+    }
253 253
 
254 254
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
255
-	/**
256
-	 * Set data
257
-	 *
258
-	 * @param 	array	$data		Data
259
-	 * @return	void
260
-	 * @see draw_jflot for syntax of data array
261
-	 */
262
-	function SetData($data)
263
-	{
255
+    /**
256
+     * Set data
257
+     *
258
+     * @param 	array	$data		Data
259
+     * @return	void
260
+     * @see draw_jflot for syntax of data array
261
+     */
262
+    function SetData($data)
263
+    {
264 264
         // phpcs:enable
265
-		$this->data = $data;
266
-	}
265
+        $this->data = $data;
266
+    }
267 267
 
268 268
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
269
-	/**
270
-	 * Set data
271
-	 *
272
-	 * @param 	array	$datacolor		Data color array(array(R,G,B),array(R,G,B)...)
273
-	 * @return	void
274
-	 */
275
-	function SetDataColor($datacolor)
276
-	{
269
+    /**
270
+     * Set data
271
+     *
272
+     * @param 	array	$datacolor		Data color array(array(R,G,B),array(R,G,B)...)
273
+     * @return	void
274
+     */
275
+    function SetDataColor($datacolor)
276
+    {
277 277
         // phpcs:enable
278
-		$this->datacolor = $datacolor;
279
-	}
278
+        $this->datacolor = $datacolor;
279
+    }
280 280
 
281 281
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
282
-	/**
283
-	 * Set type
284
-	 *
285
-	 * @param 	array	$type		Array with type for each serie. Example: array('pie'), array('lines',...,'bars')
286
-	 * @return	void
287
-	 */
288
-	function SetType($type)
289
-	{
282
+    /**
283
+     * Set type
284
+     *
285
+     * @param 	array	$type		Array with type for each serie. Example: array('pie'), array('lines',...,'bars')
286
+     * @return	void
287
+     */
288
+    function SetType($type)
289
+    {
290 290
         // phpcs:enable
291
-		$this->type = $type;
292
-	}
291
+        $this->type = $type;
292
+    }
293 293
 
294 294
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
295
-	/**
296
-	 * Set legend
297
-	 *
298
-	 * @param 	array	$legend		Legend. Example: array('seriename1','seriname2',...)
299
-	 * @return	void
300
-	 */
301
-	function SetLegend($legend)
302
-	{
295
+    /**
296
+     * Set legend
297
+     *
298
+     * @param 	array	$legend		Legend. Example: array('seriename1','seriname2',...)
299
+     * @return	void
300
+     */
301
+    function SetLegend($legend)
302
+    {
303 303
         // phpcs:enable
304
-		$this->Legend = $legend;
305
-	}
304
+        $this->Legend = $legend;
305
+    }
306 306
 
307 307
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
308
-	/**
309
-	 * Set min width
310
-	 *
311
-	 * @param 	int		$legendwidthmin		Min width
312
-	 * @return	void
313
-	 */
314
-	function SetLegendWidthMin($legendwidthmin)
315
-	{
308
+    /**
309
+     * Set min width
310
+     *
311
+     * @param 	int		$legendwidthmin		Min width
312
+     * @return	void
313
+     */
314
+    function SetLegendWidthMin($legendwidthmin)
315
+    {
316 316
         // phpcs:enable
317
-		$this->LegendWidthMin = $legendwidthmin;
318
-	}
317
+        $this->LegendWidthMin = $legendwidthmin;
318
+    }
319 319
 
320 320
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
321
-	/**
322
-	 * Set max value
323
-	 *
324
-	 * @param 	int		$max			Max value
325
-	 * @return	void
326
-	 */
327
-	function SetMaxValue($max)
328
-	{
321
+    /**
322
+     * Set max value
323
+     *
324
+     * @param 	int		$max			Max value
325
+     * @return	void
326
+     */
327
+    function SetMaxValue($max)
328
+    {
329 329
         // phpcs:enable
330
-		$this->MaxValue = $max;
331
-	}
330
+        $this->MaxValue = $max;
331
+    }
332 332
 
333 333
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
334
-	/**
335
-	 * Get max value
336
-	 *
337
-	 * @return	int		Max value
338
-	 */
339
-	function GetMaxValue()
340
-	{
334
+    /**
335
+     * Get max value
336
+     *
337
+     * @return	int		Max value
338
+     */
339
+    function GetMaxValue()
340
+    {
341 341
         // phpcs:enable
342
-		return $this->MaxValue;
343
-	}
342
+        return $this->MaxValue;
343
+    }
344 344
 
345 345
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
346
-	/**
347
-	 * Set min value
348
-	 *
349
-	 * @param 	int		$min			Min value
350
-	 * @return	void
351
-	 */
352
-	function SetMinValue($min)
353
-	{
346
+    /**
347
+     * Set min value
348
+     *
349
+     * @param 	int		$min			Min value
350
+     * @return	void
351
+     */
352
+    function SetMinValue($min)
353
+    {
354 354
         // phpcs:enable
355
-		$this->MinValue = $min;
356
-	}
355
+        $this->MinValue = $min;
356
+    }
357 357
 
358 358
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
359
-	/**
360
-	 * Get min value
361
-	 *
362
-	 * @return	int		Max value
363
-	 */
364
-	function GetMinValue()
365
-	{
359
+    /**
360
+     * Get min value
361
+     *
362
+     * @return	int		Max value
363
+     */
364
+    function GetMinValue()
365
+    {
366 366
         // phpcs:enable
367
-		return $this->MinValue;
368
-	}
367
+        return $this->MinValue;
368
+    }
369 369
 
370 370
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
371
-	/**
372
-	 * Set height
373
-	 *
374
-	 * @param 	int		$h				Height
375
-	 * @return	void
376
-	 */
377
-	function SetHeight($h)
378
-	{
371
+    /**
372
+     * Set height
373
+     *
374
+     * @param 	int		$h				Height
375
+     * @return	void
376
+     */
377
+    function SetHeight($h)
378
+    {
379 379
         // phpcs:enable
380
-		$this->height = $h;
381
-	}
380
+        $this->height = $h;
381
+    }
382 382
 
383 383
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
384
-	/**
385
-	 * Set shading
386
-	 *
387
-	 * @param 	string	$s				Shading
388
-	 * @return	void
389
-	 */
390
-	function SetShading($s)
391
-	{
384
+    /**
385
+     * Set shading
386
+     *
387
+     * @param 	string	$s				Shading
388
+     * @return	void
389
+     */
390
+    function SetShading($s)
391
+    {
392 392
         // phpcs:enable
393
-		$this->SetShading = $s;
394
-	}
393
+        $this->SetShading = $s;
394
+    }
395 395
 
396 396
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
397
-	/**
398
-	 * Set shading
399
-	 *
400
-	 * @param 	string	$s				Shading
401
-	 * @return	void
402
-	 */
403
-	function SetCssPrefix($s)
404
-	{
397
+    /**
398
+     * Set shading
399
+     *
400
+     * @param 	string	$s				Shading
401
+     * @return	void
402
+     */
403
+    function SetCssPrefix($s)
404
+    {
405 405
         // phpcs:enable
406
-		$this->cssprefix = $s;
407
-	}
406
+        $this->cssprefix = $s;
407
+    }
408 408
 
409 409
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
410
-	/**
411
-	 * Reset bg color
412
-	 *
413
-	 * @return	void
414
-	 */
415
-	function ResetBgColor()
416
-	{
410
+    /**
411
+     * Reset bg color
412
+     *
413
+     * @return	void
414
+     */
415
+    function ResetBgColor()
416
+    {
417 417
         // phpcs:enable
418
-		unset($this->bgcolor);
419
-	}
418
+        unset($this->bgcolor);
419
+    }
420 420
 
421 421
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
422
-	/**
423
-	 * Reset bgcolorgrid
424
-	 *
425
-	 * @return	void
426
-	 */
427
-	function ResetBgColorGrid()
428
-	{
422
+    /**
423
+     * Reset bgcolorgrid
424
+     *
425
+     * @return	void
426
+     */
427
+    function ResetBgColorGrid()
428
+    {
429 429
         // phpcs:enable
430
-		unset($this->bgcolorgrid);
431
-	}
432
-
433
-	/**
434
-	 * Is graph ko
435
-	 *
436
-	 * @return	string		Error
437
-	 */
438
-	function isGraphKo()
439
-	{
440
-		return $this->error;
441
-	}
442
-
443
-	/**
444
-	 * Show legend or not
445
-	 *
446
-	 * @param	int		$showlegend		1=Show legend (default), 0=Hide legend
447
-	 * @return	void
448
-	 */
449
-	function setShowLegend($showlegend)
450
-	{
451
-		$this->showlegend=$showlegend;
452
-	}
453
-
454
-	/**
455
-	 * Show pointvalue or not
456
-	 *
457
-	 * @param	int		$showpointvalue		1=Show value for each point, as tooltip or inline (default), 0=Hide value
458
-	 * @return	void
459
-	 */
460
-	function setShowPointValue($showpointvalue)
461
-	{
462
-		$this->showpointvalue=$showpointvalue;
463
-	}
464
-
465
-	/**
466
-	 * Show percent or not
467
-	 *
468
-	 * @param	int		$showpercent		1=Show percent for each point, as tooltip or inline, 0=Hide percent (default)
469
-	 * @return	void
470
-	 */
471
-	function setShowPercent($showpercent)
472
-	{
473
-		$this->showpercent=$showpercent;
474
-	}
430
+        unset($this->bgcolorgrid);
431
+    }
432
+
433
+    /**
434
+     * Is graph ko
435
+     *
436
+     * @return	string		Error
437
+     */
438
+    function isGraphKo()
439
+    {
440
+        return $this->error;
441
+    }
442
+
443
+    /**
444
+     * Show legend or not
445
+     *
446
+     * @param	int		$showlegend		1=Show legend (default), 0=Hide legend
447
+     * @return	void
448
+     */
449
+    function setShowLegend($showlegend)
450
+    {
451
+        $this->showlegend=$showlegend;
452
+    }
453
+
454
+    /**
455
+     * Show pointvalue or not
456
+     *
457
+     * @param	int		$showpointvalue		1=Show value for each point, as tooltip or inline (default), 0=Hide value
458
+     * @return	void
459
+     */
460
+    function setShowPointValue($showpointvalue)
461
+    {
462
+        $this->showpointvalue=$showpointvalue;
463
+    }
464
+
465
+    /**
466
+     * Show percent or not
467
+     *
468
+     * @param	int		$showpercent		1=Show percent for each point, as tooltip or inline, 0=Hide percent (default)
469
+     * @return	void
470
+     */
471
+    function setShowPercent($showpercent)
472
+    {
473
+        $this->showpercent=$showpercent;
474
+    }
475 475
 
476 476
 
477 477
 
478 478
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
479
-	/**
480
-	 * Define background color of complete image
481
-	 *
482
-	 * @param	array	$bg_color		array(R,G,B) ou 'onglet' ou 'default'
483
-	 * @return	void
484
-	 */
485
-	function SetBgColor($bg_color = array(255,255,255))
486
-	{
479
+    /**
480
+     * Define background color of complete image
481
+     *
482
+     * @param	array	$bg_color		array(R,G,B) ou 'onglet' ou 'default'
483
+     * @return	void
484
+     */
485
+    function SetBgColor($bg_color = array(255,255,255))
486
+    {
487 487
         // phpcs:enable
488
-		global $theme_bgcolor,$theme_bgcoloronglet;
489
-
490
-		if (! is_array($bg_color))
491
-		{
492
-			if ($bg_color == 'onglet')
493
-			{
494
-				//print 'ee'.join(',',$theme_bgcoloronglet);
495
-				$this->bgcolor = $theme_bgcoloronglet;
496
-			}
497
-			else
498
-			{
499
-				$this->bgcolor = $theme_bgcolor;
500
-			}
501
-		}
502
-		else
503
-		{
504
-			$this->bgcolor = $bg_color;
505
-		}
506
-	}
488
+        global $theme_bgcolor,$theme_bgcoloronglet;
489
+
490
+        if (! is_array($bg_color))
491
+        {
492
+            if ($bg_color == 'onglet')
493
+            {
494
+                //print 'ee'.join(',',$theme_bgcoloronglet);
495
+                $this->bgcolor = $theme_bgcoloronglet;
496
+            }
497
+            else
498
+            {
499
+                $this->bgcolor = $theme_bgcolor;
500
+            }
501
+        }
502
+        else
503
+        {
504
+            $this->bgcolor = $bg_color;
505
+        }
506
+    }
507 507
 
508 508
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
509
-	/**
510
-	 * Define background color of grid
511
-	 *
512
-	 * @param	array	$bg_colorgrid		array(R,G,B) ou 'onglet' ou 'default'
513
-	 * @return	void
514
-	 */
515
-	function SetBgColorGrid($bg_colorgrid = array(255,255,255))
516
-	{
509
+    /**
510
+     * Define background color of grid
511
+     *
512
+     * @param	array	$bg_colorgrid		array(R,G,B) ou 'onglet' ou 'default'
513
+     * @return	void
514
+     */
515
+    function SetBgColorGrid($bg_colorgrid = array(255,255,255))
516
+    {
517 517
         // phpcs:enable
518
-		global $theme_bgcolor,$theme_bgcoloronglet;
519
-
520
-		if (! is_array($bg_colorgrid))
521
-		{
522
-			if ($bg_colorgrid == 'onglet')
523
-			{
524
-				//print 'ee'.join(',',$theme_bgcoloronglet);
525
-				$this->bgcolorgrid = $theme_bgcoloronglet;
526
-			}
527
-			else
528
-			{
529
-				$this->bgcolorgrid = $theme_bgcolor;
530
-			}
531
-		}
532
-		else
533
-		{
534
-			$this->bgcolorgrid = $bg_colorgrid;
535
-		}
536
-	}
518
+        global $theme_bgcolor,$theme_bgcoloronglet;
519
+
520
+        if (! is_array($bg_colorgrid))
521
+        {
522
+            if ($bg_colorgrid == 'onglet')
523
+            {
524
+                //print 'ee'.join(',',$theme_bgcoloronglet);
525
+                $this->bgcolorgrid = $theme_bgcoloronglet;
526
+            }
527
+            else
528
+            {
529
+                $this->bgcolorgrid = $theme_bgcolor;
530
+            }
531
+        }
532
+        else
533
+        {
534
+            $this->bgcolorgrid = $bg_colorgrid;
535
+        }
536
+    }
537 537
 
538 538
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
539
-	/**
540
-	 * Reset data color
541
-	 *
542
-	 * @return	void
543
-	 */
544
-	function ResetDataColor()
545
-	{
539
+    /**
540
+     * Reset data color
541
+     *
542
+     * @return	void
543
+     */
544
+    function ResetDataColor()
545
+    {
546 546
         // phpcs:enable
547
-		unset($this->datacolor);
548
-	}
547
+        unset($this->datacolor);
548
+    }
549 549
 
550 550
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
551
-	/**
552
-	 * Get max value
553
-	 *
554
-	 * @return	int		Max value
555
-	 */
556
-	function GetMaxValueInData()
557
-	{
551
+    /**
552
+     * Get max value
553
+     *
554
+     * @return	int		Max value
555
+     */
556
+    function GetMaxValueInData()
557
+    {
558 558
         // phpcs:enable
559
-		$k = 0;
560
-		$vals = array();
561
-
562
-		$nblines = count($this->data);
563
-		$nbvalues = count($this->data[0]) - 1;
564
-
565
-		for ($j = 0 ; $j < $nblines ; $j++)
566
-		{
567
-			for ($i = 0 ; $i < $nbvalues ; $i++)
568
-			{
569
-				$vals[$k] = $this->data[$j][$i+1];
570
-				$k++;
571
-			}
572
-		}
573
-		rsort($vals);
574
-		return $vals[0];
575
-	}
559
+        $k = 0;
560
+        $vals = array();
561
+
562
+        $nblines = count($this->data);
563
+        $nbvalues = count($this->data[0]) - 1;
564
+
565
+        for ($j = 0 ; $j < $nblines ; $j++)
566
+        {
567
+            for ($i = 0 ; $i < $nbvalues ; $i++)
568
+            {
569
+                $vals[$k] = $this->data[$j][$i+1];
570
+                $k++;
571
+            }
572
+        }
573
+        rsort($vals);
574
+        return $vals[0];
575
+    }
576 576
 
577 577
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
578
-	/**
579
-	 * Return min value of all data
580
-	 *
581
-	 * @return	int		Min value of all data
582
-	 */
583
-	function GetMinValueInData()
584
-	{
578
+    /**
579
+     * Return min value of all data
580
+     *
581
+     * @return	int		Min value of all data
582
+     */
583
+    function GetMinValueInData()
584
+    {
585 585
         // phpcs:enable
586
-		$k = 0;
587
-		$vals = array();
588
-
589
-		$nblines = count($this->data);
590
-		$nbvalues = count($this->data[0]) - 1;
591
-
592
-		for ($j = 0 ; $j < $nblines ; $j++)
593
-		{
594
-			for ($i = 0 ; $i < $nbvalues ; $i++)
595
-			{
596
-				$vals[$k] = $this->data[$j][$i+1];
597
-				$k++;
598
-			}
599
-		}
600
-		sort($vals);
601
-		return $vals[0];
602
-	}
586
+        $k = 0;
587
+        $vals = array();
588
+
589
+        $nblines = count($this->data);
590
+        $nbvalues = count($this->data[0]) - 1;
591
+
592
+        for ($j = 0 ; $j < $nblines ; $j++)
593
+        {
594
+            for ($i = 0 ; $i < $nbvalues ; $i++)
595
+            {
596
+                $vals[$k] = $this->data[$j][$i+1];
597
+                $k++;
598
+            }
599
+        }
600
+        sort($vals);
601
+        return $vals[0];
602
+    }
603 603
 
604 604
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
605
-	/**
606
-	 * Return max value of all data
607
-	 *
608
-	 * @return 	int		Max value of all data
609
-	 */
610
-	function GetCeilMaxValue()
611
-	{
605
+    /**
606
+     * Return max value of all data
607
+     *
608
+     * @return 	int		Max value of all data
609
+     */
610
+    function GetCeilMaxValue()
611
+    {
612 612
         // phpcs:enable
613
-		$max = $this->GetMaxValueInData();
614
-		if ($max != 0) $max++;
615
-		$size=dol_strlen(abs(ceil($max)));
616
-		$factor=1;
617
-		for ($i=0; $i < ($size-1); $i++)
618
-		{
619
-			$factor*=10;
620
-		}
621
-
622
-		$res=0;
623
-		if (is_numeric($max)) $res=ceil($max/$factor)*$factor;
624
-
625
-		//print "max=".$max." res=".$res;
626
-		return $res;
627
-	}
613
+        $max = $this->GetMaxValueInData();
614
+        if ($max != 0) $max++;
615
+        $size=dol_strlen(abs(ceil($max)));
616
+        $factor=1;
617
+        for ($i=0; $i < ($size-1); $i++)
618
+        {
619
+            $factor*=10;
620
+        }
621
+
622
+        $res=0;
623
+        if (is_numeric($max)) $res=ceil($max/$factor)*$factor;
624
+
625
+        //print "max=".$max." res=".$res;
626
+        return $res;
627
+    }
628 628
 
629 629
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
630
-	/**
631
-	 * Return min value of all data
632
-	 *
633
-	 * @return 	double		Max value of all data
634
-	 */
635
-	function GetFloorMinValue()
636
-	{
630
+    /**
631
+     * Return min value of all data
632
+     *
633
+     * @return 	double		Max value of all data
634
+     */
635
+    function GetFloorMinValue()
636
+    {
637 637
         // phpcs:enable
638
-		$min = $this->GetMinValueInData();
639
-		if ($min == '') $min=0;
640
-		if ($min != 0) $min--;
641
-		$size=dol_strlen(abs(floor($min)));
642
-		$factor=1;
643
-		for ($i=0; $i < ($size-1); $i++)
644
-		{
645
-			$factor*=10;
646
-		}
647
-
648
-		$res=floor($min/$factor)*$factor;
649
-
650
-		//print "min=".$min." res=".$res;
651
-		return $res;
652
-	}
653
-
654
-	/**
655
-	 * Build a graph into memory using correct library  (may also be wrote on disk, depending on library used)
656
-	 *
657
-	 * @param	string	$file    	Image file name to use to save onto disk (also used as javascript unique id)
658
-	 * @param	string	$fileurl	Url path to show image if saved onto disk
659
-	 * @return	integer|null
660
-	 */
661
-	function draw($file, $fileurl='')
662
-	{
663
-		if (empty($file))
664
-		{
665
-			$this->error="Call to draw method was made with empty value for parameter file.";
666
-			dol_syslog(get_class($this)."::draw ".$this->error, LOG_ERR);
667
-			return -2;
668
-		}
669
-		if (! is_array($this->data))
670
-		{
671
-			$this->error="Call to draw method was made but SetData was not called or called with an empty dataset for parameters";
672
-			dol_syslog(get_class($this)."::draw ".$this->error, LOG_ERR);
673
-			return -1;
674
-		}
675
-		if (count($this->data) < 1)
676
-		{
677
-			$this->error="Call to draw method was made but SetData was is an empty dataset";
678
-			dol_syslog(get_class($this)."::draw ".$this->error, LOG_WARNING);
679
-		}
680
-		$call = "draw_".$this->_library;
681
-		call_user_func_array(array($this,$call), array($file,$fileurl));
682
-	}
638
+        $min = $this->GetMinValueInData();
639
+        if ($min == '') $min=0;
640
+        if ($min != 0) $min--;
641
+        $size=dol_strlen(abs(floor($min)));
642
+        $factor=1;
643
+        for ($i=0; $i < ($size-1); $i++)
644
+        {
645
+            $factor*=10;
646
+        }
647
+
648
+        $res=floor($min/$factor)*$factor;
649
+
650
+        //print "min=".$min." res=".$res;
651
+        return $res;
652
+    }
653
+
654
+    /**
655
+     * Build a graph into memory using correct library  (may also be wrote on disk, depending on library used)
656
+     *
657
+     * @param	string	$file    	Image file name to use to save onto disk (also used as javascript unique id)
658
+     * @param	string	$fileurl	Url path to show image if saved onto disk
659
+     * @return	integer|null
660
+     */
661
+    function draw($file, $fileurl='')
662
+    {
663
+        if (empty($file))
664
+        {
665
+            $this->error="Call to draw method was made with empty value for parameter file.";
666
+            dol_syslog(get_class($this)."::draw ".$this->error, LOG_ERR);
667
+            return -2;
668
+        }
669
+        if (! is_array($this->data))
670
+        {
671
+            $this->error="Call to draw method was made but SetData was not called or called with an empty dataset for parameters";
672
+            dol_syslog(get_class($this)."::draw ".$this->error, LOG_ERR);
673
+            return -1;
674
+        }
675
+        if (count($this->data) < 1)
676
+        {
677
+            $this->error="Call to draw method was made but SetData was is an empty dataset";
678
+            dol_syslog(get_class($this)."::draw ".$this->error, LOG_WARNING);
679
+        }
680
+        $call = "draw_".$this->_library;
681
+        call_user_func_array(array($this,$call), array($file,$fileurl));
682
+    }
683 683
 
684 684
 
685 685
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
686
-	/**
687
-	 * Build a graph onto disk using Artichow library and return img string to it
688
-	 *
689
-	 * @param	string	$file    	Image file name to use if we save onto disk
690
-	 * @param	string	$fileurl	Url path to show image if saved onto disk
691
-	 * @return	void
692
-	 */
693
-	private function draw_artichow($file,$fileurl)
694
-	{
686
+    /**
687
+     * Build a graph onto disk using Artichow library and return img string to it
688
+     *
689
+     * @param	string	$file    	Image file name to use if we save onto disk
690
+     * @param	string	$fileurl	Url path to show image if saved onto disk
691
+     * @return	void
692
+     */
693
+    private function draw_artichow($file,$fileurl)
694
+    {
695 695
         // phpcs:enable
696
-		global $artichow_defaultfont;
697
-
698
-		dol_syslog(get_class($this)."::draw_artichow this->type=".join(',',$this->type));
699
-
700
-		if (! defined('SHADOW_RIGHT_TOP'))  define('SHADOW_RIGHT_TOP',3);
701
-		if (! defined('LEGEND_BACKGROUND')) define('LEGEND_BACKGROUND',2);
702
-		if (! defined('LEGEND_LINE'))       define('LEGEND_LINE',1);
703
-
704
-		// Create graph
705
-		$classname='';
706
-		if (! isset($this->type[0]) || $this->type[0] == 'bars')  $classname='BarPlot';    // Only one type (first one) is supported by artichow
707
-		else if ($this->type[0] == 'lines' || $this->type[0] == 'linesnopoint') $classname='LinePlot';
708
-		else $classname='TypeUnknown';
709
-		include_once ARTICHOW_PATH.$classname.'.class.php';
710
-
711
-		// Definition de couleurs
712
-		$bgcolor=new Color($this->bgcolor[0],$this->bgcolor[1],$this->bgcolor[2]);
713
-		$bgcolorgrid=new Color($this->bgcolorgrid[0],$this->bgcolorgrid[1],$this->bgcolorgrid[2]);
714
-		$colortrans=new Color(0,0,0,100);
715
-		$colorsemitrans=new Color(255,255,255,60);
716
-		$colorgradient= new LinearGradient(new Color(235, 235, 235),new Color(255, 255, 255),0);
717
-		$colorwhite=new Color(255,255,255);
718
-
719
-		// Graph
720
-		$graph = new Graph($this->width, $this->height);
721
-		$graph->border->hide();
722
-		$graph->setAntiAliasing(true);
723
-		if (isset($this->title))
724
-		{
725
-			$graph->title->set($this->title);
726
-			//print $artichow_defaultfont;exit;
727
-			$graph->title->setFont(new $artichow_defaultfont(10));
728
-		}
729
-
730
-		if (is_array($this->bgcolor)) $graph->setBackgroundColor($bgcolor);
731
-		else $graph->setBackgroundGradient($colorgradient);
732
-
733
-		$group = new PlotGroup;
734
-		//$group->setSpace(5, 5, 0, 0);
735
-
736
-		$paddleft=50;
737
-		$paddright=10;
738
-		$strl=dol_strlen(max(abs($this->MaxValue),abs($this->MinValue)));
739
-		if ($strl > 6) $paddleft += ($strl * 4);
740
-		$group->setPadding($paddleft, $paddright);		// Width on left and right for Y axis values
741
-		$group->legend->setSpace(0);
742
-		$group->legend->setPadding(2,2,2,2);
743
-		$group->legend->setPosition(null, 0.1);
744
-		$group->legend->setBackgroundColor($colorsemitrans);
745
-
746
-		if (is_array($this->bgcolorgrid)) $group->grid->setBackgroundColor($bgcolorgrid);
747
-		else $group->grid->setBackgroundColor($colortrans);
748
-
749
-		if ($this->hideXGrid)	$group->grid->hideVertical(true);
750
-		if ($this->hideYGrid)	$group->grid->hideHorizontal(true);
751
-
752
-		// On boucle sur chaque lot de donnees
753
-		$legends=array();
754
-		$i=0;
755
-		$nblot=count($this->data[0])-1;
756
-
757
-		while ($i < $nblot)
758
-		{
759
-			$x=0;
760
-			$values=array();
761
-			foreach($this->data as $key => $valarray)
762
-			{
763
-				$legends[$x] = $valarray[0];
764
-				$values[$x]  = $valarray[$i+1];
765
-				$x++;
766
-			}
767
-
768
-			// We fix unknown values to null
769
-			$newvalues=array();
770
-			foreach($values as $val)
771
-			{
772
-				$newvalues[]=(is_numeric($val) ? $val : null);
773
-			}
696
+        global $artichow_defaultfont;
697
+
698
+        dol_syslog(get_class($this)."::draw_artichow this->type=".join(',',$this->type));
699
+
700
+        if (! defined('SHADOW_RIGHT_TOP'))  define('SHADOW_RIGHT_TOP',3);
701
+        if (! defined('LEGEND_BACKGROUND')) define('LEGEND_BACKGROUND',2);
702
+        if (! defined('LEGEND_LINE'))       define('LEGEND_LINE',1);
703
+
704
+        // Create graph
705
+        $classname='';
706
+        if (! isset($this->type[0]) || $this->type[0] == 'bars')  $classname='BarPlot';    // Only one type (first one) is supported by artichow
707
+        else if ($this->type[0] == 'lines' || $this->type[0] == 'linesnopoint') $classname='LinePlot';
708
+        else $classname='TypeUnknown';
709
+        include_once ARTICHOW_PATH.$classname.'.class.php';
710
+
711
+        // Definition de couleurs
712
+        $bgcolor=new Color($this->bgcolor[0],$this->bgcolor[1],$this->bgcolor[2]);
713
+        $bgcolorgrid=new Color($this->bgcolorgrid[0],$this->bgcolorgrid[1],$this->bgcolorgrid[2]);
714
+        $colortrans=new Color(0,0,0,100);
715
+        $colorsemitrans=new Color(255,255,255,60);
716
+        $colorgradient= new LinearGradient(new Color(235, 235, 235),new Color(255, 255, 255),0);
717
+        $colorwhite=new Color(255,255,255);
718
+
719
+        // Graph
720
+        $graph = new Graph($this->width, $this->height);
721
+        $graph->border->hide();
722
+        $graph->setAntiAliasing(true);
723
+        if (isset($this->title))
724
+        {
725
+            $graph->title->set($this->title);
726
+            //print $artichow_defaultfont;exit;
727
+            $graph->title->setFont(new $artichow_defaultfont(10));
728
+        }
729
+
730
+        if (is_array($this->bgcolor)) $graph->setBackgroundColor($bgcolor);
731
+        else $graph->setBackgroundGradient($colorgradient);
732
+
733
+        $group = new PlotGroup;
734
+        //$group->setSpace(5, 5, 0, 0);
735
+
736
+        $paddleft=50;
737
+        $paddright=10;
738
+        $strl=dol_strlen(max(abs($this->MaxValue),abs($this->MinValue)));
739
+        if ($strl > 6) $paddleft += ($strl * 4);
740
+        $group->setPadding($paddleft, $paddright);		// Width on left and right for Y axis values
741
+        $group->legend->setSpace(0);
742
+        $group->legend->setPadding(2,2,2,2);
743
+        $group->legend->setPosition(null, 0.1);
744
+        $group->legend->setBackgroundColor($colorsemitrans);
745
+
746
+        if (is_array($this->bgcolorgrid)) $group->grid->setBackgroundColor($bgcolorgrid);
747
+        else $group->grid->setBackgroundColor($colortrans);
748
+
749
+        if ($this->hideXGrid)	$group->grid->hideVertical(true);
750
+        if ($this->hideYGrid)	$group->grid->hideHorizontal(true);
751
+
752
+        // On boucle sur chaque lot de donnees
753
+        $legends=array();
754
+        $i=0;
755
+        $nblot=count($this->data[0])-1;
756
+
757
+        while ($i < $nblot)
758
+        {
759
+            $x=0;
760
+            $values=array();
761
+            foreach($this->data as $key => $valarray)
762
+            {
763
+                $legends[$x] = $valarray[0];
764
+                $values[$x]  = $valarray[$i+1];
765
+                $x++;
766
+            }
767
+
768
+            // We fix unknown values to null
769
+            $newvalues=array();
770
+            foreach($values as $val)
771
+            {
772
+                $newvalues[]=(is_numeric($val) ? $val : null);
773
+            }
774
+
775
+
776
+            if ($this->type[0] == 'bars')
777
+            {
778
+                //print "Lot de donnees $i<br>";
779
+                //print_r($values);
780
+                //print '<br>';
781
+
782
+                $color=new Color($this->datacolor[$i][0],$this->datacolor[$i][1],$this->datacolor[$i][2],20);
783
+                $colorbis=new Color(min($this->datacolor[$i][0]+50,255),min($this->datacolor[$i][1]+50,255),min($this->datacolor[$i][2]+50,255),50);
784
+
785
+                $colorgrey=new Color(100,100,100);
786
+                $colorborder=new Color($this->datacolor[$i][0],$this->datacolor[$i][1],$this->datacolor[$i][2]);
787
+
788
+                if ($this->mode == 'side')  $plot = new BarPlot($newvalues, $i+1, $nblot);
789
+                if ($this->mode == 'depth') $plot = new BarPlot($newvalues, 1, 1, ($nblot-$i-1)*5);
790
+
791
+                $plot->barBorder->setColor($colorgrey);
792
+                //$plot->setBarColor($color);
793
+                $plot->setBarGradient(new LinearGradient($colorbis, $color, 90));
794
+
795
+                if ($this->mode == 'side')  $plot->setBarPadding(0.1, 0.1);
796
+                if ($this->mode == 'depth') $plot->setBarPadding(0.1, 0.4);
797
+                if ($this->mode == 'side')  $plot->setBarSpace(5);
798
+                if ($this->mode == 'depth') $plot->setBarSpace(2);
799
+
800
+                $plot->barShadow->setSize($this->SetShading);
801
+                $plot->barShadow->setPosition(SHADOW_RIGHT_TOP);
802
+                $plot->barShadow->setColor(new Color(160, 160, 160, 50));
803
+                $plot->barShadow->smooth(true);
804
+                //$plot->setSize(1, 0.96);
805
+                //$plot->setCenter(0.5, 0.52);
806
+
807
+                // Le mode automatique est plus efficace
808
+                $plot->SetYMax($this->MaxValue);
809
+                $plot->SetYMin($this->MinValue);
810
+            }
811
+
812
+            if ($this->type[0] == 'lines' || $this->type[0] == 'linesnopoint')
813
+            {
814
+                $color=new Color($this->datacolor[$i][0],$this->datacolor[$i][1],$this->datacolor[$i][2],20);
815
+                $colorbis=new Color(min($this->datacolor[$i][0]+20,255),min($this->datacolor[$i][1]+20,255),min($this->datacolor[$i][2]+20,255),60);
816
+                $colorter=new Color(min($this->datacolor[$i][0]+50,255),min($this->datacolor[$i][1]+50,255),min($this->datacolor[$i][2]+50,255),90);
817
+
818
+                $plot = new LinePlot($newvalues);
819
+                //$plot->setSize(1, 0.96);
820
+                //$plot->setCenter(0.5, 0.52);
821
+
822
+                $plot->setColor($color);
823
+                $plot->setThickness(1);
824
+
825
+                // Set line background gradient
826
+                $plot->setFillGradient(new LinearGradient($colorter, $colorbis, 90));
827
+
828
+                $plot->xAxis->setLabelText($legends);
829
+
830
+                // Le mode automatique est plus efficace
831
+                $plot->SetYMax($this->MaxValue);
832
+                $plot->SetYMin($this->MinValue);
833
+                //$plot->setYAxis(0);
834
+                //$plot->hideLine(true);
835
+            }
836
+
837
+            //$plot->reduce(80);		// Evite temps d'affichage trop long et nombre de ticks absisce satures
838
+
839
+            $group->legend->setTextFont(new $artichow_defaultfont(10)); // This is to force Artichow to use awFileFontDriver to
840
+            // solve a bug in Artichow with UTF8
841
+            if (count($this->Legend))
842
+            {
843
+                if ($this->type[0] == 'bars')  										$group->legend->add($plot, $this->Legend[$i], LEGEND_BACKGROUND);
844
+                if ($this->type[0] == 'lines' || $this->type[0] == 'linesnopoint')	$group->legend->add($plot, $this->Legend[$i], LEGEND_LINE);
845
+            }
846
+            $group->add($plot);
774 847
 
848
+            $i++;
849
+        }
850
+
851
+        $group->axis->bottom->setLabelText($legends);
852
+        $group->axis->bottom->label->setFont(new $artichow_defaultfont(7));
853
+
854
+        //print $group->axis->bottom->getLabelNumber();
855
+        if ($this->labelInterval > 0) $group->axis->bottom->setLabelInterval($this->labelInterval);
775 856
 
776
-			if ($this->type[0] == 'bars')
777
-			{
778
-				//print "Lot de donnees $i<br>";
779
-				//print_r($values);
780
-				//print '<br>';
781
-
782
-				$color=new Color($this->datacolor[$i][0],$this->datacolor[$i][1],$this->datacolor[$i][2],20);
783
-				$colorbis=new Color(min($this->datacolor[$i][0]+50,255),min($this->datacolor[$i][1]+50,255),min($this->datacolor[$i][2]+50,255),50);
784
-
785
-				$colorgrey=new Color(100,100,100);
786
-				$colorborder=new Color($this->datacolor[$i][0],$this->datacolor[$i][1],$this->datacolor[$i][2]);
787
-
788
-				if ($this->mode == 'side')  $plot = new BarPlot($newvalues, $i+1, $nblot);
789
-				if ($this->mode == 'depth') $plot = new BarPlot($newvalues, 1, 1, ($nblot-$i-1)*5);
790
-
791
-				$plot->barBorder->setColor($colorgrey);
792
-				//$plot->setBarColor($color);
793
-				$plot->setBarGradient(new LinearGradient($colorbis, $color, 90));
794
-
795
-				if ($this->mode == 'side')  $plot->setBarPadding(0.1, 0.1);
796
-				if ($this->mode == 'depth') $plot->setBarPadding(0.1, 0.4);
797
-				if ($this->mode == 'side')  $plot->setBarSpace(5);
798
-				if ($this->mode == 'depth') $plot->setBarSpace(2);
799
-
800
-				$plot->barShadow->setSize($this->SetShading);
801
-				$plot->barShadow->setPosition(SHADOW_RIGHT_TOP);
802
-				$plot->barShadow->setColor(new Color(160, 160, 160, 50));
803
-				$plot->barShadow->smooth(true);
804
-				//$plot->setSize(1, 0.96);
805
-				//$plot->setCenter(0.5, 0.52);
806
-
807
-				// Le mode automatique est plus efficace
808
-				$plot->SetYMax($this->MaxValue);
809
-				$plot->SetYMin($this->MinValue);
810
-			}
857
+        $graph->add($group);
858
+
859
+        // Generate file
860
+        $graph->draw($file);
811 861
 
812
-			if ($this->type[0] == 'lines' || $this->type[0] == 'linesnopoint')
813
-			{
814
-				$color=new Color($this->datacolor[$i][0],$this->datacolor[$i][1],$this->datacolor[$i][2],20);
815
-				$colorbis=new Color(min($this->datacolor[$i][0]+20,255),min($this->datacolor[$i][1]+20,255),min($this->datacolor[$i][2]+20,255),60);
816
-				$colorter=new Color(min($this->datacolor[$i][0]+50,255),min($this->datacolor[$i][1]+50,255),min($this->datacolor[$i][2]+50,255),90);
817
-
818
-				$plot = new LinePlot($newvalues);
819
-				//$plot->setSize(1, 0.96);
820
-				//$plot->setCenter(0.5, 0.52);
821
-
822
-				$plot->setColor($color);
823
-				$plot->setThickness(1);
824
-
825
-				// Set line background gradient
826
-				$plot->setFillGradient(new LinearGradient($colorter, $colorbis, 90));
827
-
828
-				$plot->xAxis->setLabelText($legends);
829
-
830
-				// Le mode automatique est plus efficace
831
-				$plot->SetYMax($this->MaxValue);
832
-				$plot->SetYMin($this->MinValue);
833
-				//$plot->setYAxis(0);
834
-				//$plot->hideLine(true);
835
-			}
836
-
837
-			//$plot->reduce(80);		// Evite temps d'affichage trop long et nombre de ticks absisce satures
838
-
839
-			$group->legend->setTextFont(new $artichow_defaultfont(10)); // This is to force Artichow to use awFileFontDriver to
840
-			// solve a bug in Artichow with UTF8
841
-			if (count($this->Legend))
842
-			{
843
-				if ($this->type[0] == 'bars')  										$group->legend->add($plot, $this->Legend[$i], LEGEND_BACKGROUND);
844
-				if ($this->type[0] == 'lines' || $this->type[0] == 'linesnopoint')	$group->legend->add($plot, $this->Legend[$i], LEGEND_LINE);
845
-			}
846
-			$group->add($plot);
847
-
848
-			$i++;
849
-		}
850
-
851
-		$group->axis->bottom->setLabelText($legends);
852
-		$group->axis->bottom->label->setFont(new $artichow_defaultfont(7));
853
-
854
-		//print $group->axis->bottom->getLabelNumber();
855
-		if ($this->labelInterval > 0) $group->axis->bottom->setLabelInterval($this->labelInterval);
856
-
857
-		$graph->add($group);
858
-
859
-		// Generate file
860
-		$graph->draw($file);
861
-
862
-		$this->stringtoshow='<!-- Build using '.$this->_library.' --><img src="'.$fileurl.'" title="'.dol_escape_htmltag($this->title?$this->title:$this->YLabel).'" alt="'.dol_escape_htmltag($this->title?$this->title:$this->YLabel).'">';
863
-	}
862
+        $this->stringtoshow='<!-- Build using '.$this->_library.' --><img src="'.$fileurl.'" title="'.dol_escape_htmltag($this->title?$this->title:$this->YLabel).'" alt="'.dol_escape_htmltag($this->title?$this->title:$this->YLabel).'">';
863
+    }
864 864
 
865 865
 
866 866
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
867
-	/**
868
-	 * Build a graph using JFlot library. Input when calling this method should be:
869
-	 *	$this->data  = array(array(0=>'labelxA',1=>yA),  array('labelxB',yB));
870
-	 *	$this->data  = array(array(0=>'labelxA',1=>yA1,...,n=>yAn), array('labelxB',yB1,...yBn));   // or when there is n series to show for each x
871
-	 *  $this->data  = array(array('label'=>'labelxA','data'=>yA),  array('labelxB',yB));			// Syntax deprecated
872
-	 *  $this->legend= array("Val1",...,"Valn");													// list of n series name
873
-	 *  $this->type  = array('bars',...'lines'); or array('pie')
874
-	 *  $this->mode = 'depth' ???
875
-	 *  $this->bgcolorgrid
876
-	 *  $this->datacolor
877
-	 *  $this->shownodatagraph
878
-	 *
879
-	 * @param	string	$file    	Image file name to use to save onto disk (also used as javascript unique id)
880
-	 * @param	string	$fileurl	Url path to show image if saved onto disk. Never used here.
881
-	 * @return	void
882
-	 */
883
-	private function draw_jflot($file, $fileurl)
884
-	{
867
+    /**
868
+     * Build a graph using JFlot library. Input when calling this method should be:
869
+     *	$this->data  = array(array(0=>'labelxA',1=>yA),  array('labelxB',yB));
870
+     *	$this->data  = array(array(0=>'labelxA',1=>yA1,...,n=>yAn), array('labelxB',yB1,...yBn));   // or when there is n series to show for each x
871
+     *  $this->data  = array(array('label'=>'labelxA','data'=>yA),  array('labelxB',yB));			// Syntax deprecated
872
+     *  $this->legend= array("Val1",...,"Valn");													// list of n series name
873
+     *  $this->type  = array('bars',...'lines'); or array('pie')
874
+     *  $this->mode = 'depth' ???
875
+     *  $this->bgcolorgrid
876
+     *  $this->datacolor
877
+     *  $this->shownodatagraph
878
+     *
879
+     * @param	string	$file    	Image file name to use to save onto disk (also used as javascript unique id)
880
+     * @param	string	$fileurl	Url path to show image if saved onto disk. Never used here.
881
+     * @return	void
882
+     */
883
+    private function draw_jflot($file, $fileurl)
884
+    {
885 885
         // phpcs:enable
886
-		global $artichow_defaultfont;
887
-
888
-		dol_syslog(get_class($this)."::draw_jflot this->type=".join(',',$this->type)." this->MaxValue=".$this->MaxValue);
889
-
890
-		if (empty($this->width) && empty($this->height))
891
-		{
892
-			print 'Error width or height not set';
893
-			return;
894
-		}
895
-
896
-		$legends=array();
897
-		$nblot=count($this->data[0])-1;    // -1 to remove legend
898
-		if ($nblot < 0) dol_syslog('Bad value for property ->data. Must be set by mydolgraph->SetData before calling mydolgrapgh->draw', LOG_WARNING);
899
-		$firstlot=0;
900
-		// Works with line but not with bars
901
-		//if ($nblot > 2) $firstlot = ($nblot - 2);        // We limit nblot to 2 because jflot can't manage more than 2 bars on same x
902
-
903
-		$i=$firstlot;
904
-		$serie=array();
905
-		while ($i < $nblot)	// Loop on each serie
906
-		{
907
-			$values=array();	// Array with horizontal y values (specific values of a serie) for each abscisse x
908
-			$serie[$i]="var d".$i." = [];\n";
909
-
910
-			// Fill array $values
911
-			$x=0;
912
-			foreach($this->data as $valarray)	// Loop on each x
913
-			{
914
-				$legends[$x] = $valarray[0];
915
-				$values[$x]  = (is_numeric($valarray[$i+1]) ? $valarray[$i+1] : null);
916
-				$x++;
917
-			}
918
-
919
-			// TODO Avoid push by adding generated long array...
920
-			if (isset($this->type[$firstlot]) && $this->type[$firstlot] == 'pie')
921
-			{
922
-				foreach($values as $x => $y) {
923
-					if (isset($y)) $serie[$i].='d'.$i.'.push({"label":"'.dol_escape_js($legends[$x]).'", "data":'.$y.'});'."\n";
924
-				}
925
-			}
926
-			else
927
-			{
928
-				foreach($values as $x => $y) {
929
-					if (isset($y)) $serie[$i].='d'.$i.'.push(['.$x.', '.$y.']);'."\n";
930
-				}
931
-			}
932
-
933
-			unset($values);
934
-			$i++;
935
-		}
936
-		$tag=dol_escape_htmltag(dol_string_unaccent(dol_string_nospecial(basename($file),'_',array('-','.'))));
937
-
938
-		$this->stringtoshow ='<!-- Build using '.$this->_library.' -->'."\n";
939
-		if (! empty($this->title)) $this->stringtoshow.='<div align="center" class="dolgraphtitle'.(empty($this->cssprefix)?'':' dolgraphtitle'.$this->cssprefix).'">'.$this->title.'</div>';
940
-		if (! empty($this->shownographyet))
941
-		{
942
-		  $this->stringtoshow.='<div style="width:'.$this->width.'px;height:'.$this->height.'px;" class="nographyet"></div>';
943
-		  $this->stringtoshow.='<div class="nographyettext">'.$langs->trans("NotEnoughDataYet").'</div>';
944
-		  return;
945
-		}
946
-		$this->stringtoshow.='<div id="placeholder_'.$tag.'" style="width:'.$this->width.'px;height:'.$this->height.'px;" class="dolgraph'.(empty($this->cssprefix)?'':' dolgraph'.$this->cssprefix).'"></div>'."\n";
947
-
948
-		$this->stringtoshow.='<script id="'.$tag.'">'."\n";
949
-		$this->stringtoshow.='$(function () {'."\n";
950
-		$i=$firstlot;
951
-		if ($nblot < 0)
952
-		{
953
-			$this->stringtoshow.='<!-- No series of data -->';
954
-		}
955
-		else
956
-		{
957
-			while ($i < $nblot)
958
-			{
959
-				$this->stringtoshow.=$serie[$i];
960
-				$i++;
961
-			}
962
-		}
963
-		$this->stringtoshow.="\n";
964
-
965
-		// Special case for Graph of type 'pie'
966
-		if (isset($this->type[$firstlot]) && $this->type[$firstlot] == 'pie')
967
-		{
968
-			$datacolor=array();
969
-			foreach($this->datacolor as $val) $datacolor[]="#".sprintf("%02x%02x%02x",$val[0],$val[1],$val[2]);
970
-
971
-			$urltemp='';	// TODO Add support for url link into labels
972
-			$showlegend=$this->showlegend;
973
-			$showpointvalue=$this->showpointvalue;
974
-			$showpercent=$this->showpercent;
975
-
976
-			$this->stringtoshow.= '
886
+        global $artichow_defaultfont;
887
+
888
+        dol_syslog(get_class($this)."::draw_jflot this->type=".join(',',$this->type)." this->MaxValue=".$this->MaxValue);
889
+
890
+        if (empty($this->width) && empty($this->height))
891
+        {
892
+            print 'Error width or height not set';
893
+            return;
894
+        }
895
+
896
+        $legends=array();
897
+        $nblot=count($this->data[0])-1;    // -1 to remove legend
898
+        if ($nblot < 0) dol_syslog('Bad value for property ->data. Must be set by mydolgraph->SetData before calling mydolgrapgh->draw', LOG_WARNING);
899
+        $firstlot=0;
900
+        // Works with line but not with bars
901
+        //if ($nblot > 2) $firstlot = ($nblot - 2);        // We limit nblot to 2 because jflot can't manage more than 2 bars on same x
902
+
903
+        $i=$firstlot;
904
+        $serie=array();
905
+        while ($i < $nblot)	// Loop on each serie
906
+        {
907
+            $values=array();	// Array with horizontal y values (specific values of a serie) for each abscisse x
908
+            $serie[$i]="var d".$i." = [];\n";
909
+
910
+            // Fill array $values
911
+            $x=0;
912
+            foreach($this->data as $valarray)	// Loop on each x
913
+            {
914
+                $legends[$x] = $valarray[0];
915
+                $values[$x]  = (is_numeric($valarray[$i+1]) ? $valarray[$i+1] : null);
916
+                $x++;
917
+            }
918
+
919
+            // TODO Avoid push by adding generated long array...
920
+            if (isset($this->type[$firstlot]) && $this->type[$firstlot] == 'pie')
921
+            {
922
+                foreach($values as $x => $y) {
923
+                    if (isset($y)) $serie[$i].='d'.$i.'.push({"label":"'.dol_escape_js($legends[$x]).'", "data":'.$y.'});'."\n";
924
+                }
925
+            }
926
+            else
927
+            {
928
+                foreach($values as $x => $y) {
929
+                    if (isset($y)) $serie[$i].='d'.$i.'.push(['.$x.', '.$y.']);'."\n";
930
+                }
931
+            }
932
+
933
+            unset($values);
934
+            $i++;
935
+        }
936
+        $tag=dol_escape_htmltag(dol_string_unaccent(dol_string_nospecial(basename($file),'_',array('-','.'))));
937
+
938
+        $this->stringtoshow ='<!-- Build using '.$this->_library.' -->'."\n";
939
+        if (! empty($this->title)) $this->stringtoshow.='<div align="center" class="dolgraphtitle'.(empty($this->cssprefix)?'':' dolgraphtitle'.$this->cssprefix).'">'.$this->title.'</div>';
940
+        if (! empty($this->shownographyet))
941
+        {
942
+            $this->stringtoshow.='<div style="width:'.$this->width.'px;height:'.$this->height.'px;" class="nographyet"></div>';
943
+            $this->stringtoshow.='<div class="nographyettext">'.$langs->trans("NotEnoughDataYet").'</div>';
944
+            return;
945
+        }
946
+        $this->stringtoshow.='<div id="placeholder_'.$tag.'" style="width:'.$this->width.'px;height:'.$this->height.'px;" class="dolgraph'.(empty($this->cssprefix)?'':' dolgraph'.$this->cssprefix).'"></div>'."\n";
947
+
948
+        $this->stringtoshow.='<script id="'.$tag.'">'."\n";
949
+        $this->stringtoshow.='$(function () {'."\n";
950
+        $i=$firstlot;
951
+        if ($nblot < 0)
952
+        {
953
+            $this->stringtoshow.='<!-- No series of data -->';
954
+        }
955
+        else
956
+        {
957
+            while ($i < $nblot)
958
+            {
959
+                $this->stringtoshow.=$serie[$i];
960
+                $i++;
961
+            }
962
+        }
963
+        $this->stringtoshow.="\n";
964
+
965
+        // Special case for Graph of type 'pie'
966
+        if (isset($this->type[$firstlot]) && $this->type[$firstlot] == 'pie')
967
+        {
968
+            $datacolor=array();
969
+            foreach($this->datacolor as $val) $datacolor[]="#".sprintf("%02x%02x%02x",$val[0],$val[1],$val[2]);
970
+
971
+            $urltemp='';	// TODO Add support for url link into labels
972
+            $showlegend=$this->showlegend;
973
+            $showpointvalue=$this->showpointvalue;
974
+            $showpercent=$this->showpercent;
975
+
976
+            $this->stringtoshow.= '
977 977
 			function plotWithOptions_'.$tag.'() {
978 978
 			$.plot($("#placeholder_'.$tag.'"), d0,
979 979
 			{
@@ -992,15 +992,15 @@  discard block
 block discarded – undo
992 992
 								var percent=Math.round(series.percent);
993 993
 								var number=series.data[0][1];
994 994
 								return \'';
995
-								$this->stringtoshow.='<span style="font-size:8pt;text-align:center;padding:2px;color:black;">';
996
-								if ($urltemp) $this->stringtoshow.='<a style="color: #FFFFFF;" border="0" href="'.$urltemp.'">';
997
-								$this->stringtoshow.='\'+';
998
-								$this->stringtoshow.=($showlegend?'':'label+\' \'+');	// Hide label if already shown in legend
999
-								$this->stringtoshow.=($showpointvalue?'number+':'');
1000
-								$this->stringtoshow.=($showpercent?'\'<br/>\'+percent+\'%\'+':'');
1001
-								$this->stringtoshow.='\'';
1002
-								if ($urltemp) $this->stringtoshow.='</a>';
1003
-								$this->stringtoshow.='</span>\';
995
+                                $this->stringtoshow.='<span style="font-size:8pt;text-align:center;padding:2px;color:black;">';
996
+                                if ($urltemp) $this->stringtoshow.='<a style="color: #FFFFFF;" border="0" href="'.$urltemp.'">';
997
+                                $this->stringtoshow.='\'+';
998
+                                $this->stringtoshow.=($showlegend?'':'label+\' \'+');	// Hide label if already shown in legend
999
+                                $this->stringtoshow.=($showpointvalue?'number+':'');
1000
+                                $this->stringtoshow.=($showpercent?'\'<br/>\'+percent+\'%\'+':'');
1001
+                                $this->stringtoshow.='\'';
1002
+                                if ($urltemp) $this->stringtoshow.='</a>';
1003
+                                $this->stringtoshow.='</span>\';
1004 1004
 							},
1005 1005
 							background: {
1006 1006
 							opacity: 0.0,
@@ -1015,20 +1015,20 @@  discard block
 block discarded – undo
1015 1015
 			pan: {
1016 1016
 				interactive: true
1017 1017
 			},';
1018
-			if (count($datacolor))
1019
-			{
1020
-				$this->stringtoshow.='colors: '.(! empty($data['seriescolor']) ? json_encode($data['seriescolor']) : json_encode($datacolor)).',';
1021
-			}
1022
-			$this->stringtoshow.='legend: {show: '.($showlegend?'true':'false').', position: \'ne\' }
1018
+            if (count($datacolor))
1019
+            {
1020
+                $this->stringtoshow.='colors: '.(! empty($data['seriescolor']) ? json_encode($data['seriescolor']) : json_encode($datacolor)).',';
1021
+            }
1022
+            $this->stringtoshow.='legend: {show: '.($showlegend?'true':'false').', position: \'ne\' }
1023 1023
 		});
1024 1024
 		}'."\n";
1025
-		}
1026
-		// Other cases, graph of type 'bars', 'lines'
1027
-		else
1028
-		{
1029
-			// Add code to support tooltips
1030
-		    // TODO: remove js css and use graph-tooltip-inner class instead by adding css in each themes
1031
-			$this->stringtoshow.='
1025
+        }
1026
+        // Other cases, graph of type 'bars', 'lines'
1027
+        else
1028
+        {
1029
+            // Add code to support tooltips
1030
+            // TODO: remove js css and use graph-tooltip-inner class instead by adding css in each themes
1031
+            $this->stringtoshow.='
1032 1032
 			function showTooltip_'.$tag.'(x, y, contents) {
1033 1033
 				$(\'<div class="graph-tooltip-inner" id="tooltip_'.$tag.'">\' + contents + \'</div>\').css({
1034 1034
 					position: \'absolute\',
@@ -1060,10 +1060,10 @@  discard block
 block discarded – undo
1060 1060
 						var y = item.datapoint[1].toFixed(2);
1061 1061
 						var z = item.series.xaxis.ticks[item.dataIndex].label;
1062 1062
 						';
1063
-						if ($this->showpointvalue > 0) $this->stringtoshow.='
1063
+                        if ($this->showpointvalue > 0) $this->stringtoshow.='
1064 1064
 							showTooltip_'.$tag.'(item.pageX, item.pageY, item.series.label + "<br>" + z + " => " + y);
1065 1065
 						';
1066
-						$this->stringtoshow.='
1066
+                        $this->stringtoshow.='
1067 1067
 					}
1068 1068
 				}
1069 1069
 				else {
@@ -1073,95 +1073,95 @@  discard block
 block discarded – undo
1073 1073
 			});
1074 1074
 			';
1075 1075
 
1076
-			$this->stringtoshow.='var stack = null, steps = false;'."\n";
1077
-
1078
-			$this->stringtoshow.='function plotWithOptions_'.$tag.'() {'."\n";
1079
-			$this->stringtoshow.='$.plot($("#placeholder_'.$tag.'"), [ '."\n";
1080
-			$i=$firstlot;
1081
-			while ($i < $nblot)
1082
-			{
1083
-				if ($i > $firstlot) $this->stringtoshow.=', '."\n";
1084
-				$color=sprintf("%02x%02x%02x",$this->datacolor[$i][0],$this->datacolor[$i][1],$this->datacolor[$i][2]);
1085
-				$this->stringtoshow.='{ ';
1086
-				if (! isset($this->type[$i]) || $this->type[$i] == 'bars') $this->stringtoshow.='bars: { lineWidth: 1, show: true, align: "'.($i==$firstlot?'center':'left').'", barWidth: 0.5 }, ';
1087
-				if (isset($this->type[$i]) && ($this->type[$i] == 'lines' || $this->type[$i] == 'linesnopoint')) $this->stringtoshow.='lines: { show: true, fill: false }, points: { show: '.($this->type[$i] == 'linesnopoint' ? 'false' : 'true').' }, ';
1088
-				$this->stringtoshow.='color: "#'.$color.'", label: "'.(isset($this->Legend[$i]) ? dol_escape_js($this->Legend[$i]) : '').'", data: d'.$i.' }';
1089
-				$i++;
1090
-			}
1091
-			// shadowSize: 0 -> Drawing is faster without shadows
1092
-			$this->stringtoshow.="\n".' ], { series: { shadowSize: 0, stack: stack, lines: { fill: false, steps: steps }, bars: { barWidth: 0.6 } }'."\n";
1093
-
1094
-			// Xaxis
1095
-			$this->stringtoshow.=', xaxis: { ticks: ['."\n";
1096
-			$x=0;
1097
-			foreach($this->data as $key => $valarray)
1098
-			{
1099
-				if ($x > 0) $this->stringtoshow.=', '."\n";
1100
-				$this->stringtoshow.= ' ['.$x.', "'.$valarray[0].'"]';
1101
-				$x++;
1102
-			}
1103
-			$this->stringtoshow.='] }'."\n";
1104
-
1105
-			// Yaxis
1106
-			$this->stringtoshow.=', yaxis: { min: '.$this->MinValue.', max: '.($this->MaxValue).' }'."\n";
1107
-
1108
-			// Background color
1109
-			$color1=sprintf("%02x%02x%02x",$this->bgcolorgrid[0],$this->bgcolorgrid[0],$this->bgcolorgrid[2]);
1110
-			$color2=sprintf("%02x%02x%02x",$this->bgcolorgrid[0],$this->bgcolorgrid[1],$this->bgcolorgrid[2]);
1111
-			$this->stringtoshow.=', grid: { hoverable: true, backgroundColor: { colors: ["#'.$color1.'", "#'.$color2.'"] }, borderWidth: 1, borderColor: \'#e6e6e6\', tickColor  : \'#e6e6e6\' }'."\n";
1112
-			//$this->stringtoshow.=', shadowSize: 20'."\n";    TODO Uncommet this
1113
-			$this->stringtoshow.='});'."\n";
1114
-			$this->stringtoshow.='}'."\n";
1115
-		}
1116
-
1117
-		$this->stringtoshow.='plotWithOptions_'.$tag.'();'."\n";
1118
-		$this->stringtoshow.='});'."\n";
1119
-		$this->stringtoshow.='</script>'."\n";
1120
-	}
1121
-
1122
-
1123
-
1124
-	/**
1125
-	 * Output HTML string to show graph
1126
-	 *
1127
-	 * @param	int			$shownographyet 	Show graph to say there is not enough data
1128
-	 * @return	string							HTML string to show graph
1129
-	 */
1130
-	function show($shownographyet=0)
1131
-	{
1132
-		global $langs;
1133
-
1134
-		if ($shownographyet)
1135
-		{
1136
-			$s= '<div class="nographyet" style="width:'.(preg_match('/%/',$this->width)?$this->width:$this->width.'px').'; height:'.(preg_match('/%/',$this->height)?$this->height:$this->height.'px').';"></div>';
1137
-			$s.='<div class="nographyettext">'.$langs->trans("NotEnoughDataYet").'</div>';
1138
-			return $s;
1139
-		}
1140
-
1141
-		return $this->stringtoshow;
1142
-	}
1143
-
1144
-
1145
-	/**
1146
-	 * getDefaultGraphSizeForStats
1147
-	 *
1148
-	 * @param	string	$direction		'width' or 'height'
1149
-	 * @param	string	$defaultsize	Value we want as default size
1150
-	 * @return	int						Value of width or height to use by default
1151
-	 */
1152
-	static function getDefaultGraphSizeForStats($direction,$defaultsize='')
1153
-	{
1154
-		global $conf;
1155
-
1156
-		if ($direction == 'width')
1157
-		{
1158
-			if (empty($conf->dol_optimize_smallscreen)) return ($defaultsize ? $defaultsize : '500');
1159
-			else return (empty($_SESSION['dol_screen_width']) ? '280' : ($_SESSION['dol_screen_width']-40));
1160
-		}
1161
-		if ($direction == 'height')
1162
-		{
1163
-			return (empty($conf->dol_optimize_smallscreen)?($defaultsize?$defaultsize:'200'):'160');
1164
-		}
1165
-		return 0;
1166
-	}
1076
+            $this->stringtoshow.='var stack = null, steps = false;'."\n";
1077
+
1078
+            $this->stringtoshow.='function plotWithOptions_'.$tag.'() {'."\n";
1079
+            $this->stringtoshow.='$.plot($("#placeholder_'.$tag.'"), [ '."\n";
1080
+            $i=$firstlot;
1081
+            while ($i < $nblot)
1082
+            {
1083
+                if ($i > $firstlot) $this->stringtoshow.=', '."\n";
1084
+                $color=sprintf("%02x%02x%02x",$this->datacolor[$i][0],$this->datacolor[$i][1],$this->datacolor[$i][2]);
1085
+                $this->stringtoshow.='{ ';
1086
+                if (! isset($this->type[$i]) || $this->type[$i] == 'bars') $this->stringtoshow.='bars: { lineWidth: 1, show: true, align: "'.($i==$firstlot?'center':'left').'", barWidth: 0.5 }, ';
1087
+                if (isset($this->type[$i]) && ($this->type[$i] == 'lines' || $this->type[$i] == 'linesnopoint')) $this->stringtoshow.='lines: { show: true, fill: false }, points: { show: '.($this->type[$i] == 'linesnopoint' ? 'false' : 'true').' }, ';
1088
+                $this->stringtoshow.='color: "#'.$color.'", label: "'.(isset($this->Legend[$i]) ? dol_escape_js($this->Legend[$i]) : '').'", data: d'.$i.' }';
1089
+                $i++;
1090
+            }
1091
+            // shadowSize: 0 -> Drawing is faster without shadows
1092
+            $this->stringtoshow.="\n".' ], { series: { shadowSize: 0, stack: stack, lines: { fill: false, steps: steps }, bars: { barWidth: 0.6 } }'."\n";
1093
+
1094
+            // Xaxis
1095
+            $this->stringtoshow.=', xaxis: { ticks: ['."\n";
1096
+            $x=0;
1097
+            foreach($this->data as $key => $valarray)
1098
+            {
1099
+                if ($x > 0) $this->stringtoshow.=', '."\n";
1100
+                $this->stringtoshow.= ' ['.$x.', "'.$valarray[0].'"]';
1101
+                $x++;
1102
+            }
1103
+            $this->stringtoshow.='] }'."\n";
1104
+
1105
+            // Yaxis
1106
+            $this->stringtoshow.=', yaxis: { min: '.$this->MinValue.', max: '.($this->MaxValue).' }'."\n";
1107
+
1108
+            // Background color
1109
+            $color1=sprintf("%02x%02x%02x",$this->bgcolorgrid[0],$this->bgcolorgrid[0],$this->bgcolorgrid[2]);
1110
+            $color2=sprintf("%02x%02x%02x",$this->bgcolorgrid[0],$this->bgcolorgrid[1],$this->bgcolorgrid[2]);
1111
+            $this->stringtoshow.=', grid: { hoverable: true, backgroundColor: { colors: ["#'.$color1.'", "#'.$color2.'"] }, borderWidth: 1, borderColor: \'#e6e6e6\', tickColor  : \'#e6e6e6\' }'."\n";
1112
+            //$this->stringtoshow.=', shadowSize: 20'."\n";    TODO Uncommet this
1113
+            $this->stringtoshow.='});'."\n";
1114
+            $this->stringtoshow.='}'."\n";
1115
+        }
1116
+
1117
+        $this->stringtoshow.='plotWithOptions_'.$tag.'();'."\n";
1118
+        $this->stringtoshow.='});'."\n";
1119
+        $this->stringtoshow.='</script>'."\n";
1120
+    }
1121
+
1122
+
1123
+
1124
+    /**
1125
+     * Output HTML string to show graph
1126
+     *
1127
+     * @param	int			$shownographyet 	Show graph to say there is not enough data
1128
+     * @return	string							HTML string to show graph
1129
+     */
1130
+    function show($shownographyet=0)
1131
+    {
1132
+        global $langs;
1133
+
1134
+        if ($shownographyet)
1135
+        {
1136
+            $s= '<div class="nographyet" style="width:'.(preg_match('/%/',$this->width)?$this->width:$this->width.'px').'; height:'.(preg_match('/%/',$this->height)?$this->height:$this->height.'px').';"></div>';
1137
+            $s.='<div class="nographyettext">'.$langs->trans("NotEnoughDataYet").'</div>';
1138
+            return $s;
1139
+        }
1140
+
1141
+        return $this->stringtoshow;
1142
+    }
1143
+
1144
+
1145
+    /**
1146
+     * getDefaultGraphSizeForStats
1147
+     *
1148
+     * @param	string	$direction		'width' or 'height'
1149
+     * @param	string	$defaultsize	Value we want as default size
1150
+     * @return	int						Value of width or height to use by default
1151
+     */
1152
+    static function getDefaultGraphSizeForStats($direction,$defaultsize='')
1153
+    {
1154
+        global $conf;
1155
+
1156
+        if ($direction == 'width')
1157
+        {
1158
+            if (empty($conf->dol_optimize_smallscreen)) return ($defaultsize ? $defaultsize : '500');
1159
+            else return (empty($_SESSION['dol_screen_width']) ? '280' : ($_SESSION['dol_screen_width']-40));
1160
+        }
1161
+        if ($direction == 'height')
1162
+        {
1163
+            return (empty($conf->dol_optimize_smallscreen)?($defaultsize?$defaultsize:'200'):'160');
1164
+        }
1165
+        return 0;
1166
+    }
1167 1167
 }
Please login to merge, or discard this patch.
dolibarr/htdocs/core/class/extrafields.class.php 1 patch
Indentation   +1967 added lines, -1967 removed lines patch added patch discarded remove patch
@@ -37,2020 +37,2020 @@
 block discarded – undo
37 37
  */
38 38
 class ExtraFields
39 39
 {
40
-	/**
40
+    /**
41 41
      * @var DoliDB Database handler.
42 42
      */
43 43
     public $db;
44 44
 
45
-	// type of element (for what object is the extrafield)
46
-	// @deprecated
47
-	var $attribute_elementtype;
48
-	// Array with type of the extra field
49
-	// @deprecated
50
-	var $attribute_type;
51
-	// Array with label of extra field
52
-	// @deprecated
53
-	var $attribute_label;
54
-	// Array with size of extra field
55
-	// @deprecated
56
-	var $attribute_size;
57
-	// array with list of possible values for some types of extra fields
58
-	// @deprecated
59
-	var $attribute_choice;
60
-	// Array to store compute formula for computed fields
61
-	// @deprecated
62
-	var $attribute_computed;
63
-	// Array to store default value
64
-	// @deprecated
65
-	var $attribute_default;
66
-	// Array to store if attribute is unique or not
67
-	// @deprecated
68
-	var $attribute_unique;
69
-	// Array to store if attribute is required or not
70
-	// @deprecated
71
-	var $attribute_required;
72
-	// Array to store parameters of attribute (used in select type)
73
-	// @deprecated
74
-	var $attribute_param;
75
-	// Array to store position of attribute
76
-	// @deprecated
77
-	var $attribute_pos;
78
-	// Array to store if attribute is editable regardless of the document status
79
-	// @deprecated
80
-	var $attribute_alwayseditable;
81
-	// Array to store permission to check
82
-	// @deprecated
83
-	var $attribute_perms;
84
-	// Array to store language file to translate label of values
85
-	// @deprecated
86
-	var $attribute_langfile;
87
-	// Array to store if field is visible by default on list
88
-	// @deprecated
89
-	var $attribute_list;
90
-
91
-	// New array to store extrafields definition
92
-	var $attributes;
93
-
94
-	/**
95
-	 * @var string Error code (or message)
96
-	 */
97
-	public $error='';
98
-
99
-	var $errno;
100
-
101
-
102
-	public static $type2label=array(
103
-	'varchar'=>'String',
104
-	'text'=>'TextLong',
105
-	'html'=>'HtmlText',
106
-	'int'=>'Int',
107
-	'double'=>'Float',
108
-	'date'=>'Date',
109
-	'datetime'=>'DateAndTime',
110
-	'boolean'=>'Boolean',
111
-	'price'=>'ExtrafieldPrice',
112
-	'phone'=>'ExtrafieldPhone',
113
-	'mail'=>'ExtrafieldMail',
114
-	'url'=>'ExtrafieldUrl',
115
-	'password' => 'ExtrafieldPassword',
116
-	'select' => 'ExtrafieldSelect',
117
-	'sellist' => 'ExtrafieldSelectList',
118
-	'radio' => 'ExtrafieldRadio',
119
-	'checkbox' => 'ExtrafieldCheckBox',
120
-	'chkbxlst' => 'ExtrafieldCheckBoxFromList',
121
-	'link' => 'ExtrafieldLink',
122
-	'separate' => 'ExtrafieldSeparator',
123
-	);
124
-
125
-
126
-	/**
127
-	 *	Constructor
128
-	 *
129
-	 *  @param		DoliDB		$db      Database handler
130
-	*/
131
-	function __construct($db)
132
-	{
133
-		$this->db = $db;
134
-		$this->error = array();
135
-		$this->attributes = array();
136
-
137
-		// For old usage
138
-		$this->attribute_elementtype = array();
139
-		$this->attribute_type = array();
140
-		$this->attribute_label = array();
141
-		$this->attribute_size = array();
142
-		$this->attribute_computed = array();
143
-		$this->attribute_default = array();
144
-		$this->attribute_unique = array();
145
-		$this->attribute_required = array();
146
-		$this->attribute_perms = array();
147
-		$this->attribute_langfile = array();
148
-		$this->attribute_list = array();
149
-	}
150
-
151
-	/**
152
-	 *  Add a new extra field parameter
153
-	 *
154
-	 *  @param	string			$attrname           Code of attribute
155
-	 *  @param  string			$label              label of attribute
156
-	 *  @param  int				$type               Type of attribute ('boolean','int','varchar','text','html','date','datehour','price','phone','mail','password','url','select','checkbox','separate',...)
157
-	 *  @param  int				$pos                Position of attribute
158
-	 *  @param  string			$size               Size/length of attribute
159
-	 *  @param  string			$elementtype        Element type. Same value than object->table_element (Example 'member', 'product', 'thirdparty', ...)
160
-	 *  @param	int				$unique				Is field unique or not
161
-	 *  @param	int				$required			Is field required or not
162
-	 *  @param	string			$default_value		Defaulted value (In database. use the default_value feature for default value on screen. Example: '', '0', 'null', 'avalue')
163
-	 *  @param  array|string	$param				Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
164
-	 *  @param  int				$alwayseditable		Is attribute always editable regardless of the document status
165
-	 *  @param	string			$perms				Permission to check
166
-	 *  @param	string			$list				Visibilty ('0'=never visible, '1'=visible on list+forms, '2'=list only, '3'=form only or 'eval string')
167
-	 *  @param	string			$help				Text with help tooltip
168
-	 *  @param  string  		$computed           Computed value
169
-	 *  @param  string  		$entity    		 	Entity of extrafields (for multicompany modules)
170
-	 *  @param  string  		$langfile  		 	Language file
171
-	 *  @param  string  		$enabled  		 	Condition to have the field enabled or not
172
-	 *  @return int      							<=0 if KO, >0 if OK
173
-	 */
174
-	function addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique=0, $required=0, $default_value='', $param='', $alwayseditable=0, $perms='', $list='-1', $help='', $computed='', $entity='', $langfile='', $enabled='1')
175
-	{
176
-		if (empty($attrname)) return -1;
177
-		if (empty($label)) return -1;
178
-
179
-		if ($elementtype == 'thirdparty') $elementtype='societe';
180
-		if ($elementtype == 'contact') $elementtype='socpeople';
181
-
182
-		// Create field into database except for separator type which is not stored in database
183
-		if ($type != 'separate')
184
-		{
185
-			$result=$this->create($attrname, $type, $size, $elementtype, $unique, $required, $default_value, $param, $perms, $list, $computed, $help);
186
-		}
187
-		$err1=$this->errno;
188
-		if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate')
189
-		{
190
-			// Add declaration of field into table
191
-			$result2=$this->create_label($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled);
192
-			$err2=$this->errno;
193
-			if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS'))
194
-			{
195
-				$this->error='';
196
-				$this->errno=0;
197
-				return 1;
198
-			}
199
-			else return -2;
200
-		}
201
-		else
202
-		{
203
-			return -1;
204
-		}
205
-	}
206
-
207
-	/**
208
-	 *	Add a new optional attribute.
209
-	 *  This is a private method. For public method, use addExtraField.
210
-	 *
211
-	 *	@param	string	$attrname			code of attribute
212
-	 *  @param	int		$type				Type of attribute ('boolean', 'int', 'varchar', 'text', 'html', 'date', 'datehour','price','phone','mail','password','url','select','checkbox', ...)
213
-	 *  @param	string	$length				Size/length of attribute ('5', '24,8', ...)
214
-	 *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', 'contact', ...)
215
-	 *  @param	int		$unique				Is field unique or not
216
-	 *  @param	int		$required			Is field required or not
217
-	 *  @param  string  $default_value		Default value for field (in database)
218
-	 *  @param  array	$param				Params for field  (ex for select list : array('options'=>array('value'=>'label of option'))
219
-	 *  @param	string	$perms				Permission
220
-	 *	@param	string	$list				Into list view by default
221
-	 *  @param  string  $computed           Computed value
222
-	 *  @return int      	           		<=0 if KO, >0 if OK
223
-	 */
224
-	private function create($attrname, $type='varchar', $length=255, $elementtype='member', $unique=0, $required=0, $default_value='',$param='', $perms='', $list='0', $computed='')
225
-	{
226
-		if ($elementtype == 'thirdparty') $elementtype='societe';
227
-		if ($elementtype == 'contact') $elementtype='socpeople';
228
-
229
-		$table=$elementtype.'_extrafields';
230
-		if ($elementtype == 'categorie') $table='categories_extrafields';
231
-
232
-		if (! empty($attrname) && preg_match("/^\w[a-zA-Z0-9_]*$/",$attrname) && ! is_numeric($attrname))
233
-		{
234
-			if ($type=='boolean') {
235
-				$typedb='int';
236
-				$lengthdb='1';
237
-			} elseif($type=='price') {
238
-				$typedb='double';
239
-				$lengthdb='24,8';
240
-			} elseif($type=='phone') {
241
-				$typedb='varchar';
242
-				$lengthdb='20';
243
-			} elseif($type=='mail') {
244
-				$typedb='varchar';
245
-				$lengthdb='128';
246
-			} elseif($type=='url') {
247
-				$typedb='varchar';
248
-				$lengthdb='255';
249
-			} elseif (($type=='select') || ($type=='sellist') || ($type=='radio') ||($type=='checkbox') ||($type=='chkbxlst')){
250
-				$typedb='varchar';
251
-				$lengthdb='255';
252
-			} elseif ($type=='link') {
253
-				$typedb='int';
254
-				$lengthdb='11';
255
-			} elseif ($type=='html') {
256
-				$typedb='text';
257
-				$lengthdb=$length;
258
-			} elseif($type=='password') {
259
-				$typedb='varchar';
260
-				$lengthdb='128';
261
-			} else {
262
-				$typedb=$type;
263
-				$lengthdb=$length;
264
-				if ($type == 'varchar' && empty($lengthdb)) $lengthdb='255';
265
-			}
266
-			$field_desc = array(
267
-				'type'=>$typedb,
268
-				'value'=>$lengthdb,
269
-				'null'=>($required?'NOT NULL':'NULL'),
270
-				'default' => $default_value
271
-			);
272
-
273
-			$result=$this->db->DDLAddField(MAIN_DB_PREFIX.$table, $attrname, $field_desc);
274
-			if ($result > 0)
275
-			{
276
-				if ($unique)
277
-				{
278
-					$sql="ALTER TABLE ".MAIN_DB_PREFIX.$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
279
-					$resql=$this->db->query($sql,1,'dml');
280
-				}
281
-				return 1;
282
-			}
283
-			else
284
-			{
285
-				$this->error=$this->db->lasterror();
286
-				$this->errno=$this->db->lasterrno();
287
-				return -1;
288
-			}
289
-		}
290
-		else
291
-		{
292
-			return 0;
293
-		}
294
-	}
45
+    // type of element (for what object is the extrafield)
46
+    // @deprecated
47
+    var $attribute_elementtype;
48
+    // Array with type of the extra field
49
+    // @deprecated
50
+    var $attribute_type;
51
+    // Array with label of extra field
52
+    // @deprecated
53
+    var $attribute_label;
54
+    // Array with size of extra field
55
+    // @deprecated
56
+    var $attribute_size;
57
+    // array with list of possible values for some types of extra fields
58
+    // @deprecated
59
+    var $attribute_choice;
60
+    // Array to store compute formula for computed fields
61
+    // @deprecated
62
+    var $attribute_computed;
63
+    // Array to store default value
64
+    // @deprecated
65
+    var $attribute_default;
66
+    // Array to store if attribute is unique or not
67
+    // @deprecated
68
+    var $attribute_unique;
69
+    // Array to store if attribute is required or not
70
+    // @deprecated
71
+    var $attribute_required;
72
+    // Array to store parameters of attribute (used in select type)
73
+    // @deprecated
74
+    var $attribute_param;
75
+    // Array to store position of attribute
76
+    // @deprecated
77
+    var $attribute_pos;
78
+    // Array to store if attribute is editable regardless of the document status
79
+    // @deprecated
80
+    var $attribute_alwayseditable;
81
+    // Array to store permission to check
82
+    // @deprecated
83
+    var $attribute_perms;
84
+    // Array to store language file to translate label of values
85
+    // @deprecated
86
+    var $attribute_langfile;
87
+    // Array to store if field is visible by default on list
88
+    // @deprecated
89
+    var $attribute_list;
90
+
91
+    // New array to store extrafields definition
92
+    var $attributes;
93
+
94
+    /**
95
+     * @var string Error code (or message)
96
+     */
97
+    public $error='';
98
+
99
+    var $errno;
100
+
101
+
102
+    public static $type2label=array(
103
+    'varchar'=>'String',
104
+    'text'=>'TextLong',
105
+    'html'=>'HtmlText',
106
+    'int'=>'Int',
107
+    'double'=>'Float',
108
+    'date'=>'Date',
109
+    'datetime'=>'DateAndTime',
110
+    'boolean'=>'Boolean',
111
+    'price'=>'ExtrafieldPrice',
112
+    'phone'=>'ExtrafieldPhone',
113
+    'mail'=>'ExtrafieldMail',
114
+    'url'=>'ExtrafieldUrl',
115
+    'password' => 'ExtrafieldPassword',
116
+    'select' => 'ExtrafieldSelect',
117
+    'sellist' => 'ExtrafieldSelectList',
118
+    'radio' => 'ExtrafieldRadio',
119
+    'checkbox' => 'ExtrafieldCheckBox',
120
+    'chkbxlst' => 'ExtrafieldCheckBoxFromList',
121
+    'link' => 'ExtrafieldLink',
122
+    'separate' => 'ExtrafieldSeparator',
123
+    );
124
+
125
+
126
+    /**
127
+     *	Constructor
128
+     *
129
+     *  @param		DoliDB		$db      Database handler
130
+     */
131
+    function __construct($db)
132
+    {
133
+        $this->db = $db;
134
+        $this->error = array();
135
+        $this->attributes = array();
136
+
137
+        // For old usage
138
+        $this->attribute_elementtype = array();
139
+        $this->attribute_type = array();
140
+        $this->attribute_label = array();
141
+        $this->attribute_size = array();
142
+        $this->attribute_computed = array();
143
+        $this->attribute_default = array();
144
+        $this->attribute_unique = array();
145
+        $this->attribute_required = array();
146
+        $this->attribute_perms = array();
147
+        $this->attribute_langfile = array();
148
+        $this->attribute_list = array();
149
+    }
150
+
151
+    /**
152
+     *  Add a new extra field parameter
153
+     *
154
+     *  @param	string			$attrname           Code of attribute
155
+     *  @param  string			$label              label of attribute
156
+     *  @param  int				$type               Type of attribute ('boolean','int','varchar','text','html','date','datehour','price','phone','mail','password','url','select','checkbox','separate',...)
157
+     *  @param  int				$pos                Position of attribute
158
+     *  @param  string			$size               Size/length of attribute
159
+     *  @param  string			$elementtype        Element type. Same value than object->table_element (Example 'member', 'product', 'thirdparty', ...)
160
+     *  @param	int				$unique				Is field unique or not
161
+     *  @param	int				$required			Is field required or not
162
+     *  @param	string			$default_value		Defaulted value (In database. use the default_value feature for default value on screen. Example: '', '0', 'null', 'avalue')
163
+     *  @param  array|string	$param				Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
164
+     *  @param  int				$alwayseditable		Is attribute always editable regardless of the document status
165
+     *  @param	string			$perms				Permission to check
166
+     *  @param	string			$list				Visibilty ('0'=never visible, '1'=visible on list+forms, '2'=list only, '3'=form only or 'eval string')
167
+     *  @param	string			$help				Text with help tooltip
168
+     *  @param  string  		$computed           Computed value
169
+     *  @param  string  		$entity    		 	Entity of extrafields (for multicompany modules)
170
+     *  @param  string  		$langfile  		 	Language file
171
+     *  @param  string  		$enabled  		 	Condition to have the field enabled or not
172
+     *  @return int      							<=0 if KO, >0 if OK
173
+     */
174
+    function addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique=0, $required=0, $default_value='', $param='', $alwayseditable=0, $perms='', $list='-1', $help='', $computed='', $entity='', $langfile='', $enabled='1')
175
+    {
176
+        if (empty($attrname)) return -1;
177
+        if (empty($label)) return -1;
178
+
179
+        if ($elementtype == 'thirdparty') $elementtype='societe';
180
+        if ($elementtype == 'contact') $elementtype='socpeople';
181
+
182
+        // Create field into database except for separator type which is not stored in database
183
+        if ($type != 'separate')
184
+        {
185
+            $result=$this->create($attrname, $type, $size, $elementtype, $unique, $required, $default_value, $param, $perms, $list, $computed, $help);
186
+        }
187
+        $err1=$this->errno;
188
+        if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate')
189
+        {
190
+            // Add declaration of field into table
191
+            $result2=$this->create_label($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled);
192
+            $err2=$this->errno;
193
+            if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS'))
194
+            {
195
+                $this->error='';
196
+                $this->errno=0;
197
+                return 1;
198
+            }
199
+            else return -2;
200
+        }
201
+        else
202
+        {
203
+            return -1;
204
+        }
205
+    }
206
+
207
+    /**
208
+     *	Add a new optional attribute.
209
+     *  This is a private method. For public method, use addExtraField.
210
+     *
211
+     *	@param	string	$attrname			code of attribute
212
+     *  @param	int		$type				Type of attribute ('boolean', 'int', 'varchar', 'text', 'html', 'date', 'datehour','price','phone','mail','password','url','select','checkbox', ...)
213
+     *  @param	string	$length				Size/length of attribute ('5', '24,8', ...)
214
+     *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', 'contact', ...)
215
+     *  @param	int		$unique				Is field unique or not
216
+     *  @param	int		$required			Is field required or not
217
+     *  @param  string  $default_value		Default value for field (in database)
218
+     *  @param  array	$param				Params for field  (ex for select list : array('options'=>array('value'=>'label of option'))
219
+     *  @param	string	$perms				Permission
220
+     *	@param	string	$list				Into list view by default
221
+     *  @param  string  $computed           Computed value
222
+     *  @return int      	           		<=0 if KO, >0 if OK
223
+     */
224
+    private function create($attrname, $type='varchar', $length=255, $elementtype='member', $unique=0, $required=0, $default_value='',$param='', $perms='', $list='0', $computed='')
225
+    {
226
+        if ($elementtype == 'thirdparty') $elementtype='societe';
227
+        if ($elementtype == 'contact') $elementtype='socpeople';
228
+
229
+        $table=$elementtype.'_extrafields';
230
+        if ($elementtype == 'categorie') $table='categories_extrafields';
231
+
232
+        if (! empty($attrname) && preg_match("/^\w[a-zA-Z0-9_]*$/",$attrname) && ! is_numeric($attrname))
233
+        {
234
+            if ($type=='boolean') {
235
+                $typedb='int';
236
+                $lengthdb='1';
237
+            } elseif($type=='price') {
238
+                $typedb='double';
239
+                $lengthdb='24,8';
240
+            } elseif($type=='phone') {
241
+                $typedb='varchar';
242
+                $lengthdb='20';
243
+            } elseif($type=='mail') {
244
+                $typedb='varchar';
245
+                $lengthdb='128';
246
+            } elseif($type=='url') {
247
+                $typedb='varchar';
248
+                $lengthdb='255';
249
+            } elseif (($type=='select') || ($type=='sellist') || ($type=='radio') ||($type=='checkbox') ||($type=='chkbxlst')){
250
+                $typedb='varchar';
251
+                $lengthdb='255';
252
+            } elseif ($type=='link') {
253
+                $typedb='int';
254
+                $lengthdb='11';
255
+            } elseif ($type=='html') {
256
+                $typedb='text';
257
+                $lengthdb=$length;
258
+            } elseif($type=='password') {
259
+                $typedb='varchar';
260
+                $lengthdb='128';
261
+            } else {
262
+                $typedb=$type;
263
+                $lengthdb=$length;
264
+                if ($type == 'varchar' && empty($lengthdb)) $lengthdb='255';
265
+            }
266
+            $field_desc = array(
267
+                'type'=>$typedb,
268
+                'value'=>$lengthdb,
269
+                'null'=>($required?'NOT NULL':'NULL'),
270
+                'default' => $default_value
271
+            );
272
+
273
+            $result=$this->db->DDLAddField(MAIN_DB_PREFIX.$table, $attrname, $field_desc);
274
+            if ($result > 0)
275
+            {
276
+                if ($unique)
277
+                {
278
+                    $sql="ALTER TABLE ".MAIN_DB_PREFIX.$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
279
+                    $resql=$this->db->query($sql,1,'dml');
280
+                }
281
+                return 1;
282
+            }
283
+            else
284
+            {
285
+                $this->error=$this->db->lasterror();
286
+                $this->errno=$this->db->lasterrno();
287
+                return -1;
288
+            }
289
+        }
290
+        else
291
+        {
292
+            return 0;
293
+        }
294
+    }
295 295
 
296 296
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
297
-	/**
298
-	 *	Add description of a new optional attribute
299
-	 *
300
-	 *	@param	string			$attrname		code of attribute
301
-	 *	@param	string			$label			label of attribute
302
-	 *  @param	int				$type			Type of attribute ('int', 'varchar', 'text', 'html', 'date', 'datehour', 'float')
303
-	 *  @param	int				$pos			Position of attribute
304
-	 *  @param	string			$size			Size/length of attribute ('5', '24,8', ...)
305
-	 *  @param  string			$elementtype	Element type ('member', 'product', 'thirdparty', ...)
306
-	 *  @param	int				$unique			Is field unique or not
307
-	 *  @param	int				$required		Is field required or not
308
-	 *  @param  array|string	$param			Params for field  (ex for select list : array('options' => array(value'=>'label of option')) )
309
-	 *  @param  int				$alwayseditable	Is attribute always editable regardless of the document status
310
-	 *  @param	string			$perms			Permission to check
311
-	 *  @param	string			$list			Visibily
312
-	 *  @param	string			$help			Help on tooltip
313
-	 *  @param  string          $default        Default value (in database. use the default_value feature for default value on screen).
314
-	 *  @param  string          $computed       Computed value
315
-	 *  @param  string          $entity     	Entity of extrafields
316
-	 *  @param	string			$langfile		Language file
317
-	 *  @param  string  		$enabled  		Condition to have the field enabled or not
318
-	 *  @return	int								<=0 if KO, >0 if OK
319
-	 */
320
-	private function create_label($attrname, $label='', $type='', $pos=0, $size=0, $elementtype='member', $unique=0, $required=0, $param='', $alwayseditable=0, $perms='', $list='-1', $help='', $default='', $computed='',$entity='', $langfile='', $enabled='1')
321
-	{
297
+    /**
298
+     *	Add description of a new optional attribute
299
+     *
300
+     *	@param	string			$attrname		code of attribute
301
+     *	@param	string			$label			label of attribute
302
+     *  @param	int				$type			Type of attribute ('int', 'varchar', 'text', 'html', 'date', 'datehour', 'float')
303
+     *  @param	int				$pos			Position of attribute
304
+     *  @param	string			$size			Size/length of attribute ('5', '24,8', ...)
305
+     *  @param  string			$elementtype	Element type ('member', 'product', 'thirdparty', ...)
306
+     *  @param	int				$unique			Is field unique or not
307
+     *  @param	int				$required		Is field required or not
308
+     *  @param  array|string	$param			Params for field  (ex for select list : array('options' => array(value'=>'label of option')) )
309
+     *  @param  int				$alwayseditable	Is attribute always editable regardless of the document status
310
+     *  @param	string			$perms			Permission to check
311
+     *  @param	string			$list			Visibily
312
+     *  @param	string			$help			Help on tooltip
313
+     *  @param  string          $default        Default value (in database. use the default_value feature for default value on screen).
314
+     *  @param  string          $computed       Computed value
315
+     *  @param  string          $entity     	Entity of extrafields
316
+     *  @param	string			$langfile		Language file
317
+     *  @param  string  		$enabled  		Condition to have the field enabled or not
318
+     *  @return	int								<=0 if KO, >0 if OK
319
+     */
320
+    private function create_label($attrname, $label='', $type='', $pos=0, $size=0, $elementtype='member', $unique=0, $required=0, $param='', $alwayseditable=0, $perms='', $list='-1', $help='', $default='', $computed='',$entity='', $langfile='', $enabled='1')
321
+    {
322 322
         // phpcs:enable
323
-		global $conf,$user;
324
-
325
-		if ($elementtype == 'thirdparty') $elementtype='societe';
326
-		if ($elementtype == 'contact') $elementtype='socpeople';
327
-
328
-		// Clean parameters
329
-		if (empty($pos)) $pos=0;
330
-		if (empty($list)) $list='0';
331
-		if (empty($required)) $required=0;
332
-		if (empty($unique)) $unique=0;
333
-		if (empty($alwayseditable)) $alwayseditable=0;
334
-
335
-		if (! empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname) && ! is_numeric($attrname))
336
-		{
337
-			if (is_array($param) && count($param) > 0)
338
-			{
339
-				$params = serialize($param);
340
-			}
341
-			elseif (strlen($param) > 0)
342
-			{
343
-				$params = trim($param);
344
-			}
345
-			else
346
-			{
347
-				$params='';
348
-			}
349
-
350
-			$sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(";
351
-			$sql.= " name,";
352
-			$sql.= " label,";
353
-			$sql.= " type,";
354
-			$sql.= " pos,";
355
-			$sql.= " size,";
356
-			$sql.= " entity,";
357
-			$sql.= " elementtype,";
358
-			$sql.= " fieldunique,";
359
-			$sql.= " fieldrequired,";
360
-			$sql.= " param,";
361
-			$sql.= " alwayseditable,";
362
-			$sql.= " perms,";
363
-			$sql.= " langs,";
364
-			$sql.= " list,";
365
-			$sql.= " fielddefault,";
366
-			$sql.= " fieldcomputed,";
367
-			$sql.= " fk_user_author,";
368
-			$sql.= " fk_user_modif,";
369
-			$sql.= " datec,";
370
-			$sql.= " enabled,";
371
-			$sql.= " help";
372
-			$sql.= " )";
373
-			$sql.= " VALUES('".$attrname."',";
374
-			$sql.= " '".$this->db->escape($label)."',";
375
-			$sql.= " '".$this->db->escape($type)."',";
376
-			$sql.= " ".$pos.",";
377
-			$sql.= " '".$this->db->escape($size)."',";
378
-			$sql.= " ".($entity===''?$conf->entity:$entity).",";
379
-			$sql.= " '".$this->db->escape($elementtype)."',";
380
-			$sql.= " ".$unique.",";
381
-			$sql.= " ".$required.",";
382
-			$sql.= " '".$this->db->escape($params)."',";
383
-			$sql.= " ".$alwayseditable.",";
384
-			$sql.= " ".($perms?"'".$this->db->escape($perms)."'":"null").",";
385
-			$sql.= " ".($langfile?"'".$this->db->escape($langfile)."'":"null").",";
386
-			$sql.= " '".$this->db->escape($list)."',";
387
-			$sql.= " ".($default?"'".$this->db->escape($default)."'":"null").",";
388
-			$sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null").",";
389
-			$sql .= " " . (is_object($user) ? $user->id : 0). ",";
390
-			$sql .= " " . (is_object($user) ? $user->id : 0). ",";
391
-			$sql .= "'" . $this->db->idate(dol_now()) . "',";
392
-			$sql.= " ".($enabled?"'".$this->db->escape($enabled)."'":"1").",";
393
-			$sql.= " ".($help?"'".$this->db->escape($help)."'":"null");
394
-			$sql.=')';
395
-
396
-			dol_syslog(get_class($this)."::create_label", LOG_DEBUG);
397
-			if ($this->db->query($sql))
398
-			{
399
-				return 1;
400
-			}
401
-			else
402
-			{
403
-				$this->error=$this->db->lasterror();
404
-				$this->errno=$this->db->lasterrno();
405
-				return -1;
406
-			}
407
-		}
408
-	}
409
-
410
-	/**
411
-	 *	Delete an optional attribute
412
-	 *
413
-	 *	@param	string	$attrname		Code of attribute to delete
414
-	 *  @param  string	$elementtype    Element type ('member', 'product', 'thirdparty', 'contact', ...)
415
-	 *  @return int              		< 0 if KO, 0 if nothing is done, 1 if OK
416
-	 */
417
-	function delete($attrname, $elementtype='member')
418
-	{
419
-		if ($elementtype == 'thirdparty') $elementtype='societe';
420
-		if ($elementtype == 'contact') $elementtype='socpeople';
421
-
422
-		$table=$elementtype.'_extrafields';
423
-		if ($elementtype == 'categorie') $table='categories_extrafields';
424
-
425
-		$error=0;
426
-
427
-		if (! empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
428
-		{
429
-			$result=$this->delete_label($attrname,$elementtype);
430
-			if ($result < 0)
431
-			{
432
-			    $this->error=$this->db->lasterror();
433
-			    $error++;
434
-			}
435
-
436
-			if (! $error)
437
-			{
438
-        		$sql = "SELECT COUNT(rowid) as nb";
439
-        		$sql.= " FROM ".MAIN_DB_PREFIX."extrafields";
440
-        		$sql.= " WHERE elementtype = '".$elementtype."'";
441
-        		$sql.= " AND name = '".$attrname."'";
442
-        		//$sql.= " AND entity IN (0,".$conf->entity.")";      Do not test on entity here. We want to see if there is still on field remaning in other entities before deleting field in table
323
+        global $conf,$user;
324
+
325
+        if ($elementtype == 'thirdparty') $elementtype='societe';
326
+        if ($elementtype == 'contact') $elementtype='socpeople';
327
+
328
+        // Clean parameters
329
+        if (empty($pos)) $pos=0;
330
+        if (empty($list)) $list='0';
331
+        if (empty($required)) $required=0;
332
+        if (empty($unique)) $unique=0;
333
+        if (empty($alwayseditable)) $alwayseditable=0;
334
+
335
+        if (! empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname) && ! is_numeric($attrname))
336
+        {
337
+            if (is_array($param) && count($param) > 0)
338
+            {
339
+                $params = serialize($param);
340
+            }
341
+            elseif (strlen($param) > 0)
342
+            {
343
+                $params = trim($param);
344
+            }
345
+            else
346
+            {
347
+                $params='';
348
+            }
349
+
350
+            $sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(";
351
+            $sql.= " name,";
352
+            $sql.= " label,";
353
+            $sql.= " type,";
354
+            $sql.= " pos,";
355
+            $sql.= " size,";
356
+            $sql.= " entity,";
357
+            $sql.= " elementtype,";
358
+            $sql.= " fieldunique,";
359
+            $sql.= " fieldrequired,";
360
+            $sql.= " param,";
361
+            $sql.= " alwayseditable,";
362
+            $sql.= " perms,";
363
+            $sql.= " langs,";
364
+            $sql.= " list,";
365
+            $sql.= " fielddefault,";
366
+            $sql.= " fieldcomputed,";
367
+            $sql.= " fk_user_author,";
368
+            $sql.= " fk_user_modif,";
369
+            $sql.= " datec,";
370
+            $sql.= " enabled,";
371
+            $sql.= " help";
372
+            $sql.= " )";
373
+            $sql.= " VALUES('".$attrname."',";
374
+            $sql.= " '".$this->db->escape($label)."',";
375
+            $sql.= " '".$this->db->escape($type)."',";
376
+            $sql.= " ".$pos.",";
377
+            $sql.= " '".$this->db->escape($size)."',";
378
+            $sql.= " ".($entity===''?$conf->entity:$entity).",";
379
+            $sql.= " '".$this->db->escape($elementtype)."',";
380
+            $sql.= " ".$unique.",";
381
+            $sql.= " ".$required.",";
382
+            $sql.= " '".$this->db->escape($params)."',";
383
+            $sql.= " ".$alwayseditable.",";
384
+            $sql.= " ".($perms?"'".$this->db->escape($perms)."'":"null").",";
385
+            $sql.= " ".($langfile?"'".$this->db->escape($langfile)."'":"null").",";
386
+            $sql.= " '".$this->db->escape($list)."',";
387
+            $sql.= " ".($default?"'".$this->db->escape($default)."'":"null").",";
388
+            $sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null").",";
389
+            $sql .= " " . (is_object($user) ? $user->id : 0). ",";
390
+            $sql .= " " . (is_object($user) ? $user->id : 0). ",";
391
+            $sql .= "'" . $this->db->idate(dol_now()) . "',";
392
+            $sql.= " ".($enabled?"'".$this->db->escape($enabled)."'":"1").",";
393
+            $sql.= " ".($help?"'".$this->db->escape($help)."'":"null");
394
+            $sql.=')';
395
+
396
+            dol_syslog(get_class($this)."::create_label", LOG_DEBUG);
397
+            if ($this->db->query($sql))
398
+            {
399
+                return 1;
400
+            }
401
+            else
402
+            {
403
+                $this->error=$this->db->lasterror();
404
+                $this->errno=$this->db->lasterrno();
405
+                return -1;
406
+            }
407
+        }
408
+    }
409
+
410
+    /**
411
+     *	Delete an optional attribute
412
+     *
413
+     *	@param	string	$attrname		Code of attribute to delete
414
+     *  @param  string	$elementtype    Element type ('member', 'product', 'thirdparty', 'contact', ...)
415
+     *  @return int              		< 0 if KO, 0 if nothing is done, 1 if OK
416
+     */
417
+    function delete($attrname, $elementtype='member')
418
+    {
419
+        if ($elementtype == 'thirdparty') $elementtype='societe';
420
+        if ($elementtype == 'contact') $elementtype='socpeople';
421
+
422
+        $table=$elementtype.'_extrafields';
423
+        if ($elementtype == 'categorie') $table='categories_extrafields';
424
+
425
+        $error=0;
426
+
427
+        if (! empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
428
+        {
429
+            $result=$this->delete_label($attrname,$elementtype);
430
+            if ($result < 0)
431
+            {
432
+                $this->error=$this->db->lasterror();
433
+                $error++;
434
+            }
435
+
436
+            if (! $error)
437
+            {
438
+                $sql = "SELECT COUNT(rowid) as nb";
439
+                $sql.= " FROM ".MAIN_DB_PREFIX."extrafields";
440
+                $sql.= " WHERE elementtype = '".$elementtype."'";
441
+                $sql.= " AND name = '".$attrname."'";
442
+                //$sql.= " AND entity IN (0,".$conf->entity.")";      Do not test on entity here. We want to see if there is still on field remaning in other entities before deleting field in table
443 443
                 $resql = $this->db->query($sql);
444 444
                 if ($resql)
445 445
                 {
446 446
                     $obj = $this->db->fetch_object($resql);
447 447
                     if ($obj->nb <= 0)
448 448
                     {
449
-            			$result=$this->db->DDLDropField(MAIN_DB_PREFIX.$table,$attrname);	// This also drop the unique key
450
-            			if ($result < 0)
451
-            			{
452
-            				$this->error=$this->db->lasterror();
453
-            				$error++;
454
-            			}
449
+                        $result=$this->db->DDLDropField(MAIN_DB_PREFIX.$table,$attrname);	// This also drop the unique key
450
+                        if ($result < 0)
451
+                        {
452
+                            $this->error=$this->db->lasterror();
453
+                            $error++;
454
+                        }
455 455
                     }
456 456
                 }
457
-			}
457
+            }
458 458
 
459
-			return $result;
460
-		}
461
-		else
462
-		{
463
-			return 0;
464
-		}
465
-	}
459
+            return $result;
460
+        }
461
+        else
462
+        {
463
+            return 0;
464
+        }
465
+    }
466 466
 
467 467
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
468
-	/**
469
-	 *	Delete description of an optional attribute
470
-	 *
471
-	 *	@param	string	$attrname			Code of attribute to delete
472
-	 *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', ...)
473
-	 *  @return int              			< 0 if KO, 0 if nothing is done, 1 if OK
474
-	 */
475
-	private function delete_label($attrname, $elementtype='member')
476
-	{
468
+    /**
469
+     *	Delete description of an optional attribute
470
+     *
471
+     *	@param	string	$attrname			Code of attribute to delete
472
+     *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', ...)
473
+     *  @return int              			< 0 if KO, 0 if nothing is done, 1 if OK
474
+     */
475
+    private function delete_label($attrname, $elementtype='member')
476
+    {
477 477
         // phpcs:enable
478
-		global $conf;
479
-
480
-		if ($elementtype == 'thirdparty') $elementtype='societe';
481
-		if ($elementtype == 'contact') $elementtype='socpeople';
482
-
483
-		if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
484
-		{
485
-			$sql = "DELETE FROM ".MAIN_DB_PREFIX."extrafields";
486
-			$sql.= " WHERE name = '".$attrname."'";
487
-			$sql.= " AND entity IN  (0,".$conf->entity.')';
488
-			$sql.= " AND elementtype = '".$elementtype."'";
489
-
490
-			dol_syslog(get_class($this)."::delete_label", LOG_DEBUG);
491
-			$resql=$this->db->query($sql);
492
-			if ($resql)
493
-			{
494
-				return 1;
495
-			}
496
-			else
497
-			{
498
-				print dol_print_error($this->db);
499
-				return -1;
500
-			}
501
-		}
502
-		else
503
-		{
504
-			return 0;
505
-		}
506
-	}
507
-
508
-	/**
509
-	 * 	Modify type of a personalized attribute
510
-	 *
511
-	 *  @param	string	$attrname			Name of attribute
512
-	 *  @param	string	$label				Label of attribute
513
-	 *  @param	string	$type				Type of attribute ('boolean', 'int', 'varchar', 'text', 'html', 'date', 'datehour','price','phone','mail','password','url','select','checkbox', ...)
514
-	 *  @param	int		$length				Length of attribute
515
-	 *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', 'contact', ...)
516
-	 *  @param	int		$unique				Is field unique or not
517
-	 *  @param	int		$required			Is field required or not
518
-	 *  @param	int		$pos				Position of attribute
519
-	 *  @param  array	$param				Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
520
-	 *  @param  int		$alwayseditable		Is attribute always editable regardless of the document status
521
-	 *  @param	string	$perms				Permission to check
522
-	 *  @param	string	$list				Visibility
523
-	 *  @param	string	$help				Help on tooltip
524
-	 *  @param  string  $default            Default value (in database. use the default_value feature for default value on screen).
525
-	 *  @param  string  $computed           Computed value
526
-	 *  @param  string  $entity	            Entity of extrafields
527
-	 *  @param	string	$langfile			Language file
528
-	 *  @param  string  $enabled  			Condition to have the field enabled or not
478
+        global $conf;
479
+
480
+        if ($elementtype == 'thirdparty') $elementtype='societe';
481
+        if ($elementtype == 'contact') $elementtype='socpeople';
482
+
483
+        if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
484
+        {
485
+            $sql = "DELETE FROM ".MAIN_DB_PREFIX."extrafields";
486
+            $sql.= " WHERE name = '".$attrname."'";
487
+            $sql.= " AND entity IN  (0,".$conf->entity.')';
488
+            $sql.= " AND elementtype = '".$elementtype."'";
489
+
490
+            dol_syslog(get_class($this)."::delete_label", LOG_DEBUG);
491
+            $resql=$this->db->query($sql);
492
+            if ($resql)
493
+            {
494
+                return 1;
495
+            }
496
+            else
497
+            {
498
+                print dol_print_error($this->db);
499
+                return -1;
500
+            }
501
+        }
502
+        else
503
+        {
504
+            return 0;
505
+        }
506
+    }
507
+
508
+    /**
509
+     * 	Modify type of a personalized attribute
510
+     *
511
+     *  @param	string	$attrname			Name of attribute
512
+     *  @param	string	$label				Label of attribute
513
+     *  @param	string	$type				Type of attribute ('boolean', 'int', 'varchar', 'text', 'html', 'date', 'datehour','price','phone','mail','password','url','select','checkbox', ...)
514
+     *  @param	int		$length				Length of attribute
515
+     *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', 'contact', ...)
516
+     *  @param	int		$unique				Is field unique or not
517
+     *  @param	int		$required			Is field required or not
518
+     *  @param	int		$pos				Position of attribute
519
+     *  @param  array	$param				Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
520
+     *  @param  int		$alwayseditable		Is attribute always editable regardless of the document status
521
+     *  @param	string	$perms				Permission to check
522
+     *  @param	string	$list				Visibility
523
+     *  @param	string	$help				Help on tooltip
524
+     *  @param  string  $default            Default value (in database. use the default_value feature for default value on screen).
525
+     *  @param  string  $computed           Computed value
526
+     *  @param  string  $entity	            Entity of extrafields
527
+     *  @param	string	$langfile			Language file
528
+     *  @param  string  $enabled  			Condition to have the field enabled or not
529 529
      *  @param  int     $totalizable        Is extrafield totalizable on list
530
-	 * 	@return	int							>0 if OK, <=0 if KO
531
-	 */
532
-	function update($attrname, $label, $type, $length, $elementtype, $unique=0, $required=0, $pos=0, $param='', $alwayseditable=0, $perms='', $list='', $help='', $default='', $computed='', $entity='', $langfile='', $enabled='1', $totalizable=0)
533
-	{
534
-		if ($elementtype == 'thirdparty') $elementtype='societe';
535
-		if ($elementtype == 'contact') $elementtype='socpeople';
530
+     * 	@return	int							>0 if OK, <=0 if KO
531
+     */
532
+    function update($attrname, $label, $type, $length, $elementtype, $unique=0, $required=0, $pos=0, $param='', $alwayseditable=0, $perms='', $list='', $help='', $default='', $computed='', $entity='', $langfile='', $enabled='1', $totalizable=0)
533
+    {
534
+        if ($elementtype == 'thirdparty') $elementtype='societe';
535
+        if ($elementtype == 'contact') $elementtype='socpeople';
536 536
 
537 537
         $table=$elementtype.'_extrafields';
538
-		if ($elementtype == 'categorie') $table='categories_extrafields';
539
-
540
-		if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
541
-		{
542
-			if ($type=='boolean') {
543
-				$typedb='int';
544
-				$lengthdb='1';
545
-			} elseif($type=='price') {
546
-				$typedb='double';
547
-				$lengthdb='24,8';
548
-			} elseif($type=='phone') {
549
-				$typedb='varchar';
550
-				$lengthdb='20';
551
-			} elseif($type=='mail') {
552
-				$typedb='varchar';
553
-				$lengthdb='128';
554
-			} elseif($type=='url') {
555
-				$typedb='varchar';
556
-				$lengthdb='255';
557
-			} elseif (($type=='select') || ($type=='sellist') || ($type=='radio') || ($type=='checkbox') || ($type=='chkbxlst')) {
558
-				$typedb='varchar';
559
-				$lengthdb='255';
560
-			} elseif ($type == 'html') {
561
-				$typedb='text';
562
-			} elseif ($type=='link') {
563
-				$typedb='int';
564
-				$lengthdb='11';
565
-			} elseif($type=='password') {
566
-				$typedb='varchar';
567
-				$lengthdb='50';
568
-			} else {
569
-				$typedb=$type;
570
-				$lengthdb=$length;
571
-			}
572
-			$field_desc = array('type'=>$typedb, 'value'=>$lengthdb, 'null'=>($required?'NOT NULL':'NULL'), 'default'=>$default);
573
-
574
-			if ($type != 'separate') // No table update when separate type
575
-			{
576
-				$result=$this->db->DDLUpdateField(MAIN_DB_PREFIX.$table, $attrname, $field_desc);
577
-			}
578
-			if ($result > 0 || $type == 'separate')
579
-			{
580
-				if ($label)
581
-				{
582
-					$result=$this->update_label($attrname,$label,$type,$length,$elementtype,$unique,$required,$pos,$param,$alwayseditable,$perms,$list,$help,$default,$computed,$entity,$langfile,$enabled, $totalizable);
583
-				}
584
-				if ($result > 0)
585
-				{
586
-					$sql='';
587
-					if ($unique)
588
-					{
589
-						$sql="ALTER TABLE ".MAIN_DB_PREFIX.$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
590
-					}
591
-					else
592
-					{
593
-						$sql="ALTER TABLE ".MAIN_DB_PREFIX.$table." DROP INDEX uk_".$table."_".$attrname;
594
-					}
595
-					dol_syslog(get_class($this).'::update', LOG_DEBUG);
596
-					$resql=$this->db->query($sql,1,'dml');
597
-					return 1;
598
-				}
599
-				else
600
-				{
601
-					$this->error=$this->db->lasterror();
602
-					return -1;
603
-				}
604
-			}
605
-			else
606
-			{
607
-				$this->error=$this->db->lasterror();
608
-				return -1;
609
-			}
610
-		}
611
-		else
612
-		{
613
-			return 0;
614
-		}
615
-	}
538
+        if ($elementtype == 'categorie') $table='categories_extrafields';
539
+
540
+        if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
541
+        {
542
+            if ($type=='boolean') {
543
+                $typedb='int';
544
+                $lengthdb='1';
545
+            } elseif($type=='price') {
546
+                $typedb='double';
547
+                $lengthdb='24,8';
548
+            } elseif($type=='phone') {
549
+                $typedb='varchar';
550
+                $lengthdb='20';
551
+            } elseif($type=='mail') {
552
+                $typedb='varchar';
553
+                $lengthdb='128';
554
+            } elseif($type=='url') {
555
+                $typedb='varchar';
556
+                $lengthdb='255';
557
+            } elseif (($type=='select') || ($type=='sellist') || ($type=='radio') || ($type=='checkbox') || ($type=='chkbxlst')) {
558
+                $typedb='varchar';
559
+                $lengthdb='255';
560
+            } elseif ($type == 'html') {
561
+                $typedb='text';
562
+            } elseif ($type=='link') {
563
+                $typedb='int';
564
+                $lengthdb='11';
565
+            } elseif($type=='password') {
566
+                $typedb='varchar';
567
+                $lengthdb='50';
568
+            } else {
569
+                $typedb=$type;
570
+                $lengthdb=$length;
571
+            }
572
+            $field_desc = array('type'=>$typedb, 'value'=>$lengthdb, 'null'=>($required?'NOT NULL':'NULL'), 'default'=>$default);
573
+
574
+            if ($type != 'separate') // No table update when separate type
575
+            {
576
+                $result=$this->db->DDLUpdateField(MAIN_DB_PREFIX.$table, $attrname, $field_desc);
577
+            }
578
+            if ($result > 0 || $type == 'separate')
579
+            {
580
+                if ($label)
581
+                {
582
+                    $result=$this->update_label($attrname,$label,$type,$length,$elementtype,$unique,$required,$pos,$param,$alwayseditable,$perms,$list,$help,$default,$computed,$entity,$langfile,$enabled, $totalizable);
583
+                }
584
+                if ($result > 0)
585
+                {
586
+                    $sql='';
587
+                    if ($unique)
588
+                    {
589
+                        $sql="ALTER TABLE ".MAIN_DB_PREFIX.$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
590
+                    }
591
+                    else
592
+                    {
593
+                        $sql="ALTER TABLE ".MAIN_DB_PREFIX.$table." DROP INDEX uk_".$table."_".$attrname;
594
+                    }
595
+                    dol_syslog(get_class($this).'::update', LOG_DEBUG);
596
+                    $resql=$this->db->query($sql,1,'dml');
597
+                    return 1;
598
+                }
599
+                else
600
+                {
601
+                    $this->error=$this->db->lasterror();
602
+                    return -1;
603
+                }
604
+            }
605
+            else
606
+            {
607
+                $this->error=$this->db->lasterror();
608
+                return -1;
609
+            }
610
+        }
611
+        else
612
+        {
613
+            return 0;
614
+        }
615
+    }
616 616
 
617 617
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
618
-	/**
619
-	 *  Modify description of personalized attribute
620
-	 *
621
-	 *  @param	string	$attrname			Name of attribute
622
-	 *  @param	string	$label				Label of attribute
623
-	 *  @param  string	$type               Type of attribute
624
-	 *  @param  int		$size		        Length of attribute
625
-	 *  @param  string	$elementtype		Element type ('member', 'product', 'thirdparty', ...)
626
-	 *  @param	int		$unique				Is field unique or not
627
-	 *  @param	int		$required			Is field required or not
628
-	 *  @param	int		$pos				Position of attribute
629
-	 *  @param  array	$param				Params for field  (ex for select list : array('options' => array(value'=>'label of option')) )
630
-	 *  @param  int		$alwayseditable		Is attribute always editable regardless of the document status
631
-	 *  @param	string	$perms				Permission to check
632
-	 *  @param	string	$list				Visiblity
633
-	 *  @param	string	$help				Help on tooltip.
634
-	 *  @param  string  $default            Default value (in database. use the default_value feature for default value on screen).
635
-	 *  @param  string  $computed           Computed value
636
-	 *  @param  string  $entity     		Entity of extrafields
637
-	 *  @param	string	$langfile			Language file
638
-	 *  @param  string  $enabled  			Condition to have the field enabled or not
618
+    /**
619
+     *  Modify description of personalized attribute
620
+     *
621
+     *  @param	string	$attrname			Name of attribute
622
+     *  @param	string	$label				Label of attribute
623
+     *  @param  string	$type               Type of attribute
624
+     *  @param  int		$size		        Length of attribute
625
+     *  @param  string	$elementtype		Element type ('member', 'product', 'thirdparty', ...)
626
+     *  @param	int		$unique				Is field unique or not
627
+     *  @param	int		$required			Is field required or not
628
+     *  @param	int		$pos				Position of attribute
629
+     *  @param  array	$param				Params for field  (ex for select list : array('options' => array(value'=>'label of option')) )
630
+     *  @param  int		$alwayseditable		Is attribute always editable regardless of the document status
631
+     *  @param	string	$perms				Permission to check
632
+     *  @param	string	$list				Visiblity
633
+     *  @param	string	$help				Help on tooltip.
634
+     *  @param  string  $default            Default value (in database. use the default_value feature for default value on screen).
635
+     *  @param  string  $computed           Computed value
636
+     *  @param  string  $entity     		Entity of extrafields
637
+     *  @param	string	$langfile			Language file
638
+     *  @param  string  $enabled  			Condition to have the field enabled or not
639 639
      *  @param  int     $totalizable        Is extrafield totalizable on list
640 640
      *  @return	int							<=0 if KO, >0 if OK
641
-	 */
642
-	private function update_label($attrname,$label,$type,$size,$elementtype,$unique=0,$required=0,$pos=0,$param='',$alwayseditable=0,$perms='',$list='0',$help='',$default='',$computed='',$entity='',$langfile='',$enabled='1', $totalizable=0)
643
-	{
641
+     */
642
+    private function update_label($attrname,$label,$type,$size,$elementtype,$unique=0,$required=0,$pos=0,$param='',$alwayseditable=0,$perms='',$list='0',$help='',$default='',$computed='',$entity='',$langfile='',$enabled='1', $totalizable=0)
643
+    {
644 644
         // phpcs:enable
645
-		global $conf, $user;
646
-		dol_syslog(get_class($this)."::update_label ".$attrname.", ".$label.", ".$type.", ".$size.", ".$elementtype.", ".$unique.", ".$required.", ".$pos.", ".$alwayseditable.", ".$perms.", ".$list.", ".$default.", ".$computed.", ".$entity.", ".$langfile.", ".$enabled.", ".$totalizable);
645
+        global $conf, $user;
646
+        dol_syslog(get_class($this)."::update_label ".$attrname.", ".$label.", ".$type.", ".$size.", ".$elementtype.", ".$unique.", ".$required.", ".$pos.", ".$alwayseditable.", ".$perms.", ".$list.", ".$default.", ".$computed.", ".$entity.", ".$langfile.", ".$enabled.", ".$totalizable);
647 647
 
648
-		// Clean parameters
649
-		if ($elementtype == 'thirdparty') $elementtype='societe';
650
-		if ($elementtype == 'contact') $elementtype='socpeople';
648
+        // Clean parameters
649
+        if ($elementtype == 'thirdparty') $elementtype='societe';
650
+        if ($elementtype == 'contact') $elementtype='socpeople';
651 651
 
652
-		if (empty($pos)) $pos=0;
653
-		if (empty($list)) $list='0';
652
+        if (empty($pos)) $pos=0;
653
+        if (empty($list)) $list='0';
654 654
         if (empty($totalizable)) {
655 655
             $totalizable = 0;
656 656
         }
657
-		if (empty($required)) $required=0;
658
-		if (empty($unique)) $unique=0;
659
-		if (empty($alwayseditable)) $alwayseditable=0;
660
-
661
-		if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
662
-		{
663
-			$this->db->begin();
664
-
665
-			if (is_array($param) && count($param) > 0)
666
-			{
667
-				$params = serialize($param);
668
-			}
669
-			elseif (strlen($param) > 0)
670
-			{
671
-				$params = trim($param);
672
-			}
673
-			else
674
-			{
675
-				$params='';
676
-			}
677
-
678
-			if ($entity === '' || $entity != '0')
679
-			{
680
-				// We dont want on all entities, we delete all and current
681
-				$sql_del = "DELETE FROM ".MAIN_DB_PREFIX."extrafields";
682
-				$sql_del.= " WHERE name = '".$attrname."'";
683
-				$sql_del.= " AND entity IN (0, ".($entity===''?$conf->entity:$entity).")";
684
-				$sql_del.= " AND elementtype = '".$elementtype."'";
685
-			}
686
-			else
687
-			{
688
-				// We want on all entities ($entities = '0'), we delete on all only (we keep setup specific to each entity)
689
-				$sql_del = "DELETE FROM ".MAIN_DB_PREFIX."extrafields";
690
-				$sql_del.= " WHERE name = '".$attrname."'";
691
-				$sql_del.= " AND entity = 0";
692
-				$sql_del.= " AND elementtype = '".$elementtype."'";
693
-			}
694
-			$resql1=$this->db->query($sql_del);
695
-
696
-			$sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(";
697
-			$sql.= " name,";		// This is code
698
-			$sql.= " entity,";
699
-			$sql.= " label,";
700
-			$sql.= " type,";
701
-			$sql.= " size,";
702
-			$sql.= " elementtype,";
703
-			$sql.= " fieldunique,";
704
-			$sql.= " fieldrequired,";
705
-			$sql.= " perms,";
706
-			$sql.= " langs,";
707
-			$sql.= " pos,";
708
-			$sql.= " alwayseditable,";
709
-			$sql.= " param,";
710
-			$sql.= " list,";
657
+        if (empty($required)) $required=0;
658
+        if (empty($unique)) $unique=0;
659
+        if (empty($alwayseditable)) $alwayseditable=0;
660
+
661
+        if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
662
+        {
663
+            $this->db->begin();
664
+
665
+            if (is_array($param) && count($param) > 0)
666
+            {
667
+                $params = serialize($param);
668
+            }
669
+            elseif (strlen($param) > 0)
670
+            {
671
+                $params = trim($param);
672
+            }
673
+            else
674
+            {
675
+                $params='';
676
+            }
677
+
678
+            if ($entity === '' || $entity != '0')
679
+            {
680
+                // We dont want on all entities, we delete all and current
681
+                $sql_del = "DELETE FROM ".MAIN_DB_PREFIX."extrafields";
682
+                $sql_del.= " WHERE name = '".$attrname."'";
683
+                $sql_del.= " AND entity IN (0, ".($entity===''?$conf->entity:$entity).")";
684
+                $sql_del.= " AND elementtype = '".$elementtype."'";
685
+            }
686
+            else
687
+            {
688
+                // We want on all entities ($entities = '0'), we delete on all only (we keep setup specific to each entity)
689
+                $sql_del = "DELETE FROM ".MAIN_DB_PREFIX."extrafields";
690
+                $sql_del.= " WHERE name = '".$attrname."'";
691
+                $sql_del.= " AND entity = 0";
692
+                $sql_del.= " AND elementtype = '".$elementtype."'";
693
+            }
694
+            $resql1=$this->db->query($sql_del);
695
+
696
+            $sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(";
697
+            $sql.= " name,";		// This is code
698
+            $sql.= " entity,";
699
+            $sql.= " label,";
700
+            $sql.= " type,";
701
+            $sql.= " size,";
702
+            $sql.= " elementtype,";
703
+            $sql.= " fieldunique,";
704
+            $sql.= " fieldrequired,";
705
+            $sql.= " perms,";
706
+            $sql.= " langs,";
707
+            $sql.= " pos,";
708
+            $sql.= " alwayseditable,";
709
+            $sql.= " param,";
710
+            $sql.= " list,";
711 711
             $sql.= " totalizable,";
712
-			$sql.= " fielddefault,";
713
-			$sql.= " fieldcomputed,";
714
-			$sql.= " fk_user_author,";
715
-			$sql.= " fk_user_modif,";
716
-			$sql.= " datec,";
717
-			$sql.= " enabled,";
718
-			$sql.= " help";
719
-			$sql.= ") VALUES (";
720
-			$sql.= "'".$attrname."',";
721
-			$sql.= " ".($entity===''?$conf->entity:$entity).",";
722
-			$sql.= " '".$this->db->escape($label)."',";
723
-			$sql.= " '".$this->db->escape($type)."',";
724
-			$sql.= " '".$this->db->escape($size)."',";
725
-			$sql.= " '".$this->db->escape($elementtype)."',";
726
-			$sql.= " ".$unique.",";
727
-			$sql.= " ".$required.",";
728
-			$sql.= " ".($perms?"'".$this->db->escape($perms)."'":"null").",";
729
-			$sql.= " ".($langfile?"'".$this->db->escape($langfile)."'":"null").",";
730
-			$sql.= " ".$pos.",";
731
-			$sql.= " '".$this->db->escape($alwayseditable)."',";
732
-			$sql.= " '".$this->db->escape($params)."',";
733
-			$sql.= " '".$this->db->escape($list)."', ";
712
+            $sql.= " fielddefault,";
713
+            $sql.= " fieldcomputed,";
714
+            $sql.= " fk_user_author,";
715
+            $sql.= " fk_user_modif,";
716
+            $sql.= " datec,";
717
+            $sql.= " enabled,";
718
+            $sql.= " help";
719
+            $sql.= ") VALUES (";
720
+            $sql.= "'".$attrname."',";
721
+            $sql.= " ".($entity===''?$conf->entity:$entity).",";
722
+            $sql.= " '".$this->db->escape($label)."',";
723
+            $sql.= " '".$this->db->escape($type)."',";
724
+            $sql.= " '".$this->db->escape($size)."',";
725
+            $sql.= " '".$this->db->escape($elementtype)."',";
726
+            $sql.= " ".$unique.",";
727
+            $sql.= " ".$required.",";
728
+            $sql.= " ".($perms?"'".$this->db->escape($perms)."'":"null").",";
729
+            $sql.= " ".($langfile?"'".$this->db->escape($langfile)."'":"null").",";
730
+            $sql.= " ".$pos.",";
731
+            $sql.= " '".$this->db->escape($alwayseditable)."',";
732
+            $sql.= " '".$this->db->escape($params)."',";
733
+            $sql.= " '".$this->db->escape($list)."', ";
734 734
             $sql.= " ".$totalizable.",";
735
-			$sql.= " ".(($default!='')?"'".$this->db->escape($default)."'":"null").",";
736
-			$sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null").",";
737
-			$sql .= " " . $user->id . ",";
738
-			$sql .= " " . $user->id . ",";
739
-			$sql .= "'" . $this->db->idate(dol_now()) . "',";
740
-			$sql .= "'" . $this->db->escape($enabled). "',";
741
-			$sql.= " ".($help?"'".$this->db->escape($help)."'":"null");
742
-			$sql.= ")";
743
-
744
-			$resql2=$this->db->query($sql);
745
-
746
-			if ($resql1 && $resql2)
747
-			{
748
-				$this->db->commit();
749
-				return 1;
750
-			}
751
-			else
752
-			{
753
-				$this->db->rollback();
754
-				print dol_print_error($this->db);
755
-				return -1;
756
-			}
757
-		}
758
-		else
759
-		{
760
-			return 0;
761
-		}
762
-	}
735
+            $sql.= " ".(($default!='')?"'".$this->db->escape($default)."'":"null").",";
736
+            $sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null").",";
737
+            $sql .= " " . $user->id . ",";
738
+            $sql .= " " . $user->id . ",";
739
+            $sql .= "'" . $this->db->idate(dol_now()) . "',";
740
+            $sql .= "'" . $this->db->escape($enabled). "',";
741
+            $sql.= " ".($help?"'".$this->db->escape($help)."'":"null");
742
+            $sql.= ")";
743
+
744
+            $resql2=$this->db->query($sql);
745
+
746
+            if ($resql1 && $resql2)
747
+            {
748
+                $this->db->commit();
749
+                return 1;
750
+            }
751
+            else
752
+            {
753
+                $this->db->rollback();
754
+                print dol_print_error($this->db);
755
+                return -1;
756
+            }
757
+        }
758
+        else
759
+        {
760
+            return 0;
761
+        }
762
+    }
763 763
 
764 764
 
765 765
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
766
-	/**
767
-	 * 	Load array this->attributes, or old this->attribute_xxx like attribute_label, attribute_type, ...
768
-	 *
769
-	 * 	@param	string		$elementtype		Type of element ('adherent', 'commande', 'thirdparty', 'facture', 'propal', 'product', ...).
770
-	 * 	@param	boolean		$forceload			Force load of extra fields whatever is option MAIN_EXTRAFIELDS_DISABLED. Deprecated. Should not be required.
771
-	 * 	@return	array							Array of attributes keys+label for all extra fields.
772
-	 */
773
-	function fetch_name_optionals_label($elementtype,$forceload=false)
774
-	{
766
+    /**
767
+     * 	Load array this->attributes, or old this->attribute_xxx like attribute_label, attribute_type, ...
768
+     *
769
+     * 	@param	string		$elementtype		Type of element ('adherent', 'commande', 'thirdparty', 'facture', 'propal', 'product', ...).
770
+     * 	@param	boolean		$forceload			Force load of extra fields whatever is option MAIN_EXTRAFIELDS_DISABLED. Deprecated. Should not be required.
771
+     * 	@return	array							Array of attributes keys+label for all extra fields.
772
+     */
773
+    function fetch_name_optionals_label($elementtype,$forceload=false)
774
+    {
775 775
         // phpcs:enable
776
-		global $conf;
777
-
778
-		if (empty($elementtype)) return array();
779
-
780
-		if ($elementtype == 'thirdparty') $elementtype='societe';
781
-		if ($elementtype == 'contact') $elementtype='socpeople';
782
-		if ($elementtype == 'order_supplier') $elementtype='commande_fournisseur';
783
-
784
-		$array_name_label=array();
785
-
786
-		// To avoid conflicts with external modules. TODO Remove this.
787
-		if (!$forceload && !empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return $array_name_label;
788
-
789
-		// Set array of label of entity
790
-		// TODO Remove completely loading of label. This should be done by presentation.
791
-		$labelmulticompany=array();
792
-		if (!empty($conf->multicompany->enabled))
793
-		{
794
-			$sql_entity_name='SELECT rowid, label FROM '.MAIN_DB_PREFIX.'entity WHERE rowid in (0,'.$conf->entity.')';
795
-			$resql_entity_name=$this->db->query($sql_entity_name);
796
-			if ($resql_entity_name)
797
-			{
798
-				while ($obj = $this->db->fetch_object($resql_entity_name))
799
-				{
800
-					$labelmulticompany[$obj->rowid]=$obj->label;
801
-				}
802
-			}
803
-		}
804
-
805
-		// We should not have several time this log. If we have, there is some optimization to do by calling a simple $object->fetch_optionals() that include cache management.
806
-		dol_syslog("fetch_name_optionals_label elementtype=".$elementtype);
807
-
808
-		$sql = "SELECT rowid,name,label,type,size,elementtype,fieldunique,fieldrequired,param,pos,alwayseditable,perms,langs,list,totalizable,fielddefault,fieldcomputed,entity,enabled,help";
809
-		$sql.= " FROM ".MAIN_DB_PREFIX."extrafields";
810
-		$sql.= " WHERE entity IN (0,".$conf->entity.")";
811
-		if ($elementtype) $sql.= " AND elementtype = '".$elementtype."'";	// Filed with object->table_element
812
-		$sql.= " ORDER BY pos";
813
-
814
-		$resql=$this->db->query($sql);
815
-		if ($resql)
816
-		{
817
-			if ($this->db->num_rows($resql))
818
-			{
819
-				while ($tab = $this->db->fetch_object($resql))
820
-				{
821
-					// We can add this attribute to object. TODO Remove this and return $this->attributes[$elementtype]['label']
822
-					if ($tab->type != 'separate')
823
-					{
824
-						$array_name_label[$tab->name]=$tab->label;
825
-					}
826
-
827
-					// Old usage
828
-					$this->attribute_type[$tab->name]=$tab->type;
829
-					$this->attribute_label[$tab->name]=$tab->label;
830
-					$this->attribute_size[$tab->name]=$tab->size;
831
-					$this->attribute_elementtype[$tab->name]=$tab->elementtype;
832
-					$this->attribute_default[$tab->name]=$tab->fielddefault;
833
-					$this->attribute_computed[$tab->name]=$tab->fieldcomputed;
834
-					$this->attribute_unique[$tab->name]=$tab->fieldunique;
835
-					$this->attribute_required[$tab->name]=$tab->fieldrequired;
836
-					$this->attribute_param[$tab->name]=($tab->param ? unserialize($tab->param) : '');
837
-					$this->attribute_pos[$tab->name]=$tab->pos;
838
-					$this->attribute_alwayseditable[$tab->name]=$tab->alwayseditable;
839
-					$this->attribute_perms[$tab->name]=(strlen($tab->perms) == 0 ? 1 : $tab->perms);
840
-					$this->attribute_langfile[$tab->name]=$tab->langs;
841
-					$this->attribute_list[$tab->name]=$tab->list;
842
-					$this->attribute_totalizable[$tab->name]=$tab->totalizable;
843
-					$this->attribute_entityid[$tab->name]=$tab->entity;
844
-					$this->attribute_entitylabel[$tab->name]=(empty($labelmulticompany[$tab->entity])?'Entity'.$tab->entity:$labelmulticompany[$tab->entity]);
845
-
846
-					// New usage
847
-					$this->attributes[$tab->elementtype]['type'][$tab->name]=$tab->type;
848
-					$this->attributes[$tab->elementtype]['label'][$tab->name]=$tab->label;
849
-					$this->attributes[$tab->elementtype]['size'][$tab->name]=$tab->size;
850
-					$this->attributes[$tab->elementtype]['elementtype'][$tab->name]=$tab->elementtype;
851
-					$this->attributes[$tab->elementtype]['default'][$tab->name]=$tab->fielddefault;
852
-					$this->attributes[$tab->elementtype]['computed'][$tab->name]=$tab->fieldcomputed;
853
-					$this->attributes[$tab->elementtype]['unique'][$tab->name]=$tab->fieldunique;
854
-					$this->attributes[$tab->elementtype]['required'][$tab->name]=$tab->fieldrequired;
855
-					$this->attributes[$tab->elementtype]['param'][$tab->name]=($tab->param ? unserialize($tab->param) : '');
856
-					$this->attributes[$tab->elementtype]['pos'][$tab->name]=$tab->pos;
857
-					$this->attributes[$tab->elementtype]['alwayseditable'][$tab->name]=$tab->alwayseditable;
858
-					$this->attributes[$tab->elementtype]['perms'][$tab->name]=(strlen($tab->perms) == 0 ? 1 : $tab->perms);
859
-					$this->attributes[$tab->elementtype]['langfile'][$tab->name]=$tab->langs;
860
-					$this->attributes[$tab->elementtype]['list'][$tab->name]=$tab->list;
776
+        global $conf;
777
+
778
+        if (empty($elementtype)) return array();
779
+
780
+        if ($elementtype == 'thirdparty') $elementtype='societe';
781
+        if ($elementtype == 'contact') $elementtype='socpeople';
782
+        if ($elementtype == 'order_supplier') $elementtype='commande_fournisseur';
783
+
784
+        $array_name_label=array();
785
+
786
+        // To avoid conflicts with external modules. TODO Remove this.
787
+        if (!$forceload && !empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return $array_name_label;
788
+
789
+        // Set array of label of entity
790
+        // TODO Remove completely loading of label. This should be done by presentation.
791
+        $labelmulticompany=array();
792
+        if (!empty($conf->multicompany->enabled))
793
+        {
794
+            $sql_entity_name='SELECT rowid, label FROM '.MAIN_DB_PREFIX.'entity WHERE rowid in (0,'.$conf->entity.')';
795
+            $resql_entity_name=$this->db->query($sql_entity_name);
796
+            if ($resql_entity_name)
797
+            {
798
+                while ($obj = $this->db->fetch_object($resql_entity_name))
799
+                {
800
+                    $labelmulticompany[$obj->rowid]=$obj->label;
801
+                }
802
+            }
803
+        }
804
+
805
+        // We should not have several time this log. If we have, there is some optimization to do by calling a simple $object->fetch_optionals() that include cache management.
806
+        dol_syslog("fetch_name_optionals_label elementtype=".$elementtype);
807
+
808
+        $sql = "SELECT rowid,name,label,type,size,elementtype,fieldunique,fieldrequired,param,pos,alwayseditable,perms,langs,list,totalizable,fielddefault,fieldcomputed,entity,enabled,help";
809
+        $sql.= " FROM ".MAIN_DB_PREFIX."extrafields";
810
+        $sql.= " WHERE entity IN (0,".$conf->entity.")";
811
+        if ($elementtype) $sql.= " AND elementtype = '".$elementtype."'";	// Filed with object->table_element
812
+        $sql.= " ORDER BY pos";
813
+
814
+        $resql=$this->db->query($sql);
815
+        if ($resql)
816
+        {
817
+            if ($this->db->num_rows($resql))
818
+            {
819
+                while ($tab = $this->db->fetch_object($resql))
820
+                {
821
+                    // We can add this attribute to object. TODO Remove this and return $this->attributes[$elementtype]['label']
822
+                    if ($tab->type != 'separate')
823
+                    {
824
+                        $array_name_label[$tab->name]=$tab->label;
825
+                    }
826
+
827
+                    // Old usage
828
+                    $this->attribute_type[$tab->name]=$tab->type;
829
+                    $this->attribute_label[$tab->name]=$tab->label;
830
+                    $this->attribute_size[$tab->name]=$tab->size;
831
+                    $this->attribute_elementtype[$tab->name]=$tab->elementtype;
832
+                    $this->attribute_default[$tab->name]=$tab->fielddefault;
833
+                    $this->attribute_computed[$tab->name]=$tab->fieldcomputed;
834
+                    $this->attribute_unique[$tab->name]=$tab->fieldunique;
835
+                    $this->attribute_required[$tab->name]=$tab->fieldrequired;
836
+                    $this->attribute_param[$tab->name]=($tab->param ? unserialize($tab->param) : '');
837
+                    $this->attribute_pos[$tab->name]=$tab->pos;
838
+                    $this->attribute_alwayseditable[$tab->name]=$tab->alwayseditable;
839
+                    $this->attribute_perms[$tab->name]=(strlen($tab->perms) == 0 ? 1 : $tab->perms);
840
+                    $this->attribute_langfile[$tab->name]=$tab->langs;
841
+                    $this->attribute_list[$tab->name]=$tab->list;
842
+                    $this->attribute_totalizable[$tab->name]=$tab->totalizable;
843
+                    $this->attribute_entityid[$tab->name]=$tab->entity;
844
+                    $this->attribute_entitylabel[$tab->name]=(empty($labelmulticompany[$tab->entity])?'Entity'.$tab->entity:$labelmulticompany[$tab->entity]);
845
+
846
+                    // New usage
847
+                    $this->attributes[$tab->elementtype]['type'][$tab->name]=$tab->type;
848
+                    $this->attributes[$tab->elementtype]['label'][$tab->name]=$tab->label;
849
+                    $this->attributes[$tab->elementtype]['size'][$tab->name]=$tab->size;
850
+                    $this->attributes[$tab->elementtype]['elementtype'][$tab->name]=$tab->elementtype;
851
+                    $this->attributes[$tab->elementtype]['default'][$tab->name]=$tab->fielddefault;
852
+                    $this->attributes[$tab->elementtype]['computed'][$tab->name]=$tab->fieldcomputed;
853
+                    $this->attributes[$tab->elementtype]['unique'][$tab->name]=$tab->fieldunique;
854
+                    $this->attributes[$tab->elementtype]['required'][$tab->name]=$tab->fieldrequired;
855
+                    $this->attributes[$tab->elementtype]['param'][$tab->name]=($tab->param ? unserialize($tab->param) : '');
856
+                    $this->attributes[$tab->elementtype]['pos'][$tab->name]=$tab->pos;
857
+                    $this->attributes[$tab->elementtype]['alwayseditable'][$tab->name]=$tab->alwayseditable;
858
+                    $this->attributes[$tab->elementtype]['perms'][$tab->name]=(strlen($tab->perms) == 0 ? 1 : $tab->perms);
859
+                    $this->attributes[$tab->elementtype]['langfile'][$tab->name]=$tab->langs;
860
+                    $this->attributes[$tab->elementtype]['list'][$tab->name]=$tab->list;
861 861
                     $this->attributes[$tab->elementtype]['totalizable'][$tab->name]=$tab->totalizable;
862
-					$this->attributes[$tab->elementtype]['entityid'][$tab->name]=$tab->entity;
863
-					$this->attributes[$tab->elementtype]['entitylabel'][$tab->name]=(empty($labelmulticompany[$tab->entity])?'Entity'.$tab->entity:$labelmulticompany[$tab->entity]);
864
-					$this->attributes[$tab->elementtype]['enabled'][$tab->name]=$tab->enabled;
865
-					$this->attributes[$tab->elementtype]['help'][$tab->name]=$tab->help;
866
-
867
-					$this->attributes[$tab->elementtype]['loaded']=1;
868
-				}
869
-			}
870
-			if ($elementtype) $this->attributes[$elementtype]['loaded']=1;	// If nothing found, we also save tag 'loaded'
871
-		}
872
-		else
873
-		{
874
-			$this->error=$this->db->lasterror();
875
-			dol_syslog(get_class($this)."::fetch_name_optionals_label ".$this->error, LOG_ERR);
876
-		}
877
-
878
-		return $array_name_label;
879
-	}
880
-
881
-
882
-	/**
883
-	 * Return HTML string to put an input field into a page
884
-	 * Code very similar with showInputField of common object
885
-	 *
886
-	 * @param  string  $key            			Key of attribute
887
-	 * @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)
888
-	 * @param  string  $moreparam      			To add more parametes on html input tag
889
-	 * @param  string  $keysuffix      			Prefix string to add after name and id of field (can be used to avoid duplicate names)
890
-	 * @param  string  $keyprefix      			Suffix string to add before name and id of field (can be used to avoid duplicate names)
891
-	 * @param  string  $morecss        			More css (to defined size of field. Old behaviour: may also be a numeric)
892
-	 * @param  int     $objectid       			Current object id
893
-	 * @param  string  $extrafieldsobjectkey	If defined (for example $object->table_element), use the new method to get extrafields data
894
-	 * @return string
895
-	 */
896
-	function showInputField($key, $value, $moreparam='', $keysuffix='', $keyprefix='', $morecss='', $objectid=0, $extrafieldsobjectkey='')
897
-	{
898
-		global $conf,$langs,$form;
899
-
900
-		if (! is_object($form))
901
-		{
902
-			require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
903
-			$form=new Form($this->db);
904
-		}
905
-
906
-		$out='';
907
-
908
-		$keyprefix = $keyprefix.'options_';		// Because we work on extrafields
909
-
910
-		if (! empty($extrafieldsobjectkey))
911
-		{
912
-			$label=$this->attributes[$extrafieldsobjectkey]['label'][$key];
913
-			$type=$this->attributes[$extrafieldsobjectkey]['type'][$key];
914
-			$size=$this->attributes[$extrafieldsobjectkey]['size'][$key];
915
-			$default=$this->attributes[$extrafieldsobjectkey]['default'][$key];
916
-			$computed=$this->attributes[$extrafieldsobjectkey]['computed'][$key];
917
-			$unique=$this->attributes[$extrafieldsobjectkey]['unique'][$key];
918
-			$required=$this->attributes[$extrafieldsobjectkey]['required'][$key];
919
-			$param=$this->attributes[$extrafieldsobjectkey]['param'][$key];
920
-			$perms=dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1);
921
-			$langfile=$this->attributes[$extrafieldsobjectkey]['langfile'][$key];
922
-			$list=dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1);
923
-			$totalizable=$this->attributes[$extrafieldsobjectkey]['totalizable'][$key];
924
-			$help=$this->attributes[$extrafieldsobjectkey]['help'][$key];
925
-			$hidden=(empty($list) ? 1 : 0);		// If empty, 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)
926
-		}
927
-		else	// Old usage
928
-		{
929
-			$label=$this->attribute_label[$key];
930
-			$type =$this->attribute_type[$key];
931
-			$size =$this->attribute_size[$key];
932
-			$elementtype=$this->attribute_elementtype[$key];	// Seems not used
933
-			$default=$this->attribute_default[$key];
934
-			$computed=$this->attribute_computed[$key];
935
-			$unique=$this->attribute_unique[$key];
936
-			$required=$this->attribute_required[$key];
937
-			$param=$this->attribute_param[$key];
938
-			$langfile=$this->attribute_langfile[$key];
939
-			$list=$this->attribute_list[$key];
940
-			$totalizable=$this->attribute_totalizable[$key];
941
-			$hidden=(empty($list) ? 1 : 0);		// If empty, 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)
942
-		}
943
-
944
-		if ($computed)
945
-		{
946
-			if (! preg_match('/^search_/', $keyprefix)) return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
947
-			else return '';
948
-		}
949
-
950
-		if (empty($morecss))
951
-		{
952
-			if ($type == 'date')
953
-			{
954
-				$morecss = 'minwidth100imp';
955
-			}
956
-			elseif ($type == 'datetime')
957
-			{
958
-				$morecss = 'minwidth200imp';
959
-			}
960
-			elseif (in_array($type,array('int','integer','double','price')))
961
-			{
962
-				$morecss = 'maxwidth75';
963
-			}
964
-			elseif ($type == 'password')
965
-			{
966
-				$morecss='maxwidth100';
967
-			}
968
-			elseif ($type == 'url')
969
-			{
970
-				$morecss='minwidth400';
971
-			}
972
-			elseif ($type == 'boolean')
973
-			{
974
-				$morecss='';
975
-			}
976
-			else
977
-			{
978
-				if (round($size) < 12)
979
-				{
980
-					$morecss = 'minwidth100';
981
-				}
982
-				else if (round($size) <= 48)
983
-				{
984
-					$morecss = 'minwidth200';
985
-				}
986
-				else
987
-				{
988
-					$morecss = 'minwidth400';
989
-				}
990
-			}
991
-		}
992
-
993
-		if (in_array($type,array('date','datetime')))
994
-		{
995
-			$tmp=explode(',',$size);
996
-			$newsize=$tmp[0];
997
-
998
-			$showtime = in_array($type,array('datetime')) ? 1 : 0;
999
-
1000
-			// Do not show current date when field not required (see selectDate() method)
1001
-			if (!$required && $value == '') $value = '-1';
1002
-
1003
-			// TODO Must also support $moreparam
1004
-			$out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
1005
-		}
1006
-		elseif (in_array($type,array('int','integer')))
1007
-		{
1008
-			$tmp=explode(',',$size);
1009
-			$newsize=$tmp[0];
1010
-			$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:'').'>';
1011
-		}
1012
-		elseif (preg_match('/varchar/', $type))
1013
-		{
1014
-			$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:'').'>';
1015
-		}
1016
-		elseif (in_array($type, array('mail', 'phone', 'url')))
1017
-		{
1018
-			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
1019
-		}
1020
-		elseif ($type == 'text')
1021
-		{
1022
-			if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
1023
-			{
1024
-				require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1025
-				$doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,false,ROWS_5,'90%');
1026
-				$out=$doleditor->Create(1);
1027
-			}
1028
-			else
1029
-			{
1030
-				$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
1031
-			}
1032
-		}
1033
-		elseif ($type == 'html')
1034
-		{
1035
-			if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
1036
-			{
1037
-				require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1038
-				$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%');
1039
-				$out=$doleditor->Create(1);
1040
-			}
1041
-			else
1042
-			{
1043
-				$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
1044
-			}
1045
-		}
1046
-		elseif ($type == 'boolean')
1047
-		{
1048
-			$checked='';
1049
-			if (!empty($value)) {
1050
-				$checked=' checked value="1" ';
1051
-			} else {
1052
-				$checked=' value="1" ';
1053
-			}
1054
-			$out='<input type="checkbox" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam?$moreparam:'').'>';
1055
-		}
1056
-		elseif ($type == 'price')
1057
-		{
1058
-			if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
1059
-				$value=price($value);
1060
-			}
1061
-			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> '.$langs->getCurrencySymbol($conf->currency);
1062
-		}
1063
-		elseif ($type == 'double')
1064
-		{
1065
-			if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
1066
-				$value=price($value);
1067
-			}
1068
-			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> ';
1069
-		}
1070
-		elseif ($type == 'select')
1071
-		{
1072
-			$out = '';
1073
-			if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
1074
-			{
1075
-				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1076
-				$out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
1077
-			}
1078
-
1079
-			$out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
1080
-			$out.='<option value="0">&nbsp;</option>';
1081
-			foreach ($param['options'] as $key => $val)
1082
-			{
1083
-				if ((string) $key == '') continue;
1084
-				list($val, $parent) = explode('|', $val);
1085
-				$out.='<option value="'.$key.'"';
1086
-				$out.= (((string) $value == (string) $key)?' selected':'');
1087
-				$out.= (!empty($parent)?' parent="'.$parent.'"':'');
1088
-				$out.='>';
1089
-				if ($langfile && $val) $out.=$langs->trans($val);
1090
-				else $out.=$val;
1091
-				$out.='</option>';
1092
-			}
1093
-			$out.='</select>';
1094
-		}
1095
-		elseif ($type == 'sellist')
1096
-		{
1097
-			$out = '';
1098
-			if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
1099
-			{
1100
-				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1101
-				$out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
1102
-			}
1103
-
1104
-			$out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
1105
-			if (is_array($param['options']))
1106
-			{
1107
-				$param_list=array_keys($param['options']);
1108
-				$InfoFieldList = explode(":", $param_list[0]);
1109
-				$parentName='';
1110
-				$parentField='';
1111
-				// 0 : tableName
1112
-				// 1 : label field name
1113
-				// 2 : key fields name (if differ of rowid)
1114
-				// 3 : key field parent (for dependent lists)
1115
-				// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
1116
-				$keyList=(empty($InfoFieldList[2])?'rowid':$InfoFieldList[2].' as rowid');
1117
-
1118
-
1119
-				if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4]))
1120
-				{
1121
-					if (strpos($InfoFieldList[4], 'extra.') !== false)
1122
-					{
1123
-						$keyList='main.'.$InfoFieldList[2].' as rowid';
1124
-					} else {
1125
-						$keyList=$InfoFieldList[2].' as rowid';
1126
-					}
1127
-				}
1128
-				if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3]))
1129
-				{
1130
-					list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
1131
-					$keyList.= ', '.$parentField;
1132
-				}
1133
-
1134
-				$fields_label = explode('|',$InfoFieldList[1]);
1135
-				if (is_array($fields_label))
1136
-				{
1137
-					$keyList .=', ';
1138
-					$keyList .= implode(', ', $fields_label);
1139
-				}
1140
-
1141
-				$sqlwhere='';
1142
-				$sql = 'SELECT '.$keyList;
1143
-				$sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
1144
-				if (!empty($InfoFieldList[4]))
1145
-				{
1146
-				    // can use curent entity filter
1147
-				    if (strpos($InfoFieldList[4], '$ENTITY$')!==false) {
1148
-				        $InfoFieldList[4]=str_replace('$ENTITY$',$conf->entity,$InfoFieldList[4]);
1149
-				    }
1150
-					// can use SELECT request
1151
-					if (strpos($InfoFieldList[4], '$SEL$')!==false) {
1152
-						$InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
1153
-					}
1154
-
1155
-					// current object id can be use into filter
1156
-					if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
1157
-						$InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
1158
-					} else {
1159
-						$InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
1160
-					}
1161
-					//We have to join on extrafield table
1162
-					if (strpos($InfoFieldList[4], 'extra')!==false)
1163
-					{
1164
-						$sql.= ' as main, '.MAIN_DB_PREFIX .$InfoFieldList[0].'_extrafields as extra';
1165
-						$sqlwhere.= ' WHERE extra.fk_object=main.'.$InfoFieldList[2]. ' AND '.$InfoFieldList[4];
1166
-					}
1167
-					else
1168
-					{
1169
-						$sqlwhere.= ' WHERE '.$InfoFieldList[4];
1170
-					}
1171
-				}
1172
-				else
1173
-				{
1174
-					$sqlwhere.= ' WHERE 1=1';
1175
-				}
1176
-				// Some tables may have field, some other not. For the moment we disable it.
1177
-				if (in_array($InfoFieldList[0],array('tablewithentity')))
1178
-				{
1179
-					$sqlwhere.= ' AND entity = '.$conf->entity;
1180
-				}
1181
-				$sql.=$sqlwhere;
1182
-				//print $sql;
1183
-
1184
-				$sql .= ' ORDER BY ' . implode(', ', $fields_label);
1185
-
1186
-				dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
1187
-				$resql = $this->db->query($sql);
1188
-				if ($resql)
1189
-				{
1190
-					$out.='<option value="0">&nbsp;</option>';
1191
-					$num = $this->db->num_rows($resql);
1192
-					$i = 0;
1193
-					while ($i < $num)
1194
-					{
1195
-						$labeltoshow='';
1196
-						$obj = $this->db->fetch_object($resql);
1197
-
1198
-						// Several field into label (eq table:code|libelle:rowid)
1199
-						$notrans = false;
1200
-						$fields_label = explode('|',$InfoFieldList[1]);
1201
-						if (is_array($fields_label))
1202
-						{
1203
-							$notrans = true;
1204
-							foreach ($fields_label as $field_toshow)
1205
-							{
1206
-								$labeltoshow.= $obj->$field_toshow.' ';
1207
-							}
1208
-						}
1209
-						else
1210
-						{
1211
-							$labeltoshow=$obj->{$InfoFieldList[1]};
1212
-						}
1213
-						$labeltoshow=dol_trunc($labeltoshow,45);
1214
-
1215
-						if ($value == $obj->rowid)
1216
-						{
1217
-							foreach ($fields_label as $field_toshow)
1218
-							{
1219
-								$translabel=$langs->trans($obj->$field_toshow);
1220
-								if ($translabel!=$obj->$field_toshow) {
1221
-									$labeltoshow=dol_trunc($translabel,18).' ';
1222
-								}else {
1223
-									$labeltoshow=dol_trunc($obj->$field_toshow,18).' ';
1224
-								}
1225
-							}
1226
-							$out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
1227
-						}
1228
-						else
1229
-						{
1230
-							if (! $notrans)
1231
-							{
1232
-								$translabel=$langs->trans($obj->{$InfoFieldList[1]});
1233
-								if ($translabel!=$obj->{$InfoFieldList[1]}) {
1234
-									$labeltoshow=dol_trunc($translabel,18);
1235
-								}
1236
-								else {
1237
-									$labeltoshow=dol_trunc($obj->{$InfoFieldList[1]},18);
1238
-								}
1239
-							}
1240
-							if (empty($labeltoshow)) $labeltoshow='(not defined)';
1241
-							if ($value==$obj->rowid)
1242
-							{
1243
-								$out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
1244
-							}
1245
-
1246
-							if (!empty($InfoFieldList[3]) && $parentField)
1247
-							{
1248
-								$parent = $parentName.':'.$obj->{$parentField};
1249
-							}
1250
-
1251
-							$out.='<option value="'.$obj->rowid.'"';
1252
-							$out.= ($value==$obj->rowid?' selected':'');
1253
-							$out.= (!empty($parent)?' parent="'.$parent.'"':'');
1254
-							$out.='>'.$labeltoshow.'</option>';
1255
-						}
1256
-
1257
-						$i++;
1258
-					}
1259
-					$this->db->free($resql);
1260
-				}
1261
-				else {
1262
-					print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
1263
-				}
1264
-			}
1265
-			$out.='</select>';
1266
-		}
1267
-		elseif ($type == 'checkbox')
1268
-		{
1269
-			$value_arr=explode(',',$value);
1270
-			$out=$form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options'])?null:$param['options']), $value_arr, '', 0, '', 0, '100%');
1271
-		}
1272
-		elseif ($type == 'radio')
1273
-		{
1274
-			$out='';
1275
-			foreach ($param['options'] as $keyopt => $val)
1276
-			{
1277
-				$out.='<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'');
1278
-				$out.=' value="'.$keyopt.'"';
1279
-				$out.=' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
1280
-				$out.= ($value==$keyopt?'checked':'');
1281
-				$out.='/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$val.'</label><br>';
1282
-			}
1283
-		}
1284
-		elseif ($type == 'chkbxlst')
1285
-		{
1286
-			if (is_array($value)) {
1287
-				$value_arr = $value;
1288
-			}
1289
-			else {
1290
-				$value_arr = explode(',', $value);
1291
-			}
1292
-
1293
-			if (is_array($param['options'])) {
1294
-				$param_list = array_keys($param['options']);
1295
-				$InfoFieldList = explode(":", $param_list[0]);
1296
-				$parentName='';
1297
-				$parentField='';
1298
-				// 0 : tableName
1299
-				// 1 : label field name
1300
-				// 2 : key fields name (if differ of rowid)
1301
-				// 3 : key field parent (for dependent lists)
1302
-				// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
1303
-				$keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
1304
-
1305
-				if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3])) {
1306
-					list ( $parentName, $parentField ) = explode('|', $InfoFieldList[3]);
1307
-					$keyList .= ', ' . $parentField;
1308
-				}
1309
-				if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4])) {
1310
-					if (strpos($InfoFieldList[4], 'extra.') !== false) {
1311
-						$keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
1312
-					} else {
1313
-						$keyList = $InfoFieldList[2] . ' as rowid';
1314
-					}
1315
-				}
1316
-
1317
-				$fields_label = explode('|', $InfoFieldList[1]);
1318
-				if (is_array($fields_label)) {
1319
-					$keyList .= ', ';
1320
-					$keyList .= implode(', ', $fields_label);
1321
-				}
1322
-
1323
-				$sqlwhere = '';
1324
-				$sql = 'SELECT ' . $keyList;
1325
-				$sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
1326
-				if (! empty($InfoFieldList[4])) {
1327
-
1328
-					// can use SELECT request
1329
-					if (strpos($InfoFieldList[4], '$SEL$')!==false) {
1330
-						$InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
1331
-					}
1332
-
1333
-					// current object id can be use into filter
1334
-					if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
1335
-						$InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
1336
-					} else if (preg_match("#^.*list.php$#",$_SERVER["DOCUMENT_URI"])) {
1337
-						// Pattern for word=$ID$
1338
-						$word = '\b[a-zA-Z0-9-\.-_]+\b=\$ID\$';
862
+                    $this->attributes[$tab->elementtype]['entityid'][$tab->name]=$tab->entity;
863
+                    $this->attributes[$tab->elementtype]['entitylabel'][$tab->name]=(empty($labelmulticompany[$tab->entity])?'Entity'.$tab->entity:$labelmulticompany[$tab->entity]);
864
+                    $this->attributes[$tab->elementtype]['enabled'][$tab->name]=$tab->enabled;
865
+                    $this->attributes[$tab->elementtype]['help'][$tab->name]=$tab->help;
866
+
867
+                    $this->attributes[$tab->elementtype]['loaded']=1;
868
+                }
869
+            }
870
+            if ($elementtype) $this->attributes[$elementtype]['loaded']=1;	// If nothing found, we also save tag 'loaded'
871
+        }
872
+        else
873
+        {
874
+            $this->error=$this->db->lasterror();
875
+            dol_syslog(get_class($this)."::fetch_name_optionals_label ".$this->error, LOG_ERR);
876
+        }
877
+
878
+        return $array_name_label;
879
+    }
880
+
881
+
882
+    /**
883
+     * Return HTML string to put an input field into a page
884
+     * Code very similar with showInputField of common object
885
+     *
886
+     * @param  string  $key            			Key of attribute
887
+     * @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)
888
+     * @param  string  $moreparam      			To add more parametes on html input tag
889
+     * @param  string  $keysuffix      			Prefix string to add after name and id of field (can be used to avoid duplicate names)
890
+     * @param  string  $keyprefix      			Suffix string to add before name and id of field (can be used to avoid duplicate names)
891
+     * @param  string  $morecss        			More css (to defined size of field. Old behaviour: may also be a numeric)
892
+     * @param  int     $objectid       			Current object id
893
+     * @param  string  $extrafieldsobjectkey	If defined (for example $object->table_element), use the new method to get extrafields data
894
+     * @return string
895
+     */
896
+    function showInputField($key, $value, $moreparam='', $keysuffix='', $keyprefix='', $morecss='', $objectid=0, $extrafieldsobjectkey='')
897
+    {
898
+        global $conf,$langs,$form;
899
+
900
+        if (! is_object($form))
901
+        {
902
+            require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
903
+            $form=new Form($this->db);
904
+        }
905
+
906
+        $out='';
907
+
908
+        $keyprefix = $keyprefix.'options_';		// Because we work on extrafields
909
+
910
+        if (! empty($extrafieldsobjectkey))
911
+        {
912
+            $label=$this->attributes[$extrafieldsobjectkey]['label'][$key];
913
+            $type=$this->attributes[$extrafieldsobjectkey]['type'][$key];
914
+            $size=$this->attributes[$extrafieldsobjectkey]['size'][$key];
915
+            $default=$this->attributes[$extrafieldsobjectkey]['default'][$key];
916
+            $computed=$this->attributes[$extrafieldsobjectkey]['computed'][$key];
917
+            $unique=$this->attributes[$extrafieldsobjectkey]['unique'][$key];
918
+            $required=$this->attributes[$extrafieldsobjectkey]['required'][$key];
919
+            $param=$this->attributes[$extrafieldsobjectkey]['param'][$key];
920
+            $perms=dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1);
921
+            $langfile=$this->attributes[$extrafieldsobjectkey]['langfile'][$key];
922
+            $list=dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1);
923
+            $totalizable=$this->attributes[$extrafieldsobjectkey]['totalizable'][$key];
924
+            $help=$this->attributes[$extrafieldsobjectkey]['help'][$key];
925
+            $hidden=(empty($list) ? 1 : 0);		// If empty, 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)
926
+        }
927
+        else	// Old usage
928
+        {
929
+            $label=$this->attribute_label[$key];
930
+            $type =$this->attribute_type[$key];
931
+            $size =$this->attribute_size[$key];
932
+            $elementtype=$this->attribute_elementtype[$key];	// Seems not used
933
+            $default=$this->attribute_default[$key];
934
+            $computed=$this->attribute_computed[$key];
935
+            $unique=$this->attribute_unique[$key];
936
+            $required=$this->attribute_required[$key];
937
+            $param=$this->attribute_param[$key];
938
+            $langfile=$this->attribute_langfile[$key];
939
+            $list=$this->attribute_list[$key];
940
+            $totalizable=$this->attribute_totalizable[$key];
941
+            $hidden=(empty($list) ? 1 : 0);		// If empty, 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)
942
+        }
943
+
944
+        if ($computed)
945
+        {
946
+            if (! preg_match('/^search_/', $keyprefix)) return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
947
+            else return '';
948
+        }
949
+
950
+        if (empty($morecss))
951
+        {
952
+            if ($type == 'date')
953
+            {
954
+                $morecss = 'minwidth100imp';
955
+            }
956
+            elseif ($type == 'datetime')
957
+            {
958
+                $morecss = 'minwidth200imp';
959
+            }
960
+            elseif (in_array($type,array('int','integer','double','price')))
961
+            {
962
+                $morecss = 'maxwidth75';
963
+            }
964
+            elseif ($type == 'password')
965
+            {
966
+                $morecss='maxwidth100';
967
+            }
968
+            elseif ($type == 'url')
969
+            {
970
+                $morecss='minwidth400';
971
+            }
972
+            elseif ($type == 'boolean')
973
+            {
974
+                $morecss='';
975
+            }
976
+            else
977
+            {
978
+                if (round($size) < 12)
979
+                {
980
+                    $morecss = 'minwidth100';
981
+                }
982
+                else if (round($size) <= 48)
983
+                {
984
+                    $morecss = 'minwidth200';
985
+                }
986
+                else
987
+                {
988
+                    $morecss = 'minwidth400';
989
+                }
990
+            }
991
+        }
992
+
993
+        if (in_array($type,array('date','datetime')))
994
+        {
995
+            $tmp=explode(',',$size);
996
+            $newsize=$tmp[0];
997
+
998
+            $showtime = in_array($type,array('datetime')) ? 1 : 0;
999
+
1000
+            // Do not show current date when field not required (see selectDate() method)
1001
+            if (!$required && $value == '') $value = '-1';
1002
+
1003
+            // TODO Must also support $moreparam
1004
+            $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
1005
+        }
1006
+        elseif (in_array($type,array('int','integer')))
1007
+        {
1008
+            $tmp=explode(',',$size);
1009
+            $newsize=$tmp[0];
1010
+            $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:'').'>';
1011
+        }
1012
+        elseif (preg_match('/varchar/', $type))
1013
+        {
1014
+            $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:'').'>';
1015
+        }
1016
+        elseif (in_array($type, array('mail', 'phone', 'url')))
1017
+        {
1018
+            $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
1019
+        }
1020
+        elseif ($type == 'text')
1021
+        {
1022
+            if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
1023
+            {
1024
+                require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1025
+                $doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,false,ROWS_5,'90%');
1026
+                $out=$doleditor->Create(1);
1027
+            }
1028
+            else
1029
+            {
1030
+                $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
1031
+            }
1032
+        }
1033
+        elseif ($type == 'html')
1034
+        {
1035
+            if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
1036
+            {
1037
+                require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1038
+                $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%');
1039
+                $out=$doleditor->Create(1);
1040
+            }
1041
+            else
1042
+            {
1043
+                $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
1044
+            }
1045
+        }
1046
+        elseif ($type == 'boolean')
1047
+        {
1048
+            $checked='';
1049
+            if (!empty($value)) {
1050
+                $checked=' checked value="1" ';
1051
+            } else {
1052
+                $checked=' value="1" ';
1053
+            }
1054
+            $out='<input type="checkbox" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam?$moreparam:'').'>';
1055
+        }
1056
+        elseif ($type == 'price')
1057
+        {
1058
+            if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
1059
+                $value=price($value);
1060
+            }
1061
+            $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> '.$langs->getCurrencySymbol($conf->currency);
1062
+        }
1063
+        elseif ($type == 'double')
1064
+        {
1065
+            if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
1066
+                $value=price($value);
1067
+            }
1068
+            $out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> ';
1069
+        }
1070
+        elseif ($type == 'select')
1071
+        {
1072
+            $out = '';
1073
+            if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
1074
+            {
1075
+                include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1076
+                $out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
1077
+            }
1078
+
1079
+            $out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
1080
+            $out.='<option value="0">&nbsp;</option>';
1081
+            foreach ($param['options'] as $key => $val)
1082
+            {
1083
+                if ((string) $key == '') continue;
1084
+                list($val, $parent) = explode('|', $val);
1085
+                $out.='<option value="'.$key.'"';
1086
+                $out.= (((string) $value == (string) $key)?' selected':'');
1087
+                $out.= (!empty($parent)?' parent="'.$parent.'"':'');
1088
+                $out.='>';
1089
+                if ($langfile && $val) $out.=$langs->trans($val);
1090
+                else $out.=$val;
1091
+                $out.='</option>';
1092
+            }
1093
+            $out.='</select>';
1094
+        }
1095
+        elseif ($type == 'sellist')
1096
+        {
1097
+            $out = '';
1098
+            if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
1099
+            {
1100
+                include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1101
+                $out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
1102
+            }
1103
+
1104
+            $out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
1105
+            if (is_array($param['options']))
1106
+            {
1107
+                $param_list=array_keys($param['options']);
1108
+                $InfoFieldList = explode(":", $param_list[0]);
1109
+                $parentName='';
1110
+                $parentField='';
1111
+                // 0 : tableName
1112
+                // 1 : label field name
1113
+                // 2 : key fields name (if differ of rowid)
1114
+                // 3 : key field parent (for dependent lists)
1115
+                // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
1116
+                $keyList=(empty($InfoFieldList[2])?'rowid':$InfoFieldList[2].' as rowid');
1117
+
1118
+
1119
+                if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4]))
1120
+                {
1121
+                    if (strpos($InfoFieldList[4], 'extra.') !== false)
1122
+                    {
1123
+                        $keyList='main.'.$InfoFieldList[2].' as rowid';
1124
+                    } else {
1125
+                        $keyList=$InfoFieldList[2].' as rowid';
1126
+                    }
1127
+                }
1128
+                if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3]))
1129
+                {
1130
+                    list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
1131
+                    $keyList.= ', '.$parentField;
1132
+                }
1133
+
1134
+                $fields_label = explode('|',$InfoFieldList[1]);
1135
+                if (is_array($fields_label))
1136
+                {
1137
+                    $keyList .=', ';
1138
+                    $keyList .= implode(', ', $fields_label);
1139
+                }
1140
+
1141
+                $sqlwhere='';
1142
+                $sql = 'SELECT '.$keyList;
1143
+                $sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
1144
+                if (!empty($InfoFieldList[4]))
1145
+                {
1146
+                    // can use curent entity filter
1147
+                    if (strpos($InfoFieldList[4], '$ENTITY$')!==false) {
1148
+                        $InfoFieldList[4]=str_replace('$ENTITY$',$conf->entity,$InfoFieldList[4]);
1149
+                    }
1150
+                    // can use SELECT request
1151
+                    if (strpos($InfoFieldList[4], '$SEL$')!==false) {
1152
+                        $InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
1153
+                    }
1154
+
1155
+                    // current object id can be use into filter
1156
+                    if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
1157
+                        $InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
1158
+                    } else {
1159
+                        $InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
1160
+                    }
1161
+                    //We have to join on extrafield table
1162
+                    if (strpos($InfoFieldList[4], 'extra')!==false)
1163
+                    {
1164
+                        $sql.= ' as main, '.MAIN_DB_PREFIX .$InfoFieldList[0].'_extrafields as extra';
1165
+                        $sqlwhere.= ' WHERE extra.fk_object=main.'.$InfoFieldList[2]. ' AND '.$InfoFieldList[4];
1166
+                    }
1167
+                    else
1168
+                    {
1169
+                        $sqlwhere.= ' WHERE '.$InfoFieldList[4];
1170
+                    }
1171
+                }
1172
+                else
1173
+                {
1174
+                    $sqlwhere.= ' WHERE 1=1';
1175
+                }
1176
+                // Some tables may have field, some other not. For the moment we disable it.
1177
+                if (in_array($InfoFieldList[0],array('tablewithentity')))
1178
+                {
1179
+                    $sqlwhere.= ' AND entity = '.$conf->entity;
1180
+                }
1181
+                $sql.=$sqlwhere;
1182
+                //print $sql;
1183
+
1184
+                $sql .= ' ORDER BY ' . implode(', ', $fields_label);
1185
+
1186
+                dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
1187
+                $resql = $this->db->query($sql);
1188
+                if ($resql)
1189
+                {
1190
+                    $out.='<option value="0">&nbsp;</option>';
1191
+                    $num = $this->db->num_rows($resql);
1192
+                    $i = 0;
1193
+                    while ($i < $num)
1194
+                    {
1195
+                        $labeltoshow='';
1196
+                        $obj = $this->db->fetch_object($resql);
1197
+
1198
+                        // Several field into label (eq table:code|libelle:rowid)
1199
+                        $notrans = false;
1200
+                        $fields_label = explode('|',$InfoFieldList[1]);
1201
+                        if (is_array($fields_label))
1202
+                        {
1203
+                            $notrans = true;
1204
+                            foreach ($fields_label as $field_toshow)
1205
+                            {
1206
+                                $labeltoshow.= $obj->$field_toshow.' ';
1207
+                            }
1208
+                        }
1209
+                        else
1210
+                        {
1211
+                            $labeltoshow=$obj->{$InfoFieldList[1]};
1212
+                        }
1213
+                        $labeltoshow=dol_trunc($labeltoshow,45);
1214
+
1215
+                        if ($value == $obj->rowid)
1216
+                        {
1217
+                            foreach ($fields_label as $field_toshow)
1218
+                            {
1219
+                                $translabel=$langs->trans($obj->$field_toshow);
1220
+                                if ($translabel!=$obj->$field_toshow) {
1221
+                                    $labeltoshow=dol_trunc($translabel,18).' ';
1222
+                                }else {
1223
+                                    $labeltoshow=dol_trunc($obj->$field_toshow,18).' ';
1224
+                                }
1225
+                            }
1226
+                            $out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
1227
+                        }
1228
+                        else
1229
+                        {
1230
+                            if (! $notrans)
1231
+                            {
1232
+                                $translabel=$langs->trans($obj->{$InfoFieldList[1]});
1233
+                                if ($translabel!=$obj->{$InfoFieldList[1]}) {
1234
+                                    $labeltoshow=dol_trunc($translabel,18);
1235
+                                }
1236
+                                else {
1237
+                                    $labeltoshow=dol_trunc($obj->{$InfoFieldList[1]},18);
1238
+                                }
1239
+                            }
1240
+                            if (empty($labeltoshow)) $labeltoshow='(not defined)';
1241
+                            if ($value==$obj->rowid)
1242
+                            {
1243
+                                $out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
1244
+                            }
1245
+
1246
+                            if (!empty($InfoFieldList[3]) && $parentField)
1247
+                            {
1248
+                                $parent = $parentName.':'.$obj->{$parentField};
1249
+                            }
1250
+
1251
+                            $out.='<option value="'.$obj->rowid.'"';
1252
+                            $out.= ($value==$obj->rowid?' selected':'');
1253
+                            $out.= (!empty($parent)?' parent="'.$parent.'"':'');
1254
+                            $out.='>'.$labeltoshow.'</option>';
1255
+                        }
1256
+
1257
+                        $i++;
1258
+                    }
1259
+                    $this->db->free($resql);
1260
+                }
1261
+                else {
1262
+                    print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
1263
+                }
1264
+            }
1265
+            $out.='</select>';
1266
+        }
1267
+        elseif ($type == 'checkbox')
1268
+        {
1269
+            $value_arr=explode(',',$value);
1270
+            $out=$form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options'])?null:$param['options']), $value_arr, '', 0, '', 0, '100%');
1271
+        }
1272
+        elseif ($type == 'radio')
1273
+        {
1274
+            $out='';
1275
+            foreach ($param['options'] as $keyopt => $val)
1276
+            {
1277
+                $out.='<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'');
1278
+                $out.=' value="'.$keyopt.'"';
1279
+                $out.=' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
1280
+                $out.= ($value==$keyopt?'checked':'');
1281
+                $out.='/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$val.'</label><br>';
1282
+            }
1283
+        }
1284
+        elseif ($type == 'chkbxlst')
1285
+        {
1286
+            if (is_array($value)) {
1287
+                $value_arr = $value;
1288
+            }
1289
+            else {
1290
+                $value_arr = explode(',', $value);
1291
+            }
1292
+
1293
+            if (is_array($param['options'])) {
1294
+                $param_list = array_keys($param['options']);
1295
+                $InfoFieldList = explode(":", $param_list[0]);
1296
+                $parentName='';
1297
+                $parentField='';
1298
+                // 0 : tableName
1299
+                // 1 : label field name
1300
+                // 2 : key fields name (if differ of rowid)
1301
+                // 3 : key field parent (for dependent lists)
1302
+                // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
1303
+                $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
1304
+
1305
+                if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3])) {
1306
+                    list ( $parentName, $parentField ) = explode('|', $InfoFieldList[3]);
1307
+                    $keyList .= ', ' . $parentField;
1308
+                }
1309
+                if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4])) {
1310
+                    if (strpos($InfoFieldList[4], 'extra.') !== false) {
1311
+                        $keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
1312
+                    } else {
1313
+                        $keyList = $InfoFieldList[2] . ' as rowid';
1314
+                    }
1315
+                }
1316
+
1317
+                $fields_label = explode('|', $InfoFieldList[1]);
1318
+                if (is_array($fields_label)) {
1319
+                    $keyList .= ', ';
1320
+                    $keyList .= implode(', ', $fields_label);
1321
+                }
1322
+
1323
+                $sqlwhere = '';
1324
+                $sql = 'SELECT ' . $keyList;
1325
+                $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
1326
+                if (! empty($InfoFieldList[4])) {
1327
+
1328
+                    // can use SELECT request
1329
+                    if (strpos($InfoFieldList[4], '$SEL$')!==false) {
1330
+                        $InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
1331
+                    }
1332
+
1333
+                    // current object id can be use into filter
1334
+                    if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
1335
+                        $InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
1336
+                    } else if (preg_match("#^.*list.php$#",$_SERVER["DOCUMENT_URI"])) {
1337
+                        // Pattern for word=$ID$
1338
+                        $word = '\b[a-zA-Z0-9-\.-_]+\b=\$ID\$';
1339 1339
 						
1340
-						// Removing space arount =, ( and )
1341
-						$InfoFieldList[4]=preg_replace('# *(=|\(|\)) *#','$1', $InfoFieldList[4]);
1340
+                        // Removing space arount =, ( and )
1341
+                        $InfoFieldList[4]=preg_replace('# *(=|\(|\)) *#','$1', $InfoFieldList[4]);
1342 1342
 						
1343
-						$nbPreg = 1;
1344
-						// While we have parenthesis
1345
-						while ($nbPreg!=0) {
1346
-							// Init des compteurs
1347
-							$nbPregRepl = $nbPregSel = 0;
1348
-							// On retire toutes les parenthèses sans = avant
1349
-							$InfoFieldList[4]=preg_replace( '#([^=])(\([^)^(]*(' . $word .   ')[^)^(]*\))#','$1 $3 ',$InfoFieldList[4],-1,$nbPregRepl);
1350
-							// On retire les espaces autour des = et parenthèses
1351
-							$InfoFieldList[4]=preg_replace('# *(=|\(|\)) *#','$1', $InfoFieldList[4]);
1352
-							// On retire toutes les parenthèses avec = avant
1353
-							$InfoFieldList[4]=preg_replace(  '#\b[a-zA-Z0-9-\.-_]+\b=\([^)^(]*(' . $word .   ')[^)^(]*\)#','$1 ',$InfoFieldList[4], -1, $nbPregSel);
1354
-							// On retire les espaces autour des = et parenthèses
1355
-							$InfoFieldList[4]=preg_replace('# *(=|\(|\)) *#','$1', $InfoFieldList[4]);
1343
+                        $nbPreg = 1;
1344
+                        // While we have parenthesis
1345
+                        while ($nbPreg!=0) {
1346
+                            // Init des compteurs
1347
+                            $nbPregRepl = $nbPregSel = 0;
1348
+                            // On retire toutes les parenthèses sans = avant
1349
+                            $InfoFieldList[4]=preg_replace( '#([^=])(\([^)^(]*(' . $word .   ')[^)^(]*\))#','$1 $3 ',$InfoFieldList[4],-1,$nbPregRepl);
1350
+                            // On retire les espaces autour des = et parenthèses
1351
+                            $InfoFieldList[4]=preg_replace('# *(=|\(|\)) *#','$1', $InfoFieldList[4]);
1352
+                            // On retire toutes les parenthèses avec = avant
1353
+                            $InfoFieldList[4]=preg_replace(  '#\b[a-zA-Z0-9-\.-_]+\b=\([^)^(]*(' . $word .   ')[^)^(]*\)#','$1 ',$InfoFieldList[4], -1, $nbPregSel);
1354
+                            // On retire les espaces autour des = et parenthèses
1355
+                            $InfoFieldList[4]=preg_replace('# *(=|\(|\)) *#','$1', $InfoFieldList[4]);
1356 1356
 							
1357
-							// Calcul du compteur général pour la boucle
1358
-							$nbPreg = $nbPregRepl + $nbPregSel;
1359
-						}
1357
+                            // Calcul du compteur général pour la boucle
1358
+                            $nbPreg = $nbPregRepl + $nbPregSel;
1359
+                        }
1360 1360
 						
1361
-						// Si l'on a un AND ou un OR, avant ou après
1362
-						preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#',$InfoFieldList[4],$matchCondition);
1363
-						while(!empty($matchCondition[0])) {
1364
-							// If the two sides differ but are not empty
1365
-							if (! empty($matchCondition[1]) && ! empty($matchCondition[3]) && $matchCondition[1] != $matchCondition[3] ) {
1366
-								// Nobody sain would do that without parentheses
1367
-								$InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
1368
-							}
1369
-							else {
1370
-								if (! empty($matchCondition[1])) {
1371
-									$boolCond =(( $matchCondition[1] == "AND" )?' AND 1 ':' OR 0 ');
1372
-									$InfoFieldList[4]=str_replace($matchCondition[0],$boolCond.$matchCondition[3],$InfoFieldList[4]);
1373
-								}
1374
-								else if (! empty($matchCondition[3])) {
1375
-									$boolCond =(( $matchCondition[3] == "AND" )?' 1 AND ':' 0 OR');
1376
-									$InfoFieldList[4]=str_replace($matchCondition[0],$boolCond,$InfoFieldList[4]);
1377
-								}
1378
-								else {
1379
-									$InfoFieldList[4] = 1;
1380
-								}
1381
-							}
1361
+                        // Si l'on a un AND ou un OR, avant ou après
1362
+                        preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#',$InfoFieldList[4],$matchCondition);
1363
+                        while(!empty($matchCondition[0])) {
1364
+                            // If the two sides differ but are not empty
1365
+                            if (! empty($matchCondition[1]) && ! empty($matchCondition[3]) && $matchCondition[1] != $matchCondition[3] ) {
1366
+                                // Nobody sain would do that without parentheses
1367
+                                $InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
1368
+                            }
1369
+                            else {
1370
+                                if (! empty($matchCondition[1])) {
1371
+                                    $boolCond =(( $matchCondition[1] == "AND" )?' AND 1 ':' OR 0 ');
1372
+                                    $InfoFieldList[4]=str_replace($matchCondition[0],$boolCond.$matchCondition[3],$InfoFieldList[4]);
1373
+                                }
1374
+                                else if (! empty($matchCondition[3])) {
1375
+                                    $boolCond =(( $matchCondition[3] == "AND" )?' 1 AND ':' 0 OR');
1376
+                                    $InfoFieldList[4]=str_replace($matchCondition[0],$boolCond,$InfoFieldList[4]);
1377
+                                }
1378
+                                else {
1379
+                                    $InfoFieldList[4] = 1;
1380
+                                }
1381
+                            }
1382 1382
 							
1383
-							// Si l'on a un AND ou un OR, avant ou après
1384
-							preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#',$InfoFieldList[4],$matchCondition);
1385
-						}
1386
-					}
1387
-					else {
1388
-						$InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
1389
-					}
1390
-
1391
-					// We have to join on extrafield table
1392
-					if (strpos($InfoFieldList[4], 'extra') !== false) {
1393
-						$sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
1394
-						$sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
1395
-					} else {
1396
-						$sqlwhere .= ' WHERE ' . $InfoFieldList[4];
1397
-					}
1398
-				} else {
1399
-					$sqlwhere .= ' WHERE 1=1';
1400
-				}
1401
-				// Some tables may have field, some other not. For the moment we disable it.
1402
-				if (in_array($InfoFieldList[0], array ('tablewithentity')))
1403
-				{
1404
-					$sqlwhere .= ' AND entity = ' . $conf->entity;
1405
-				}
1406
-				// $sql.=preg_replace('/^ AND /','',$sqlwhere);
1407
-				// print $sql;
1408
-
1409
-				$sql .= $sqlwhere;
1410
-				dol_syslog(get_class($this) . '::showInputField type=chkbxlst',LOG_DEBUG);
1411
-				$resql = $this->db->query($sql);
1412
-				if ($resql) {
1413
-					$num = $this->db->num_rows($resql);
1414
-					$i = 0;
1415
-
1416
-					$data=array();
1417
-
1418
-					while ( $i < $num ) {
1419
-						$labeltoshow = '';
1420
-						$obj = $this->db->fetch_object($resql);
1421
-
1422
-						$notrans = false;
1423
-						// Several field into label (eq table:code|libelle:rowid)
1424
-						$fields_label = explode('|', $InfoFieldList[1]);
1425
-						if (is_array($fields_label)) {
1426
-							$notrans = true;
1427
-							foreach ( $fields_label as $field_toshow ) {
1428
-								$labeltoshow .= $obj->$field_toshow . ' ';
1429
-							}
1430
-						} else {
1431
-							$labeltoshow = $obj->{$InfoFieldList[1]};
1432
-						}
1433
-						$labeltoshow = dol_trunc($labeltoshow, 45);
1434
-
1435
-						if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1436
-							foreach ( $fields_label as $field_toshow ) {
1437
-								$translabel = $langs->trans($obj->$field_toshow);
1438
-								if ($translabel != $obj->$field_toshow) {
1439
-									$labeltoshow = dol_trunc($translabel, 18) . ' ';
1440
-								} else {
1441
-									$labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
1442
-								}
1443
-							}
1444
-
1445
-							$data[$obj->rowid]=$labeltoshow;
1446
-						} else {
1447
-							if (! $notrans) {
1448
-								$translabel = $langs->trans($obj->{$InfoFieldList[1]});
1449
-								if ($translabel != $obj->{$InfoFieldList[1]}) {
1450
-									$labeltoshow = dol_trunc($translabel, 18);
1451
-								} else {
1452
-									$labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
1453
-								}
1454
-							}
1455
-							if (empty($labeltoshow))
1456
-								$labeltoshow = '(not defined)';
1457
-
1458
-								if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1459
-									$data[$obj->rowid]=$labeltoshow;
1460
-								}
1461
-
1462
-								if (! empty($InfoFieldList[3]) && $parentField) {
1463
-									$parent = $parentName . ':' . $obj->{$parentField};
1464
-								}
1465
-
1466
-								$data[$obj->rowid]=$labeltoshow;
1467
-						}
1468
-
1469
-						$i ++;
1470
-					}
1471
-					$this->db->free($resql);
1472
-
1473
-					$out=$form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
1474
-				} else {
1475
-					print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
1476
-				}
1477
-			}
1478
-		}
1479
-		elseif ($type == 'link')
1480
-		{
1481
-			$param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
1482
-			$showempty=(($required && $default != '')?0:1);
1483
-			$out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty);
1484
-		}
1485
-		elseif ($type == 'password')
1486
-		{
1487
-			// If prefix is 'search_', field is used as a filter, we use a common text field.
1488
-			$out='<input style="display:none" type="text" name="fakeusernameremembered">';	// Hidden field to reduce impact of evil Google Chrome autopopulate bug.
1489
-			$out.='<input autocomplete="new-password" type="'.($keyprefix=='search_'?'text':'password').'" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'>';
1490
-		}
1491
-		if (!empty($hidden)) {
1492
-			$out='<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
1493
-		}
1494
-		/* Add comments
1383
+                            // Si l'on a un AND ou un OR, avant ou après
1384
+                            preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#',$InfoFieldList[4],$matchCondition);
1385
+                        }
1386
+                    }
1387
+                    else {
1388
+                        $InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
1389
+                    }
1390
+
1391
+                    // We have to join on extrafield table
1392
+                    if (strpos($InfoFieldList[4], 'extra') !== false) {
1393
+                        $sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
1394
+                        $sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
1395
+                    } else {
1396
+                        $sqlwhere .= ' WHERE ' . $InfoFieldList[4];
1397
+                    }
1398
+                } else {
1399
+                    $sqlwhere .= ' WHERE 1=1';
1400
+                }
1401
+                // Some tables may have field, some other not. For the moment we disable it.
1402
+                if (in_array($InfoFieldList[0], array ('tablewithentity')))
1403
+                {
1404
+                    $sqlwhere .= ' AND entity = ' . $conf->entity;
1405
+                }
1406
+                // $sql.=preg_replace('/^ AND /','',$sqlwhere);
1407
+                // print $sql;
1408
+
1409
+                $sql .= $sqlwhere;
1410
+                dol_syslog(get_class($this) . '::showInputField type=chkbxlst',LOG_DEBUG);
1411
+                $resql = $this->db->query($sql);
1412
+                if ($resql) {
1413
+                    $num = $this->db->num_rows($resql);
1414
+                    $i = 0;
1415
+
1416
+                    $data=array();
1417
+
1418
+                    while ( $i < $num ) {
1419
+                        $labeltoshow = '';
1420
+                        $obj = $this->db->fetch_object($resql);
1421
+
1422
+                        $notrans = false;
1423
+                        // Several field into label (eq table:code|libelle:rowid)
1424
+                        $fields_label = explode('|', $InfoFieldList[1]);
1425
+                        if (is_array($fields_label)) {
1426
+                            $notrans = true;
1427
+                            foreach ( $fields_label as $field_toshow ) {
1428
+                                $labeltoshow .= $obj->$field_toshow . ' ';
1429
+                            }
1430
+                        } else {
1431
+                            $labeltoshow = $obj->{$InfoFieldList[1]};
1432
+                        }
1433
+                        $labeltoshow = dol_trunc($labeltoshow, 45);
1434
+
1435
+                        if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1436
+                            foreach ( $fields_label as $field_toshow ) {
1437
+                                $translabel = $langs->trans($obj->$field_toshow);
1438
+                                if ($translabel != $obj->$field_toshow) {
1439
+                                    $labeltoshow = dol_trunc($translabel, 18) . ' ';
1440
+                                } else {
1441
+                                    $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
1442
+                                }
1443
+                            }
1444
+
1445
+                            $data[$obj->rowid]=$labeltoshow;
1446
+                        } else {
1447
+                            if (! $notrans) {
1448
+                                $translabel = $langs->trans($obj->{$InfoFieldList[1]});
1449
+                                if ($translabel != $obj->{$InfoFieldList[1]}) {
1450
+                                    $labeltoshow = dol_trunc($translabel, 18);
1451
+                                } else {
1452
+                                    $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
1453
+                                }
1454
+                            }
1455
+                            if (empty($labeltoshow))
1456
+                                $labeltoshow = '(not defined)';
1457
+
1458
+                                if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1459
+                                    $data[$obj->rowid]=$labeltoshow;
1460
+                                }
1461
+
1462
+                                if (! empty($InfoFieldList[3]) && $parentField) {
1463
+                                    $parent = $parentName . ':' . $obj->{$parentField};
1464
+                                }
1465
+
1466
+                                $data[$obj->rowid]=$labeltoshow;
1467
+                        }
1468
+
1469
+                        $i ++;
1470
+                    }
1471
+                    $this->db->free($resql);
1472
+
1473
+                    $out=$form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
1474
+                } else {
1475
+                    print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
1476
+                }
1477
+            }
1478
+        }
1479
+        elseif ($type == 'link')
1480
+        {
1481
+            $param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
1482
+            $showempty=(($required && $default != '')?0:1);
1483
+            $out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty);
1484
+        }
1485
+        elseif ($type == 'password')
1486
+        {
1487
+            // If prefix is 'search_', field is used as a filter, we use a common text field.
1488
+            $out='<input style="display:none" type="text" name="fakeusernameremembered">';	// Hidden field to reduce impact of evil Google Chrome autopopulate bug.
1489
+            $out.='<input autocomplete="new-password" type="'.($keyprefix=='search_'?'text':'password').'" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'>';
1490
+        }
1491
+        if (!empty($hidden)) {
1492
+            $out='<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
1493
+        }
1494
+        /* Add comments
1495 1495
 		 if ($type == 'date') $out.=' (YYYY-MM-DD)';
1496 1496
 		 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
1497 1497
 		 */
1498
-		return $out;
1499
-	}
1500
-
1501
-
1502
-	/**
1503
-	 * Return HTML string to put an output field into a page
1504
-	 *
1505
-	 * @param   string	$key            		Key of attribute
1506
-	 * @param   string	$value          		Value to show
1507
-	 * @param	string	$moreparam				To add more parameters on html input tag (only checkbox use html input for output rendering)
1508
-	 * @param	string	$extrafieldsobjectkey	If defined (for example $object->table_element), use the new method to get extrafields data
1509
-	 * @return	string							Formated value
1510
-	 */
1511
-	function showOutputField($key, $value, $moreparam='', $extrafieldsobjectkey='')
1512
-	{
1513
-		global $conf,$langs;
1514
-
1515
-		if (! empty($extrafieldsobjectkey))
1516
-		{
1517
-			$label=$this->attributes[$extrafieldsobjectkey]['label'][$key];
1518
-			$type=$this->attributes[$extrafieldsobjectkey]['type'][$key];
1519
-			$size=$this->attributes[$extrafieldsobjectkey]['size'][$key];
1520
-			$default=$this->attributes[$extrafieldsobjectkey]['default'][$key];
1521
-			$computed=$this->attributes[$extrafieldsobjectkey]['computed'][$key];
1522
-			$unique=$this->attributes[$extrafieldsobjectkey]['unique'][$key];
1523
-			$required=$this->attributes[$extrafieldsobjectkey]['required'][$key];
1524
-			$param=$this->attributes[$extrafieldsobjectkey]['param'][$key];
1525
-			$perms=dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1);
1526
-			$langfile=$this->attributes[$extrafieldsobjectkey]['langfile'][$key];
1527
-			$list=dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1);
1528
-			$help=$this->attributes[$extrafieldsobjectkey]['help'][$key];
1529
-			$hidden=(empty($list) ? 1 : 0);		// If $list empty, 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)
1530
-		}
1531
-		else	// Old usage
1532
-		{
1533
-			$label=$this->attribute_label[$key];
1534
-			$type=$this->attribute_type[$key];
1535
-			$size=$this->attribute_size[$key];
1536
-			$default=$this->attribute_default[$key];
1537
-			$computed=$this->attribute_computed[$key];
1538
-			$unique=$this->attribute_unique[$key];
1539
-			$required=$this->attribute_required[$key];
1540
-			$param=$this->attribute_param[$key];
1541
-			$perms=dol_eval($this->attribute_perms[$key], 1);
1542
-			$langfile=$this->attribute_langfile[$key];
1543
-			$list=dol_eval($this->attribute_list[$key], 1);
1544
-			$help='';	// Not supported with old syntax
1545
-			$hidden=(empty($list) ? 1 : 0);		// If $list empty, 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)
1546
-		}
1547
-
1548
-		if ($hidden) return '';		// This is a protection. If field is hidden, we should just not call this method.
1549
-
1550
-		// If field is a computed field, value must become result of compute
1551
-		if ($computed)
1552
-		{
1553
-		    // Make the eval of compute string
1554
-		    //var_dump($computed);
1555
-		    $value = dol_eval($computed, 1, 0);
1556
-		}
1557
-
1558
-		$showsize=0;
1559
-		if ($type == 'date')
1560
-		{
1561
-			$showsize=10;
1562
-			$value=dol_print_date($value, 'day');
1563
-		}
1564
-		elseif ($type == 'datetime')
1565
-		{
1566
-			$showsize=19;
1567
-			$value=dol_print_date($value, 'dayhour');
1568
-		}
1569
-		elseif ($type == 'int')
1570
-		{
1571
-			$showsize=10;
1572
-		}
1573
-		elseif ($type == 'double')
1574
-		{
1575
-			if (!empty($value)) {
1576
-				$value=price($value);
1577
-			}
1578
-		}
1579
-		elseif ($type == 'boolean')
1580
-		{
1581
-			$checked='';
1582
-			if (!empty($value)) {
1583
-				$checked=' checked ';
1584
-			}
1585
-			$value='<input type="checkbox" '.$checked.' '.($moreparam?$moreparam:'').' readonly disabled>';
1586
-		}
1587
-		elseif ($type == 'mail')
1588
-		{
1589
-			$value=dol_print_email($value, 0, 0, 0, 64, 1, 1);
1590
-		}
1591
-		elseif ($type == 'url')
1592
-		{
1593
-			$value=dol_print_url($value,'_blank',32,1);
1594
-		}
1595
-		elseif ($type == 'phone')
1596
-		{
1597
-			$value=dol_print_phone($value, '', 0, 0, '', '&nbsp;', 1);
1598
-		}
1599
-		elseif ($type == 'price')
1600
-		{
1601
-			$value=price($value, 0, $langs, 0, 0, -1, $conf->currency);
1602
-		}
1603
-		elseif ($type == 'select')
1604
-		{
1605
-			if ($langfile && $param['options'][$value]) $value=$langs->trans($param['options'][$value]);
1606
-			else $value=$param['options'][$value];
1607
-		}
1608
-		elseif ($type == 'sellist')
1609
-		{
1610
-			$param_list=array_keys($param['options']);
1611
-			$InfoFieldList = explode(":", $param_list[0]);
1612
-
1613
-			$selectkey="rowid";
1614
-			$keyList='rowid';
1615
-
1616
-			if (count($InfoFieldList)>=3)
1617
-			{
1618
-				$selectkey = $InfoFieldList[2];
1619
-				$keyList=$InfoFieldList[2].' as rowid';
1620
-			}
1621
-
1622
-			$fields_label = explode('|',$InfoFieldList[1]);
1623
-			if(is_array($fields_label)) {
1624
-				$keyList .=', ';
1625
-				$keyList .= implode(', ', $fields_label);
1626
-			}
1627
-
1628
-			$sql = 'SELECT '.$keyList;
1629
-			$sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
1630
-			if (strpos($InfoFieldList[4], 'extra')!==false)
1631
-			{
1632
-				$sql.= ' as main';
1633
-			}
1634
-			if ($selectkey=='rowid' && empty($value)) {
1635
-				$sql.= " WHERE ".$selectkey."=0";
1636
-			} elseif ($selectkey=='rowid') {
1637
-				$sql.= " WHERE ".$selectkey."=".$this->db->escape($value);
1638
-			}else {
1639
-				$sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
1640
-			}
1641
-
1642
-			//$sql.= ' AND entity = '.$conf->entity;
1643
-
1644
-			dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
1645
-			$resql = $this->db->query($sql);
1646
-			if ($resql)
1647
-			{
1648
-				$value='';	// value was used, so now we reste it to use it to build final output
1649
-
1650
-				$obj = $this->db->fetch_object($resql);
1651
-
1652
-				// Several field into label (eq table:code|libelle:rowid)
1653
-				$fields_label = explode('|',$InfoFieldList[1]);
1654
-
1655
-				if(is_array($fields_label) && count($fields_label)>1)
1656
-				{
1657
-					foreach ($fields_label as $field_toshow)
1658
-					{
1659
-						$translabel='';
1660
-						if (!empty($obj->$field_toshow)) {
1661
-							$translabel=$langs->trans($obj->$field_toshow);
1662
-						}
1663
-						if ($translabel!=$field_toshow) {
1664
-							$value.=dol_trunc($translabel,18).' ';
1665
-						}else {
1666
-							$value.=$obj->$field_toshow.' ';
1667
-						}
1668
-					}
1669
-				}
1670
-				else
1671
-				{
1672
-					$translabel='';
1673
-					if (!empty($obj->{$InfoFieldList[1]})) {
1674
-						$translabel=$langs->trans($obj->{$InfoFieldList[1]});
1675
-					}
1676
-					if ($translabel!=$obj->{$InfoFieldList[1]}) {
1677
-						$value=dol_trunc($translabel,18);
1678
-					}else {
1679
-						$value=$obj->{$InfoFieldList[1]};
1680
-					}
1681
-				}
1682
-			}
1683
-			else dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
1684
-		}
1685
-		elseif ($type == 'radio')
1686
-		{
1687
-			$value=$param['options'][$value];
1688
-		}
1689
-		elseif ($type == 'checkbox')
1690
-		{
1691
-			$value_arr=explode(',',$value);
1692
-			$value='';
1693
-			$toprint=array();
1694
-			if (is_array($value_arr))
1695
-			{
1696
-				foreach ($value_arr as $keyval=>$valueval) {
1697
-					$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$param['options'][$valueval].'</li>';
1698
-				}
1699
-			}
1700
-			$value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
1701
-		}
1702
-		elseif ($type == 'chkbxlst')
1703
-		{
1704
-			$value_arr = explode(',', $value);
1705
-
1706
-			$param_list = array_keys($param['options']);
1707
-			$InfoFieldList = explode(":", $param_list[0]);
1708
-
1709
-			$selectkey = "rowid";
1710
-			$keyList = 'rowid';
1711
-
1712
-			if (count($InfoFieldList) >= 3) {
1713
-				$selectkey = $InfoFieldList[2];
1714
-				$keyList = $InfoFieldList[2] . ' as rowid';
1715
-			}
1716
-
1717
-			$fields_label = explode('|', $InfoFieldList[1]);
1718
-			if (is_array($fields_label)) {
1719
-				$keyList .= ', ';
1720
-				$keyList .= implode(', ', $fields_label);
1721
-			}
1722
-
1723
-			$sql = 'SELECT ' . $keyList;
1724
-			$sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
1725
-			if (strpos($InfoFieldList[4], 'extra') !== false) {
1726
-				$sql .= ' as main';
1727
-			}
1728
-			// $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
1729
-			// $sql.= ' AND entity = '.$conf->entity;
1730
-
1731
-			dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst',LOG_DEBUG);
1732
-			$resql = $this->db->query($sql);
1733
-			if ($resql) {
1734
-				$value = ''; // value was used, so now we reste it to use it to build final output
1735
-				$toprint=array();
1736
-				while ( $obj = $this->db->fetch_object($resql) ) {
1737
-
1738
-					// Several field into label (eq table:code|libelle:rowid)
1739
-					$fields_label = explode('|', $InfoFieldList[1]);
1740
-					if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1741
-						if (is_array($fields_label) && count($fields_label) > 1) {
1742
-							foreach ( $fields_label as $field_toshow ) {
1743
-								$translabel = '';
1744
-								if (! empty($obj->$field_toshow)) {
1745
-									$translabel = $langs->trans($obj->$field_toshow);
1746
-								}
1747
-								if ($translabel != $field_toshow) {
1748
-									$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
1749
-								} else {
1750
-									$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->$field_toshow.'</li>';
1751
-								}
1752
-							}
1753
-						} else {
1754
-							$translabel = '';
1755
-							if (! empty($obj->{$InfoFieldList[1]})) {
1756
-								$translabel = $langs->trans($obj->{$InfoFieldList[1]});
1757
-							}
1758
-							if ($translabel != $obj->{$InfoFieldList[1]}) {
1759
-								$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
1760
-							} else {
1761
-								$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->{$InfoFieldList[1]}.'</li>';
1762
-							}
1763
-						}
1764
-					}
1765
-				}
1766
-				$value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
1767
-			} else {
1768
-				dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING);
1769
-			}
1770
-		}
1771
-		elseif ($type == 'link')
1772
-		{
1773
-			$out='';
1774
-
1775
-			// Only if something to display (perf)
1776
-			if ($value)		// If we have -1 here, pb is into sert, not into ouptu
1777
-			{
1778
-				$param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
1779
-
1780
-				$InfoFieldList = explode(":", $param_list[0]);
1781
-				$classname=$InfoFieldList[0];
1782
-				$classpath=$InfoFieldList[1];
1783
-				if (! empty($classpath))
1784
-				{
1785
-					dol_include_once($InfoFieldList[1]);
1786
-					if ($classname && class_exists($classname))
1787
-					{
1788
-						$object = new $classname($this->db);
1789
-						$object->fetch($value);
1790
-						$value=$object->getNomUrl(3);
1791
-					}
1792
-				}
1793
-				else
1794
-				{
1795
-					dol_syslog('Error bad setup of extrafield', LOG_WARNING);
1796
-					return 'Error bad setup of extrafield';
1797
-				}
1798
-			}
1799
-		}
1800
-		elseif ($type == 'text')
1801
-		{
1802
-			$value=dol_htmlentitiesbr($value);
1803
-		}
1804
-		elseif ($type == 'html')
1805
-		{
1806
-			$value=dol_htmlentitiesbr($value);
1807
-		}
1808
-		elseif ($type == 'password')
1809
-		{
1810
-			$value=dol_trunc(preg_replace('/./i','*',$value), 8, 'right', 'UTF-8', 1);
1811
-		}
1812
-		else
1813
-		{
1814
-			$showsize=round($size);
1815
-			if ($showsize > 48) $showsize=48;
1816
-		}
1817
-
1818
-		//print $type.'-'.$size;
1819
-		$out=$value;
1820
-
1821
-		return $out;
1822
-	}
1823
-
1824
-	/**
1825
-	 * Return tag to describe alignement to use for this extrafield
1826
-	 *
1827
-	 * @param   string	$key            		Key of attribute
1828
-	 * @param	string	$extrafieldsobjectkey	If defined, use the new method to get extrafields data
1829
-	 * @return	string							Formated value
1830
-	 */
1831
-	function getAlignFlag($key, $extrafieldsobjectkey='')
1832
-	{
1833
-		global $conf,$langs;
1834
-
1835
-		if (! empty($extrafieldsobjectkey)) $type=$this->attributes[$extrafieldsobjectkey]['type'][$key];
1836
-		else $type=$this->attribute_type[$key];
1837
-
1838
-		$align='';
1498
+        return $out;
1499
+    }
1500
+
1501
+
1502
+    /**
1503
+     * Return HTML string to put an output field into a page
1504
+     *
1505
+     * @param   string	$key            		Key of attribute
1506
+     * @param   string	$value          		Value to show
1507
+     * @param	string	$moreparam				To add more parameters on html input tag (only checkbox use html input for output rendering)
1508
+     * @param	string	$extrafieldsobjectkey	If defined (for example $object->table_element), use the new method to get extrafields data
1509
+     * @return	string							Formated value
1510
+     */
1511
+    function showOutputField($key, $value, $moreparam='', $extrafieldsobjectkey='')
1512
+    {
1513
+        global $conf,$langs;
1514
+
1515
+        if (! empty($extrafieldsobjectkey))
1516
+        {
1517
+            $label=$this->attributes[$extrafieldsobjectkey]['label'][$key];
1518
+            $type=$this->attributes[$extrafieldsobjectkey]['type'][$key];
1519
+            $size=$this->attributes[$extrafieldsobjectkey]['size'][$key];
1520
+            $default=$this->attributes[$extrafieldsobjectkey]['default'][$key];
1521
+            $computed=$this->attributes[$extrafieldsobjectkey]['computed'][$key];
1522
+            $unique=$this->attributes[$extrafieldsobjectkey]['unique'][$key];
1523
+            $required=$this->attributes[$extrafieldsobjectkey]['required'][$key];
1524
+            $param=$this->attributes[$extrafieldsobjectkey]['param'][$key];
1525
+            $perms=dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1);
1526
+            $langfile=$this->attributes[$extrafieldsobjectkey]['langfile'][$key];
1527
+            $list=dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1);
1528
+            $help=$this->attributes[$extrafieldsobjectkey]['help'][$key];
1529
+            $hidden=(empty($list) ? 1 : 0);		// If $list empty, 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)
1530
+        }
1531
+        else	// Old usage
1532
+        {
1533
+            $label=$this->attribute_label[$key];
1534
+            $type=$this->attribute_type[$key];
1535
+            $size=$this->attribute_size[$key];
1536
+            $default=$this->attribute_default[$key];
1537
+            $computed=$this->attribute_computed[$key];
1538
+            $unique=$this->attribute_unique[$key];
1539
+            $required=$this->attribute_required[$key];
1540
+            $param=$this->attribute_param[$key];
1541
+            $perms=dol_eval($this->attribute_perms[$key], 1);
1542
+            $langfile=$this->attribute_langfile[$key];
1543
+            $list=dol_eval($this->attribute_list[$key], 1);
1544
+            $help='';	// Not supported with old syntax
1545
+            $hidden=(empty($list) ? 1 : 0);		// If $list empty, 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)
1546
+        }
1547
+
1548
+        if ($hidden) return '';		// This is a protection. If field is hidden, we should just not call this method.
1839 1549
 
1550
+        // If field is a computed field, value must become result of compute
1551
+        if ($computed)
1552
+        {
1553
+            // Make the eval of compute string
1554
+            //var_dump($computed);
1555
+            $value = dol_eval($computed, 1, 0);
1556
+        }
1557
+
1558
+        $showsize=0;
1840 1559
         if ($type == 'date')
1841
-		{
1842
-			$align="center";
1843
-		}
1844
-		elseif ($type == 'datetime')
1845
-		{
1846
-			$align="center";
1847
-		}
1848
-		elseif ($type == 'int')
1849
-		{
1850
-			$align="right";
1851
-		}
1852
-		elseif ($type == 'double')
1853
-		{
1854
-			$align="right";
1855
-		}
1856
-		elseif ($type == 'boolean')
1857
-		{
1858
-			$align="center";
1859
-		}
1860
-		elseif ($type == 'radio')
1861
-		{
1862
-			$align="center";
1863
-		}
1864
-		elseif ($type == 'checkbox')
1865
-		{
1866
-			$align="center";
1867
-		}
1868
-		elseif ($type == 'price')
1869
-		{
1870
-			$align="right";
1871
-		}
1872
-
1873
-		return $align;
1874
-	}
1875
-
1876
-	/**
1877
-	 * Return HTML string to print separator extrafield
1878
-	 *
1879
-	 * @param   string	$key            Key of attribute
1880
-	 * @param	string	$object			Object
1881
-	 * @return 	string					HTML code with line for separator
1882
-	 */
1883
-	function showSeparator($key, $object)
1884
-	{
1885
-		global $langs;
1886
-
1887
-		$out = '<tr class="trextrafieldseparator trextrafieldseparator'.$key.'"><td colspan="2"><strong>';
1888
-		$out.= $langs->trans($this->attributes[$object->table_element]['label'][$key]);
1889
-		$out.= '</strong></td></tr>';
1890
-		return $out;
1891
-	}
1892
-
1893
-	/**
1894
-	 * Fill array_options property of object by extrafields value (using for data sent by forms)
1895
-	 *
1896
-	 * @param   array	$extralabels    $array of extrafields (@deprecated)
1897
-	 * @param   object	$object         Object
1898
-	 * @param	string	$onlykey		Only following key is filled. When we make update of only one extrafield ($action = 'update_extras'), calling page must must set this to avoid to have other extrafields being reset.
1899
-	 * @return	int						1 if array_options set, 0 if no value, -1 if error (field required missing for example)
1900
-	 */
1901
-	function setOptionalsFromPost($extralabels, &$object, $onlykey='')
1902
-	{
1903
-		global $_POST, $langs;
1904
-		$nofillrequired='';// For error when required field left blank
1905
-		$error_field_required = array();
1906
-
1907
-		if (is_array($this->attributes[$object->table_element]['label'])) $extralabels=$this->attributes[$object->table_element]['label'];
1908
-
1909
-		if (is_array($extralabels))
1910
-		{
1911
-			// Get extra fields
1912
-			foreach ($extralabels as $key => $value)
1913
-			{
1914
-				if (! empty($onlykey) && $key != $onlykey) continue;
1915
-
1916
-				$key_type = $this->attributes[$object->table_element]['type'][$key];
1917
-				if ($key_type == 'separate') continue;
1918
-
1919
-				$enabled = 1;
1920
-				if (isset($this->attributes[$object->table_element]['list'][$key]))
1921
-				{
1922
-					$enabled = dol_eval($this->attributes[$object->table_element]['list'][$key], 1);
1923
-				}
1924
-				$perms = 1;
1925
-				if (isset($this->attributes[$object->table_element]['perms'][$key]))
1926
-				{
1927
-					$perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1);
1928
-				}
1929
-				if (empty($enabled)) continue;
1930
-				if (empty($perms)) continue;
1931
-
1932
-				if ($this->attributes[$object->table_element]['required'][$key])	// Value is required
1933
-				{
1934
-					// Check if empty without using GETPOST, value can be alpha, int, array, etc...
1935
-					if ((! is_array($_POST["options_".$key]) && empty($_POST["options_".$key]) && $_POST["options_".$key] != '0')
1936
-						|| (is_array($_POST["options_".$key]) && empty($_POST["options_".$key])))
1937
-					{
1938
-						//print 'ccc'.$value.'-'.$this->attributes[$object->table_element]['required'][$key];
1939
-						$nofillrequired++;
1940
-						$error_field_required[] = $langs->transnoentitiesnoconv($value);
1941
-					}
1942
-				}
1943
-
1944
-				if (in_array($key_type,array('date')))
1945
-				{
1946
-					// Clean parameters
1947
-					// TODO GMT date in memory must be GMT so we should add gm=true in parameters
1948
-					$value_key=dol_mktime(0, 0, 0, $_POST["options_".$key."month"], $_POST["options_".$key."day"], $_POST["options_".$key."year"]);
1949
-				}
1950
-				elseif (in_array($key_type,array('datetime')))
1951
-				{
1952
-					// Clean parameters
1953
-					// TODO GMT date in memory must be GMT so we should add gm=true in parameters
1954
-					$value_key=dol_mktime($_POST["options_".$key."hour"], $_POST["options_".$key."min"], 0, $_POST["options_".$key."month"], $_POST["options_".$key."day"], $_POST["options_".$key."year"]);
1955
-				}
1956
-				else if (in_array($key_type,array('checkbox','chkbxlst')))
1957
-				{
1958
-					$value_arr=GETPOST("options_".$key, 'array'); // check if an array
1959
-					if (!empty($value_arr)) {
1960
-						$value_key=implode($value_arr,',');
1961
-					}else {
1962
-						$value_key='';
1963
-					}
1964
-				}
1965
-				else if (in_array($key_type,array('price','double')))
1966
-				{
1967
-					$value_arr=GETPOST("options_".$key, 'alpha');
1968
-					$value_key=price2num($value_arr);
1969
-				}
1970
-				else
1971
-				{
1972
-					$value_key=GETPOST("options_".$key);
1973
-				}
1974
-
1975
-				$object->array_options["options_".$key]=$value_key;
1976
-			}
1977
-
1978
-			if ($nofillrequired) {
1979
-				$langs->load('errors');
1980
-				setEventMessages($langs->trans('ErrorFieldsRequired').' : '.implode(', ',$error_field_required), null, 'errors');
1981
-				return -1;
1982
-			}
1983
-			else {
1984
-				return 1;
1985
-			}
1986
-		}
1987
-		else {
1988
-			return 0;
1989
-		}
1990
-	}
1991
-
1992
-	/**
1993
-	 * return array_options array of data of extrafields value of object sent by a search form
1994
-	 *
1995
-	 * @param  array|string		$extrafieldsobjectkey  	array of extrafields (old usage) or value of object->table_element (new usage)
1996
-	 * @param  string			$keyprefix      		Prefix string to add into name and id of field (can be used to avoid duplicate names)
1997
-	 * @param  string			$keysuffix      		Suffix string to add into name and id of field (can be used to avoid duplicate names)
1998
-	 * @return array|int								array_options set or 0 if no value
1999
-	 */
2000
-	function getOptionalsFromPost($extrafieldsobjectkey, $keyprefix='', $keysuffix='')
2001
-	{
2002
-		global $_POST;
2003
-
2004
-		if (is_string($extrafieldsobjectkey) && is_array($this->attributes[$extrafieldsobjectkey]['label']))
2005
-		{
2006
-			$extralabels = $this->attributes[$extrafieldsobjectkey]['label'];
2007
-		}
2008
-		else
2009
-		{
2010
-			$extralabels = $extrafieldsobjectkey;
2011
-		}
2012
-
2013
-		if (is_array($extralabels))
2014
-		{
2015
-			$array_options = array();
2016
-
2017
-			// Get extra fields
2018
-			foreach ($extralabels as $key => $value)
2019
-			{
2020
-				$key_type = '';
2021
-				if (is_string($extrafieldsobjectkey))
2022
-				{
2023
-					$key_type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
2024
-				}
2025
-
2026
-				if (in_array($key_type,array('date','datetime')))
2027
-				{
2028
-					// Clean parameters
2029
-					$value_key=dol_mktime($_POST[$keysuffix."options_".$key.$keyprefix."hour"], $_POST[$keysuffix."options_".$key.$keyprefix."min"], 0, $_POST[$keysuffix."options_".$key.$keyprefix."month"], $_POST[$keysuffix."options_".$key.$keyprefix."day"], $_POST[$keysuffix."options_".$key.$keyprefix."year"]);
2030
-				}
2031
-				else if (in_array($key_type,array('checkbox', 'chkbxlst')))
2032
-				{
2033
-					$value_arr=GETPOST($keysuffix."options_".$key.$keyprefix);
2034
-					// Make sure we get an array even if there's only one checkbox
2035
-					$value_arr=(array) $value_arr;
2036
-					$value_key=implode(',', $value_arr);
2037
-				}
2038
-				else if (in_array($key_type,array('price','double')))
2039
-				{
2040
-					$value_arr=GETPOST($keysuffix."options_".$key.$keyprefix);
2041
-					$value_key=price2num($value_arr);
2042
-				}
2043
-				else
2044
-				{
2045
-					$value_key=GETPOST($keysuffix."options_".$key.$keyprefix);
2046
-				}
2047
-
2048
-				$array_options[$keysuffix."options_".$key]=$value_key;	// No keyprefix here. keyprefix is used only for read.
2049
-			}
2050
-
2051
-			return $array_options;
2052
-		}
2053
-
2054
-		return 0;
2055
-	}
1560
+        {
1561
+            $showsize=10;
1562
+            $value=dol_print_date($value, 'day');
1563
+        }
1564
+        elseif ($type == 'datetime')
1565
+        {
1566
+            $showsize=19;
1567
+            $value=dol_print_date($value, 'dayhour');
1568
+        }
1569
+        elseif ($type == 'int')
1570
+        {
1571
+            $showsize=10;
1572
+        }
1573
+        elseif ($type == 'double')
1574
+        {
1575
+            if (!empty($value)) {
1576
+                $value=price($value);
1577
+            }
1578
+        }
1579
+        elseif ($type == 'boolean')
1580
+        {
1581
+            $checked='';
1582
+            if (!empty($value)) {
1583
+                $checked=' checked ';
1584
+            }
1585
+            $value='<input type="checkbox" '.$checked.' '.($moreparam?$moreparam:'').' readonly disabled>';
1586
+        }
1587
+        elseif ($type == 'mail')
1588
+        {
1589
+            $value=dol_print_email($value, 0, 0, 0, 64, 1, 1);
1590
+        }
1591
+        elseif ($type == 'url')
1592
+        {
1593
+            $value=dol_print_url($value,'_blank',32,1);
1594
+        }
1595
+        elseif ($type == 'phone')
1596
+        {
1597
+            $value=dol_print_phone($value, '', 0, 0, '', '&nbsp;', 1);
1598
+        }
1599
+        elseif ($type == 'price')
1600
+        {
1601
+            $value=price($value, 0, $langs, 0, 0, -1, $conf->currency);
1602
+        }
1603
+        elseif ($type == 'select')
1604
+        {
1605
+            if ($langfile && $param['options'][$value]) $value=$langs->trans($param['options'][$value]);
1606
+            else $value=$param['options'][$value];
1607
+        }
1608
+        elseif ($type == 'sellist')
1609
+        {
1610
+            $param_list=array_keys($param['options']);
1611
+            $InfoFieldList = explode(":", $param_list[0]);
1612
+
1613
+            $selectkey="rowid";
1614
+            $keyList='rowid';
1615
+
1616
+            if (count($InfoFieldList)>=3)
1617
+            {
1618
+                $selectkey = $InfoFieldList[2];
1619
+                $keyList=$InfoFieldList[2].' as rowid';
1620
+            }
1621
+
1622
+            $fields_label = explode('|',$InfoFieldList[1]);
1623
+            if(is_array($fields_label)) {
1624
+                $keyList .=', ';
1625
+                $keyList .= implode(', ', $fields_label);
1626
+            }
1627
+
1628
+            $sql = 'SELECT '.$keyList;
1629
+            $sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
1630
+            if (strpos($InfoFieldList[4], 'extra')!==false)
1631
+            {
1632
+                $sql.= ' as main';
1633
+            }
1634
+            if ($selectkey=='rowid' && empty($value)) {
1635
+                $sql.= " WHERE ".$selectkey."=0";
1636
+            } elseif ($selectkey=='rowid') {
1637
+                $sql.= " WHERE ".$selectkey."=".$this->db->escape($value);
1638
+            }else {
1639
+                $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
1640
+            }
1641
+
1642
+            //$sql.= ' AND entity = '.$conf->entity;
1643
+
1644
+            dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
1645
+            $resql = $this->db->query($sql);
1646
+            if ($resql)
1647
+            {
1648
+                $value='';	// value was used, so now we reste it to use it to build final output
1649
+
1650
+                $obj = $this->db->fetch_object($resql);
1651
+
1652
+                // Several field into label (eq table:code|libelle:rowid)
1653
+                $fields_label = explode('|',$InfoFieldList[1]);
1654
+
1655
+                if(is_array($fields_label) && count($fields_label)>1)
1656
+                {
1657
+                    foreach ($fields_label as $field_toshow)
1658
+                    {
1659
+                        $translabel='';
1660
+                        if (!empty($obj->$field_toshow)) {
1661
+                            $translabel=$langs->trans($obj->$field_toshow);
1662
+                        }
1663
+                        if ($translabel!=$field_toshow) {
1664
+                            $value.=dol_trunc($translabel,18).' ';
1665
+                        }else {
1666
+                            $value.=$obj->$field_toshow.' ';
1667
+                        }
1668
+                    }
1669
+                }
1670
+                else
1671
+                {
1672
+                    $translabel='';
1673
+                    if (!empty($obj->{$InfoFieldList[1]})) {
1674
+                        $translabel=$langs->trans($obj->{$InfoFieldList[1]});
1675
+                    }
1676
+                    if ($translabel!=$obj->{$InfoFieldList[1]}) {
1677
+                        $value=dol_trunc($translabel,18);
1678
+                    }else {
1679
+                        $value=$obj->{$InfoFieldList[1]};
1680
+                    }
1681
+                }
1682
+            }
1683
+            else dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
1684
+        }
1685
+        elseif ($type == 'radio')
1686
+        {
1687
+            $value=$param['options'][$value];
1688
+        }
1689
+        elseif ($type == 'checkbox')
1690
+        {
1691
+            $value_arr=explode(',',$value);
1692
+            $value='';
1693
+            $toprint=array();
1694
+            if (is_array($value_arr))
1695
+            {
1696
+                foreach ($value_arr as $keyval=>$valueval) {
1697
+                    $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$param['options'][$valueval].'</li>';
1698
+                }
1699
+            }
1700
+            $value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
1701
+        }
1702
+        elseif ($type == 'chkbxlst')
1703
+        {
1704
+            $value_arr = explode(',', $value);
1705
+
1706
+            $param_list = array_keys($param['options']);
1707
+            $InfoFieldList = explode(":", $param_list[0]);
1708
+
1709
+            $selectkey = "rowid";
1710
+            $keyList = 'rowid';
1711
+
1712
+            if (count($InfoFieldList) >= 3) {
1713
+                $selectkey = $InfoFieldList[2];
1714
+                $keyList = $InfoFieldList[2] . ' as rowid';
1715
+            }
1716
+
1717
+            $fields_label = explode('|', $InfoFieldList[1]);
1718
+            if (is_array($fields_label)) {
1719
+                $keyList .= ', ';
1720
+                $keyList .= implode(', ', $fields_label);
1721
+            }
1722
+
1723
+            $sql = 'SELECT ' . $keyList;
1724
+            $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
1725
+            if (strpos($InfoFieldList[4], 'extra') !== false) {
1726
+                $sql .= ' as main';
1727
+            }
1728
+            // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
1729
+            // $sql.= ' AND entity = '.$conf->entity;
1730
+
1731
+            dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst',LOG_DEBUG);
1732
+            $resql = $this->db->query($sql);
1733
+            if ($resql) {
1734
+                $value = ''; // value was used, so now we reste it to use it to build final output
1735
+                $toprint=array();
1736
+                while ( $obj = $this->db->fetch_object($resql) ) {
1737
+
1738
+                    // Several field into label (eq table:code|libelle:rowid)
1739
+                    $fields_label = explode('|', $InfoFieldList[1]);
1740
+                    if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
1741
+                        if (is_array($fields_label) && count($fields_label) > 1) {
1742
+                            foreach ( $fields_label as $field_toshow ) {
1743
+                                $translabel = '';
1744
+                                if (! empty($obj->$field_toshow)) {
1745
+                                    $translabel = $langs->trans($obj->$field_toshow);
1746
+                                }
1747
+                                if ($translabel != $field_toshow) {
1748
+                                    $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
1749
+                                } else {
1750
+                                    $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->$field_toshow.'</li>';
1751
+                                }
1752
+                            }
1753
+                        } else {
1754
+                            $translabel = '';
1755
+                            if (! empty($obj->{$InfoFieldList[1]})) {
1756
+                                $translabel = $langs->trans($obj->{$InfoFieldList[1]});
1757
+                            }
1758
+                            if ($translabel != $obj->{$InfoFieldList[1]}) {
1759
+                                $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
1760
+                            } else {
1761
+                                $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->{$InfoFieldList[1]}.'</li>';
1762
+                            }
1763
+                        }
1764
+                    }
1765
+                }
1766
+                $value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
1767
+            } else {
1768
+                dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING);
1769
+            }
1770
+        }
1771
+        elseif ($type == 'link')
1772
+        {
1773
+            $out='';
1774
+
1775
+            // Only if something to display (perf)
1776
+            if ($value)		// If we have -1 here, pb is into sert, not into ouptu
1777
+            {
1778
+                $param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
1779
+
1780
+                $InfoFieldList = explode(":", $param_list[0]);
1781
+                $classname=$InfoFieldList[0];
1782
+                $classpath=$InfoFieldList[1];
1783
+                if (! empty($classpath))
1784
+                {
1785
+                    dol_include_once($InfoFieldList[1]);
1786
+                    if ($classname && class_exists($classname))
1787
+                    {
1788
+                        $object = new $classname($this->db);
1789
+                        $object->fetch($value);
1790
+                        $value=$object->getNomUrl(3);
1791
+                    }
1792
+                }
1793
+                else
1794
+                {
1795
+                    dol_syslog('Error bad setup of extrafield', LOG_WARNING);
1796
+                    return 'Error bad setup of extrafield';
1797
+                }
1798
+            }
1799
+        }
1800
+        elseif ($type == 'text')
1801
+        {
1802
+            $value=dol_htmlentitiesbr($value);
1803
+        }
1804
+        elseif ($type == 'html')
1805
+        {
1806
+            $value=dol_htmlentitiesbr($value);
1807
+        }
1808
+        elseif ($type == 'password')
1809
+        {
1810
+            $value=dol_trunc(preg_replace('/./i','*',$value), 8, 'right', 'UTF-8', 1);
1811
+        }
1812
+        else
1813
+        {
1814
+            $showsize=round($size);
1815
+            if ($showsize > 48) $showsize=48;
1816
+        }
1817
+
1818
+        //print $type.'-'.$size;
1819
+        $out=$value;
1820
+
1821
+        return $out;
1822
+    }
1823
+
1824
+    /**
1825
+     * Return tag to describe alignement to use for this extrafield
1826
+     *
1827
+     * @param   string	$key            		Key of attribute
1828
+     * @param	string	$extrafieldsobjectkey	If defined, use the new method to get extrafields data
1829
+     * @return	string							Formated value
1830
+     */
1831
+    function getAlignFlag($key, $extrafieldsobjectkey='')
1832
+    {
1833
+        global $conf,$langs;
1834
+
1835
+        if (! empty($extrafieldsobjectkey)) $type=$this->attributes[$extrafieldsobjectkey]['type'][$key];
1836
+        else $type=$this->attribute_type[$key];
1837
+
1838
+        $align='';
1839
+
1840
+        if ($type == 'date')
1841
+        {
1842
+            $align="center";
1843
+        }
1844
+        elseif ($type == 'datetime')
1845
+        {
1846
+            $align="center";
1847
+        }
1848
+        elseif ($type == 'int')
1849
+        {
1850
+            $align="right";
1851
+        }
1852
+        elseif ($type == 'double')
1853
+        {
1854
+            $align="right";
1855
+        }
1856
+        elseif ($type == 'boolean')
1857
+        {
1858
+            $align="center";
1859
+        }
1860
+        elseif ($type == 'radio')
1861
+        {
1862
+            $align="center";
1863
+        }
1864
+        elseif ($type == 'checkbox')
1865
+        {
1866
+            $align="center";
1867
+        }
1868
+        elseif ($type == 'price')
1869
+        {
1870
+            $align="right";
1871
+        }
1872
+
1873
+        return $align;
1874
+    }
1875
+
1876
+    /**
1877
+     * Return HTML string to print separator extrafield
1878
+     *
1879
+     * @param   string	$key            Key of attribute
1880
+     * @param	string	$object			Object
1881
+     * @return 	string					HTML code with line for separator
1882
+     */
1883
+    function showSeparator($key, $object)
1884
+    {
1885
+        global $langs;
1886
+
1887
+        $out = '<tr class="trextrafieldseparator trextrafieldseparator'.$key.'"><td colspan="2"><strong>';
1888
+        $out.= $langs->trans($this->attributes[$object->table_element]['label'][$key]);
1889
+        $out.= '</strong></td></tr>';
1890
+        return $out;
1891
+    }
1892
+
1893
+    /**
1894
+     * Fill array_options property of object by extrafields value (using for data sent by forms)
1895
+     *
1896
+     * @param   array	$extralabels    $array of extrafields (@deprecated)
1897
+     * @param   object	$object         Object
1898
+     * @param	string	$onlykey		Only following key is filled. When we make update of only one extrafield ($action = 'update_extras'), calling page must must set this to avoid to have other extrafields being reset.
1899
+     * @return	int						1 if array_options set, 0 if no value, -1 if error (field required missing for example)
1900
+     */
1901
+    function setOptionalsFromPost($extralabels, &$object, $onlykey='')
1902
+    {
1903
+        global $_POST, $langs;
1904
+        $nofillrequired='';// For error when required field left blank
1905
+        $error_field_required = array();
1906
+
1907
+        if (is_array($this->attributes[$object->table_element]['label'])) $extralabels=$this->attributes[$object->table_element]['label'];
1908
+
1909
+        if (is_array($extralabels))
1910
+        {
1911
+            // Get extra fields
1912
+            foreach ($extralabels as $key => $value)
1913
+            {
1914
+                if (! empty($onlykey) && $key != $onlykey) continue;
1915
+
1916
+                $key_type = $this->attributes[$object->table_element]['type'][$key];
1917
+                if ($key_type == 'separate') continue;
1918
+
1919
+                $enabled = 1;
1920
+                if (isset($this->attributes[$object->table_element]['list'][$key]))
1921
+                {
1922
+                    $enabled = dol_eval($this->attributes[$object->table_element]['list'][$key], 1);
1923
+                }
1924
+                $perms = 1;
1925
+                if (isset($this->attributes[$object->table_element]['perms'][$key]))
1926
+                {
1927
+                    $perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1);
1928
+                }
1929
+                if (empty($enabled)) continue;
1930
+                if (empty($perms)) continue;
1931
+
1932
+                if ($this->attributes[$object->table_element]['required'][$key])	// Value is required
1933
+                {
1934
+                    // Check if empty without using GETPOST, value can be alpha, int, array, etc...
1935
+                    if ((! is_array($_POST["options_".$key]) && empty($_POST["options_".$key]) && $_POST["options_".$key] != '0')
1936
+                        || (is_array($_POST["options_".$key]) && empty($_POST["options_".$key])))
1937
+                    {
1938
+                        //print 'ccc'.$value.'-'.$this->attributes[$object->table_element]['required'][$key];
1939
+                        $nofillrequired++;
1940
+                        $error_field_required[] = $langs->transnoentitiesnoconv($value);
1941
+                    }
1942
+                }
1943
+
1944
+                if (in_array($key_type,array('date')))
1945
+                {
1946
+                    // Clean parameters
1947
+                    // TODO GMT date in memory must be GMT so we should add gm=true in parameters
1948
+                    $value_key=dol_mktime(0, 0, 0, $_POST["options_".$key."month"], $_POST["options_".$key."day"], $_POST["options_".$key."year"]);
1949
+                }
1950
+                elseif (in_array($key_type,array('datetime')))
1951
+                {
1952
+                    // Clean parameters
1953
+                    // TODO GMT date in memory must be GMT so we should add gm=true in parameters
1954
+                    $value_key=dol_mktime($_POST["options_".$key."hour"], $_POST["options_".$key."min"], 0, $_POST["options_".$key."month"], $_POST["options_".$key."day"], $_POST["options_".$key."year"]);
1955
+                }
1956
+                else if (in_array($key_type,array('checkbox','chkbxlst')))
1957
+                {
1958
+                    $value_arr=GETPOST("options_".$key, 'array'); // check if an array
1959
+                    if (!empty($value_arr)) {
1960
+                        $value_key=implode($value_arr,',');
1961
+                    }else {
1962
+                        $value_key='';
1963
+                    }
1964
+                }
1965
+                else if (in_array($key_type,array('price','double')))
1966
+                {
1967
+                    $value_arr=GETPOST("options_".$key, 'alpha');
1968
+                    $value_key=price2num($value_arr);
1969
+                }
1970
+                else
1971
+                {
1972
+                    $value_key=GETPOST("options_".$key);
1973
+                }
1974
+
1975
+                $object->array_options["options_".$key]=$value_key;
1976
+            }
1977
+
1978
+            if ($nofillrequired) {
1979
+                $langs->load('errors');
1980
+                setEventMessages($langs->trans('ErrorFieldsRequired').' : '.implode(', ',$error_field_required), null, 'errors');
1981
+                return -1;
1982
+            }
1983
+            else {
1984
+                return 1;
1985
+            }
1986
+        }
1987
+        else {
1988
+            return 0;
1989
+        }
1990
+    }
1991
+
1992
+    /**
1993
+     * return array_options array of data of extrafields value of object sent by a search form
1994
+     *
1995
+     * @param  array|string		$extrafieldsobjectkey  	array of extrafields (old usage) or value of object->table_element (new usage)
1996
+     * @param  string			$keyprefix      		Prefix string to add into name and id of field (can be used to avoid duplicate names)
1997
+     * @param  string			$keysuffix      		Suffix string to add into name and id of field (can be used to avoid duplicate names)
1998
+     * @return array|int								array_options set or 0 if no value
1999
+     */
2000
+    function getOptionalsFromPost($extrafieldsobjectkey, $keyprefix='', $keysuffix='')
2001
+    {
2002
+        global $_POST;
2003
+
2004
+        if (is_string($extrafieldsobjectkey) && is_array($this->attributes[$extrafieldsobjectkey]['label']))
2005
+        {
2006
+            $extralabels = $this->attributes[$extrafieldsobjectkey]['label'];
2007
+        }
2008
+        else
2009
+        {
2010
+            $extralabels = $extrafieldsobjectkey;
2011
+        }
2012
+
2013
+        if (is_array($extralabels))
2014
+        {
2015
+            $array_options = array();
2016
+
2017
+            // Get extra fields
2018
+            foreach ($extralabels as $key => $value)
2019
+            {
2020
+                $key_type = '';
2021
+                if (is_string($extrafieldsobjectkey))
2022
+                {
2023
+                    $key_type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
2024
+                }
2025
+
2026
+                if (in_array($key_type,array('date','datetime')))
2027
+                {
2028
+                    // Clean parameters
2029
+                    $value_key=dol_mktime($_POST[$keysuffix."options_".$key.$keyprefix."hour"], $_POST[$keysuffix."options_".$key.$keyprefix."min"], 0, $_POST[$keysuffix."options_".$key.$keyprefix."month"], $_POST[$keysuffix."options_".$key.$keyprefix."day"], $_POST[$keysuffix."options_".$key.$keyprefix."year"]);
2030
+                }
2031
+                else if (in_array($key_type,array('checkbox', 'chkbxlst')))
2032
+                {
2033
+                    $value_arr=GETPOST($keysuffix."options_".$key.$keyprefix);
2034
+                    // Make sure we get an array even if there's only one checkbox
2035
+                    $value_arr=(array) $value_arr;
2036
+                    $value_key=implode(',', $value_arr);
2037
+                }
2038
+                else if (in_array($key_type,array('price','double')))
2039
+                {
2040
+                    $value_arr=GETPOST($keysuffix."options_".$key.$keyprefix);
2041
+                    $value_key=price2num($value_arr);
2042
+                }
2043
+                else
2044
+                {
2045
+                    $value_key=GETPOST($keysuffix."options_".$key.$keyprefix);
2046
+                }
2047
+
2048
+                $array_options[$keysuffix."options_".$key]=$value_key;	// No keyprefix here. keyprefix is used only for read.
2049
+            }
2050
+
2051
+            return $array_options;
2052
+        }
2053
+
2054
+        return 0;
2055
+    }
2056 2056
 }
Please login to merge, or discard this patch.
dolibarr/htdocs/core/class/events.class.php 1 patch
Indentation   +237 added lines, -237 removed lines patch added patch discarded remove patch
@@ -34,62 +34,62 @@  discard block
 block discarded – undo
34 34
  */
35 35
 class Events // extends CommonObject
36 36
 {
37
-	/**
38
-	 * @var string ID to identify managed object
39
-	 */
40
-	public $element='events';
37
+    /**
38
+     * @var string ID to identify managed object
39
+     */
40
+    public $element='events';
41 41
 
42
-	/**
43
-	 * @var string Name of table without prefix where object is stored
44
-	 */
45
-	public $table_element='events';
42
+    /**
43
+     * @var string Name of table without prefix where object is stored
44
+     */
45
+    public $table_element='events';
46 46
 
47
-	/**
48
-	 * @var int ID
49
-	 */
50
-	public $id;
47
+    /**
48
+     * @var int ID
49
+     */
50
+    public $id;
51 51
 
52 52
     /**
53 53
      * @var DoliDB Database handler.
54 54
      */
55 55
     public $db;
56 56
 
57
-	/**
58
-	 * @var string Error code (or message)
59
-	 */
60
-	public $error='';
61
-
62
-	public $tms;
63
-	public $type;
64
-
65
-	/**
66
-	 * @var int Entity
67
-	 */
68
-	public $entity;
69
-
70
-	public $dateevent;
71
-
72
-	/**
73
-	 * @var string description
74
-	 */
75
-	public $description;
76
-
77
-	// List of all Audit/Security events supported by triggers
78
-	public $eventstolog=array(
79
-		array('id'=>'USER_LOGIN',             'test'=>1),
80
-		array('id'=>'USER_LOGIN_FAILED',      'test'=>1),
81
-	    array('id'=>'USER_LOGOUT',            'test'=>1),
82
-		array('id'=>'USER_CREATE',            'test'=>1),
83
-		array('id'=>'USER_MODIFY',            'test'=>1),
84
-		array('id'=>'USER_NEW_PASSWORD',      'test'=>1),
85
-		array('id'=>'USER_ENABLEDISABLE',     'test'=>1),
86
-		array('id'=>'USER_DELETE',            'test'=>1),
87
-	/*    array('id'=>'USER_SETINGROUP',        'test'=>1), deprecated. Replace with USER_MODIFY
57
+    /**
58
+     * @var string Error code (or message)
59
+     */
60
+    public $error='';
61
+
62
+    public $tms;
63
+    public $type;
64
+
65
+    /**
66
+     * @var int Entity
67
+     */
68
+    public $entity;
69
+
70
+    public $dateevent;
71
+
72
+    /**
73
+     * @var string description
74
+     */
75
+    public $description;
76
+
77
+    // List of all Audit/Security events supported by triggers
78
+    public $eventstolog=array(
79
+        array('id'=>'USER_LOGIN',             'test'=>1),
80
+        array('id'=>'USER_LOGIN_FAILED',      'test'=>1),
81
+        array('id'=>'USER_LOGOUT',            'test'=>1),
82
+        array('id'=>'USER_CREATE',            'test'=>1),
83
+        array('id'=>'USER_MODIFY',            'test'=>1),
84
+        array('id'=>'USER_NEW_PASSWORD',      'test'=>1),
85
+        array('id'=>'USER_ENABLEDISABLE',     'test'=>1),
86
+        array('id'=>'USER_DELETE',            'test'=>1),
87
+    /*    array('id'=>'USER_SETINGROUP',        'test'=>1), deprecated. Replace with USER_MODIFY
88 88
 	    array('id'=>'USER_REMOVEFROMGROUP',   'test'=>1), deprecated. Replace with USER_MODIFY */
89
-		array('id'=>'GROUP_CREATE',           'test'=>1),
90
-		array('id'=>'GROUP_MODIFY',           'test'=>1),
91
-		array('id'=>'GROUP_DELETE',           'test'=>1),
92
-	/*	array('id'=>'ACTION_CREATE',          'test'=>$conf->societe->enabled),
89
+        array('id'=>'GROUP_CREATE',           'test'=>1),
90
+        array('id'=>'GROUP_MODIFY',           'test'=>1),
91
+        array('id'=>'GROUP_DELETE',           'test'=>1),
92
+    /*	array('id'=>'ACTION_CREATE',          'test'=>$conf->societe->enabled),
93 93
 		array('id'=>'COMPANY_CREATE',         'test'=>$conf->societe->enabled),
94 94
 		array('id'=>'CONTRACT_VALIDATE',      'test'=>$conf->contrat->enabled),
95 95
 		array('id'=>'PROPAL_VALIDATE',        'test'=>$conf->propal->enabled),
@@ -111,199 +111,199 @@  discard block
 block discarded – undo
111 111
 		array('id'=>'MEMBER_RESILIATE',       'test'=>$conf->adherent->enabled),
112 112
 		array('id'=>'MEMBER_DELETE',          'test'=>$conf->adherent->enabled),
113 113
 	*/
114
-	);
115
-
116
-
117
-	/**
118
-	 *	Constructor
119
-	 *
120
-	 *  @param		DoliDB		$db      Database handler
121
-	 */
122
-	function __construct($db)
123
-	{
124
-		$this->db = $db;
125
-	}
126
-
127
-
128
-	/**
129
-	 *   Create in database
130
-	 *
131
-	 *   @param      User	$user       User that create
132
-	 *   @return     int     		    <0 if KO, >0 if OK
133
-	 */
134
-	function create($user)
135
-	{
136
-		global $conf, $langs;
137
-
138
-		// Clean parameters
139
-		$this->description=trim($this->description);
140
-		if (empty($this->user_agent) && !empty($_SERVER['HTTP_USER_AGENT'])) $this->user_agent=$_SERVER['HTTP_USER_AGENT'];
141
-
142
-		// Check parameters
143
-		if (empty($this->description)) { $this->error='ErrorBadValueForParameterCreateEventDesc'; return -1; }
144
-
145
-		// Insert request
146
-		$sql = "INSERT INTO ".MAIN_DB_PREFIX."events(";
147
-		$sql.= "type,";
148
-		$sql.= "entity,";
149
-		$sql.= "ip,";
150
-		$sql.= "user_agent,";
151
-		$sql.= "dateevent,";
152
-		$sql.= "fk_user,";
153
-		$sql.= "description";
154
-		$sql.= ") VALUES (";
155
-		$sql.= " '".$this->db->escape($this->type)."',";
156
-		$sql.= " ".$conf->entity.",";
157
-		$sql.= " '".$this->db->escape(getUserRemoteIP())."',";
158
-		$sql.= " ".($this->user_agent ? "'".$this->db->escape(dol_trunc($this->user_agent,250))."'" : 'NULL').",";
159
-		$sql.= " '".$this->db->idate($this->dateevent)."',";
160
-		$sql.= " ".($user->id?"'".$this->db->escape($user->id)."'":'NULL').",";
161
-		$sql.= " '".$this->db->escape(dol_trunc($this->description,250))."'";
162
-		$sql.= ")";
163
-
164
-		dol_syslog(get_class($this)."::create", LOG_DEBUG);
165
-		$resql=$this->db->query($sql);
166
-		if ($resql)
167
-		{
168
-			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."events");
169
-			return $this->id;
170
-		}
171
-		else
172
-		{
173
-			$this->error="Error ".$this->db->lasterror();
174
-			return -1;
175
-		}
176
-	}
177
-
178
-
179
-	/**
180
-	 * Update database
181
-	 *
182
-	 * @param	User    $user        	User that modify
183
-	 * @param   int		$notrigger	    0=no, 1=yes (no update trigger)
184
-	 * @return  int         			<0 if KO, >0 if OK
185
-	 */
186
-	function update($user=null, $notrigger=0)
187
-	{
188
-		global $conf, $langs;
189
-
190
-		// Clean parameters
191
-		$this->id=trim($this->id);
192
-		$this->type=trim($this->type);
193
-		$this->description=trim($this->description);
194
-
195
-		// Check parameters
196
-		// Put here code to add control on parameters values
197
-
198
-		// Update request
199
-		$sql = "UPDATE ".MAIN_DB_PREFIX."events SET";
200
-		$sql.= " type='".$this->db->escape($this->type)."',";
201
-		$sql.= " dateevent='".$this->db->idate($this->dateevent)."',";
202
-		$sql.= " description='".$this->db->escape($this->description)."'";
203
-		$sql.= " WHERE rowid=".$this->id;
204
-
205
-		dol_syslog(get_class($this)."::update", LOG_DEBUG);
206
-		$resql = $this->db->query($sql);
207
-		if (! $resql)
208
-		{
209
-			$this->error="Error ".$this->db->lasterror();
210
-			return -1;
211
-		}
212
-		return 1;
213
-	}
214
-
215
-
216
-	/**
217
-	 *  Load object in memory from database
218
-	 *
219
-	 *  @param	int		$id         Id object
220
-	 *  @param  User	$user       User that load
221
-	 *  @return int         		<0 if KO, >0 if OK
222
-	 */
223
-	function fetch($id, $user=null)
224
-	{
225
-		global $langs;
226
-
227
-		$sql = "SELECT";
228
-		$sql.= " t.rowid,";
229
-		$sql.= " t.tms,";
230
-		$sql.= " t.type,";
231
-		$sql.= " t.entity,";
232
-		$sql.= " t.dateevent,";
233
-		$sql.= " t.description,";
234
-		$sql.= " t.ip,";
235
-		$sql.= " t.user_agent";
236
-		$sql.= " FROM ".MAIN_DB_PREFIX."events as t";
237
-		$sql.= " WHERE t.rowid = ".$id;
238
-
239
-		dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
240
-		$resql=$this->db->query($sql);
241
-		if ($resql)
242
-		{
243
-			if ($this->db->num_rows($resql))
244
-			{
245
-				$obj = $this->db->fetch_object($resql);
246
-
247
-				$this->id    = $obj->rowid;
248
-				$this->tms = $this->db->jdate($obj->tms);
249
-				$this->type = $obj->type;
250
-				$this->entity = $obj->entity;
251
-				$this->dateevent = $this->db->jdate($obj->dateevent);
252
-				$this->description = $obj->description;
253
-				$this->ip = $obj->ip;
254
-				$this->user_agent = $obj->user_agent;
255
-			}
256
-			$this->db->free($resql);
257
-
258
-			return 1;
259
-		}
260
-		else
261
-		{
262
-			$this->error="Error ".$this->db->lasterror();
263
-			return -1;
264
-		}
265
-	}
266
-
267
-
268
-	/**
269
-	 *  Delete object in database
270
-	 *
271
-	 *	@param	User	$user       User that delete
272
-	 *	@return	int					<0 if KO, >0 if OK
273
-	 */
274
-	function delete($user)
275
-	{
276
-		global $conf, $langs;
277
-
278
-		$sql = "DELETE FROM ".MAIN_DB_PREFIX."events";
279
-		$sql.= " WHERE rowid=".$this->id;
280
-
281
-		dol_syslog(get_class($this)."::delete", LOG_DEBUG);
282
-		$resql = $this->db->query($sql);
283
-		if (! $resql)
284
-		{
285
-			$this->error="Error ".$this->db->lasterror();
286
-			return -1;
287
-		}
288
-
289
-		return 1;
290
-	}
291
-
292
-
293
-	/**
114
+    );
115
+
116
+
117
+    /**
118
+     *	Constructor
119
+     *
120
+     *  @param		DoliDB		$db      Database handler
121
+     */
122
+    function __construct($db)
123
+    {
124
+        $this->db = $db;
125
+    }
126
+
127
+
128
+    /**
129
+     *   Create in database
130
+     *
131
+     *   @param      User	$user       User that create
132
+     *   @return     int     		    <0 if KO, >0 if OK
133
+     */
134
+    function create($user)
135
+    {
136
+        global $conf, $langs;
137
+
138
+        // Clean parameters
139
+        $this->description=trim($this->description);
140
+        if (empty($this->user_agent) && !empty($_SERVER['HTTP_USER_AGENT'])) $this->user_agent=$_SERVER['HTTP_USER_AGENT'];
141
+
142
+        // Check parameters
143
+        if (empty($this->description)) { $this->error='ErrorBadValueForParameterCreateEventDesc'; return -1; }
144
+
145
+        // Insert request
146
+        $sql = "INSERT INTO ".MAIN_DB_PREFIX."events(";
147
+        $sql.= "type,";
148
+        $sql.= "entity,";
149
+        $sql.= "ip,";
150
+        $sql.= "user_agent,";
151
+        $sql.= "dateevent,";
152
+        $sql.= "fk_user,";
153
+        $sql.= "description";
154
+        $sql.= ") VALUES (";
155
+        $sql.= " '".$this->db->escape($this->type)."',";
156
+        $sql.= " ".$conf->entity.",";
157
+        $sql.= " '".$this->db->escape(getUserRemoteIP())."',";
158
+        $sql.= " ".($this->user_agent ? "'".$this->db->escape(dol_trunc($this->user_agent,250))."'" : 'NULL').",";
159
+        $sql.= " '".$this->db->idate($this->dateevent)."',";
160
+        $sql.= " ".($user->id?"'".$this->db->escape($user->id)."'":'NULL').",";
161
+        $sql.= " '".$this->db->escape(dol_trunc($this->description,250))."'";
162
+        $sql.= ")";
163
+
164
+        dol_syslog(get_class($this)."::create", LOG_DEBUG);
165
+        $resql=$this->db->query($sql);
166
+        if ($resql)
167
+        {
168
+            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."events");
169
+            return $this->id;
170
+        }
171
+        else
172
+        {
173
+            $this->error="Error ".$this->db->lasterror();
174
+            return -1;
175
+        }
176
+    }
177
+
178
+
179
+    /**
180
+     * Update database
181
+     *
182
+     * @param	User    $user        	User that modify
183
+     * @param   int		$notrigger	    0=no, 1=yes (no update trigger)
184
+     * @return  int         			<0 if KO, >0 if OK
185
+     */
186
+    function update($user=null, $notrigger=0)
187
+    {
188
+        global $conf, $langs;
189
+
190
+        // Clean parameters
191
+        $this->id=trim($this->id);
192
+        $this->type=trim($this->type);
193
+        $this->description=trim($this->description);
194
+
195
+        // Check parameters
196
+        // Put here code to add control on parameters values
197
+
198
+        // Update request
199
+        $sql = "UPDATE ".MAIN_DB_PREFIX."events SET";
200
+        $sql.= " type='".$this->db->escape($this->type)."',";
201
+        $sql.= " dateevent='".$this->db->idate($this->dateevent)."',";
202
+        $sql.= " description='".$this->db->escape($this->description)."'";
203
+        $sql.= " WHERE rowid=".$this->id;
204
+
205
+        dol_syslog(get_class($this)."::update", LOG_DEBUG);
206
+        $resql = $this->db->query($sql);
207
+        if (! $resql)
208
+        {
209
+            $this->error="Error ".$this->db->lasterror();
210
+            return -1;
211
+        }
212
+        return 1;
213
+    }
214
+
215
+
216
+    /**
217
+     *  Load object in memory from database
218
+     *
219
+     *  @param	int		$id         Id object
220
+     *  @param  User	$user       User that load
221
+     *  @return int         		<0 if KO, >0 if OK
222
+     */
223
+    function fetch($id, $user=null)
224
+    {
225
+        global $langs;
226
+
227
+        $sql = "SELECT";
228
+        $sql.= " t.rowid,";
229
+        $sql.= " t.tms,";
230
+        $sql.= " t.type,";
231
+        $sql.= " t.entity,";
232
+        $sql.= " t.dateevent,";
233
+        $sql.= " t.description,";
234
+        $sql.= " t.ip,";
235
+        $sql.= " t.user_agent";
236
+        $sql.= " FROM ".MAIN_DB_PREFIX."events as t";
237
+        $sql.= " WHERE t.rowid = ".$id;
238
+
239
+        dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
240
+        $resql=$this->db->query($sql);
241
+        if ($resql)
242
+        {
243
+            if ($this->db->num_rows($resql))
244
+            {
245
+                $obj = $this->db->fetch_object($resql);
246
+
247
+                $this->id    = $obj->rowid;
248
+                $this->tms = $this->db->jdate($obj->tms);
249
+                $this->type = $obj->type;
250
+                $this->entity = $obj->entity;
251
+                $this->dateevent = $this->db->jdate($obj->dateevent);
252
+                $this->description = $obj->description;
253
+                $this->ip = $obj->ip;
254
+                $this->user_agent = $obj->user_agent;
255
+            }
256
+            $this->db->free($resql);
257
+
258
+            return 1;
259
+        }
260
+        else
261
+        {
262
+            $this->error="Error ".$this->db->lasterror();
263
+            return -1;
264
+        }
265
+    }
266
+
267
+
268
+    /**
269
+     *  Delete object in database
270
+     *
271
+     *	@param	User	$user       User that delete
272
+     *	@return	int					<0 if KO, >0 if OK
273
+     */
274
+    function delete($user)
275
+    {
276
+        global $conf, $langs;
277
+
278
+        $sql = "DELETE FROM ".MAIN_DB_PREFIX."events";
279
+        $sql.= " WHERE rowid=".$this->id;
280
+
281
+        dol_syslog(get_class($this)."::delete", LOG_DEBUG);
282
+        $resql = $this->db->query($sql);
283
+        if (! $resql)
284
+        {
285
+            $this->error="Error ".$this->db->lasterror();
286
+            return -1;
287
+        }
288
+
289
+        return 1;
290
+    }
291
+
292
+
293
+    /**
294 294
      *  Initialise an instance with random values.
295 295
      *  Used to build previews or test instances.
296 296
      *	id must be 0 if object instance is a specimen.
297 297
      *
298 298
      *  @return	void
299
-	 */
300
-	function initAsSpecimen()
301
-	{
302
-		$this->id=0;
303
-
304
-		$this->tms=time();
305
-		$this->type='';
306
-		$this->dateevent=time();
307
-		$this->description='This is a specimen event';
308
-	}
299
+     */
300
+    function initAsSpecimen()
301
+    {
302
+        $this->id=0;
303
+
304
+        $this->tms=time();
305
+        $this->type='';
306
+        $this->dateevent=time();
307
+        $this->description='This is a specimen event';
308
+    }
309 309
 }
Please login to merge, or discard this patch.
dolibarr/htdocs/core/class/ctyperesource.class.php 1 patch
Indentation   +418 added lines, -418 removed lines patch added patch discarded remove patch
@@ -32,436 +32,436 @@  discard block
 block discarded – undo
32 32
  */
33 33
 class Ctyperesource
34 34
 {
35
-	/**
36
-	 * @var string Id to identify managed objects
37
-	 */
38
-	public $element = 'ctyperesource';
35
+    /**
36
+     * @var string Id to identify managed objects
37
+     */
38
+    public $element = 'ctyperesource';
39 39
 
40
-	/**
41
-	 * @var string Name of table without prefix where object is stored
42
-	 */
43
-	public $table_element = 'c_type_resource';
40
+    /**
41
+     * @var string Name of table without prefix where object is stored
42
+     */
43
+    public $table_element = 'c_type_resource';
44 44
 
45
-	/**
46
-	 * @var CtyperesourceLine[] Lines
47
-	 */
48
-	public $lines = array();
45
+    /**
46
+     * @var CtyperesourceLine[] Lines
47
+     */
48
+    public $lines = array();
49 49
 
50
-	public $code;
50
+    public $code;
51 51
 
52
-	/**
52
+    /**
53 53
      * @var string Type resource label
54 54
      */
55 55
     public $label;
56 56
 
57
-	public $active;
57
+    public $active;
58
+
59
+
60
+    /**
61
+     * Constructor
62
+     *
63
+     * @param DoliDb $db Database handler
64
+     */
65
+    public function __construct(DoliDB $db)
66
+    {
67
+        $this->db = $db;
68
+    }
69
+
70
+    /**
71
+     * Create object into database
72
+     *
73
+     * @param  User $user      User that creates
74
+     * @param  bool $notrigger false=launch triggers after, true=disable triggers
75
+     *
76
+     * @return int <0 if KO, Id of created object if OK
77
+     */
78
+    public function create(User $user, $notrigger = false)
79
+    {
80
+        dol_syslog(__METHOD__, LOG_DEBUG);
81
+
82
+        $error = 0;
83
+
84
+        // Clean parameters
85
+
86
+        if (isset($this->code)) {
87
+                $this->code = trim($this->code);
88
+        }
89
+        if (isset($this->label)) {
90
+                $this->label = trim($this->label);
91
+        }
92
+        if (isset($this->active)) {
93
+                $this->active = trim($this->active);
94
+        }
95
+
58 96
 
59 97
 
60
-	/**
61
-	 * Constructor
62
-	 *
63
-	 * @param DoliDb $db Database handler
64
-	 */
65
-	public function __construct(DoliDB $db)
66
-	{
67
-		$this->db = $db;
68
-	}
98
+        // Check parameters
99
+        // Put here code to add control on parameters values
69 100
 
70
-	/**
71
-	 * Create object into database
72
-	 *
73
-	 * @param  User $user      User that creates
74
-	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
75
-	 *
76
-	 * @return int <0 if KO, Id of created object if OK
77
-	 */
78
-	public function create(User $user, $notrigger = false)
79
-	{
80
-		dol_syslog(__METHOD__, LOG_DEBUG);
101
+        // Insert request
102
+        $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element . '(';
81 103
 
82
-		$error = 0;
104
+        $sql.= 'code,';
105
+        $sql.= 'label';
106
+        $sql.= 'active';
83 107
 
84
-		// Clean parameters
85 108
 
86
-		if (isset($this->code)) {
87
-			 $this->code = trim($this->code);
88
-		}
89
-		if (isset($this->label)) {
90
-			 $this->label = trim($this->label);
91
-		}
92
-		if (isset($this->active)) {
93
-			 $this->active = trim($this->active);
94
-		}
109
+        $sql .= ') VALUES (';
95 110
 
111
+        $sql .= ' '.(! isset($this->code)?'NULL':"'".$this->db->escape($this->code)."'").',';
112
+        $sql .= ' '.(! isset($this->label)?'NULL':"'".$this->db->escape($this->label)."'").',';
113
+        $sql .= ' '.(! isset($this->active)?'NULL':$this->active);
96 114
 
97 115
 
98
-		// Check parameters
99
-		// Put here code to add control on parameters values
116
+        $sql .= ')';
100 117
 
101
-		// Insert request
102
-		$sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element . '(';
118
+        $this->db->begin();
103 119
 
104
-		$sql.= 'code,';
105
-		$sql.= 'label';
106
-		$sql.= 'active';
120
+        $resql = $this->db->query($sql);
121
+        if (!$resql) {
122
+            $error ++;
123
+            $this->errors[] = 'Error ' . $this->db->lasterror();
124
+            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
125
+        }
107 126
 
127
+        if (!$error) {
128
+            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
108 129
 
109
-		$sql .= ') VALUES (';
130
+            // Uncomment this and change MYOBJECT to your own tag if you
131
+            // want this action to call a trigger.
132
+            //if (!$notrigger) {
110 133
 
111
-		$sql .= ' '.(! isset($this->code)?'NULL':"'".$this->db->escape($this->code)."'").',';
112
-		$sql .= ' '.(! isset($this->label)?'NULL':"'".$this->db->escape($this->label)."'").',';
113
-		$sql .= ' '.(! isset($this->active)?'NULL':$this->active);
134
+            //  // Call triggers
135
+            //  $result=$this->call_trigger('MYOBJECT_CREATE',$user);
136
+            //  if ($result < 0) $error++;
137
+            //  // End call triggers
138
+            //}
139
+        }
114 140
 
141
+        // Commit or rollback
142
+        if ($error) {
143
+            $this->db->rollback();
115 144
 
116
-		$sql .= ')';
145
+            return - 1 * $error;
146
+        } else {
147
+            $this->db->commit();
117 148
 
118
-		$this->db->begin();
119
-
120
-		$resql = $this->db->query($sql);
121
-		if (!$resql) {
122
-			$error ++;
123
-			$this->errors[] = 'Error ' . $this->db->lasterror();
124
-			dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
125
-		}
126
-
127
-		if (!$error) {
128
-			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
129
-
130
-			// Uncomment this and change MYOBJECT to your own tag if you
131
-			// want this action to call a trigger.
132
-			//if (!$notrigger) {
133
-
134
-			//  // Call triggers
135
-			//  $result=$this->call_trigger('MYOBJECT_CREATE',$user);
136
-			//  if ($result < 0) $error++;
137
-			//  // End call triggers
138
-			//}
139
-		}
140
-
141
-		// Commit or rollback
142
-		if ($error) {
143
-			$this->db->rollback();
144
-
145
-			return - 1 * $error;
146
-		} else {
147
-			$this->db->commit();
148
-
149
-			return $this->id;
150
-		}
151
-	}
152
-
153
-	/**
154
-	 * Load object in memory from the database
155
-	 *
156
-	 * @param int    $id  Id object
157
-	 * @param string $code code
158
-	 * @param string $label Label
159
-	 *
160
-	 * @return int <0 if KO, 0 if not found, >0 if OK
161
-	 */
162
-	public function fetch($id,$code='',$label='')
163
-	{
164
-		dol_syslog(__METHOD__, LOG_DEBUG);
165
-
166
-		$sql = 'SELECT';
167
-		$sql .= ' t.rowid,';
168
-
169
-		$sql .= " t.code,";
170
-		$sql .= " t.label,";
171
-		$sql .= " t.active";
172
-
173
-
174
-		$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
175
-		if ($id)   $sql.= " WHERE t.id = ".$id;
176
-		elseif ($code) $sql.= " WHERE t.code = '".$this->db->escape($code)."'";
177
-		elseif ($label) $sql.= " WHERE t.label = '".$this->db->escape($label)."'";
178
-
179
-
180
-		$resql = $this->db->query($sql);
181
-		if ($resql) {
182
-			$numrows = $this->db->num_rows($resql);
183
-			if ($numrows) {
184
-				$obj = $this->db->fetch_object($resql);
185
-
186
-				$this->id = $obj->rowid;
187
-
188
-				$this->code = $obj->code;
189
-				$this->label = $obj->label;
190
-				$this->active = $obj->active;
191
-			}
192
-
193
-			// Retrieve all extrafields for invoice
194
-			// fetch optionals attributes and labels
195
-			// $this->fetch_optionals();
196
-
197
-			// $this->fetch_lines();
198
-
199
-			$this->db->free($resql);
200
-
201
-			if ($numrows) {
202
-				return 1;
203
-			} else {
204
-				return 0;
205
-			}
206
-		} else {
207
-			$this->errors[] = 'Error ' . $this->db->lasterror();
208
-			dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
209
-
210
-			return - 1;
211
-		}
212
-	}
213
-
214
-	/**
215
-	 * Load object in memory from the database
216
-	 *
217
-	 * @param string $sortorder Sort Order
218
-	 * @param string $sortfield Sort field
219
-	 * @param int    $limit     offset limit
220
-	 * @param int    $offset    offset limit
221
-	 * @param array  $filter    filter array
222
-	 * @param string $filtermode filter mode (AND or OR)
223
-	 *
224
-	 * @return int <0 if KO, >0 if OK
225
-	 */
226
-	public function fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter = array(), $filtermode='AND')
227
-	{
228
-		dol_syslog(__METHOD__, LOG_DEBUG);
229
-
230
-		$sql = 'SELECT';
231
-		$sql .= ' t.rowid,';
232
-
233
-		$sql .= " t.code,";
234
-		$sql .= " t.label,";
235
-		$sql .= " t.active";
236
-
237
-
238
-		$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element. ' as t';
239
-
240
-		// Manage filter
241
-		$sqlwhere = array();
242
-		if (count($filter) > 0) {
243
-			foreach ($filter as $key => $value) {
244
-				$sqlwhere [] = $key . ' LIKE \'%' . $this->db->escape($value) . '%\'';
245
-			}
246
-		}
247
-
248
-		if (count($sqlwhere) > 0) {
249
-			$sql .= ' WHERE ' . implode(' '.$filtermode.' ', $sqlwhere);
250
-		}
251
-		if (!empty($sortfield)) {
252
-			$sql .= $this->db->order($sortfield,$sortorder);
253
-		}
254
-		if (!empty($limit)) {
255
-		 $sql .=  ' ' . $this->db->plimit($limit, $offset);
256
-		}
257
-
258
-		$resql = $this->db->query($sql);
259
-		if ($resql) {
260
-			$num = $this->db->num_rows($resql);
261
-
262
-			while ($obj = $this->db->fetch_object($resql)) {
263
-				$line = new self($this->db);
264
-
265
-				$line->id = $obj->rowid;
266
-
267
-				$line->code = $obj->code;
268
-				$line->label = $obj->label;
269
-				$line->active = $obj->active;
270
-			}
271
-			$this->db->free($resql);
272
-
273
-			return $num;
274
-		} else {
275
-			$this->errors[] = 'Error ' . $this->db->lasterror();
276
-			dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
277
-
278
-			return - 1;
279
-		}
280
-	}
281
-
282
-	/**
283
-	 * Update object into database
284
-	 *
285
-	 * @param  User $user      User that modifies
286
-	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
287
-	 *
288
-	 * @return int <0 if KO, >0 if OK
289
-	 */
290
-	public function update(User $user, $notrigger = false)
291
-	{
292
-		$error = 0;
293
-
294
-		dol_syslog(__METHOD__, LOG_DEBUG);
295
-
296
-		// Clean parameters
297
-
298
-		if (isset($this->code)) {
299
-			 $this->code = trim($this->code);
300
-		}
301
-		if (isset($this->label)) {
302
-			 $this->label = trim($this->label);
303
-		}
304
-		if (isset($this->active)) {
305
-			 $this->active = trim($this->active);
306
-		}
307
-
308
-		// Check parameters
309
-		// Put here code to add a control on parameters values
310
-
311
-		// Update request
312
-		$sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . ' SET';
313
-
314
-		$sql .= ' code = '.(isset($this->code)?"'".$this->db->escape($this->code)."'":"null").',';
315
-		$sql .= ' label = '.(isset($this->label)?"'".$this->db->escape($this->label)."'":"null").',';
316
-		$sql .= ' active = '.(isset($this->active)?$this->active:"null");
317
-
318
-
319
-		$sql .= ' WHERE rowid=' . $this->id;
320
-
321
-		$this->db->begin();
322
-
323
-		$resql = $this->db->query($sql);
324
-		if (!$resql) {
325
-			$error ++;
326
-			$this->errors[] = 'Error ' . $this->db->lasterror();
327
-			dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
328
-		}
329
-
330
-		// Uncomment this and change MYOBJECT to your own tag if you
331
-		// want this action calls a trigger.
332
-		//if (!$error && !$notrigger) {
333
-
334
-		//  // Call triggers
335
-		//  $result=$this->call_trigger('MYOBJECT_MODIFY',$user);
336
-		//  if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
337
-		//  // End call triggers
338
-		//}
339
-
340
-		// Commit or rollback
341
-		if ($error) {
342
-			$this->db->rollback();
343
-
344
-			return - 1 * $error;
345
-		} else {
346
-			$this->db->commit();
347
-
348
-			return 1;
349
-		}
350
-	}
351
-
352
-	/**
353
-	 * Delete object in database
354
-	 *
355
-	 * @param User $user      User that deletes
356
-	 * @param bool $notrigger false=launch triggers after, true=disable triggers
357
-	 *
358
-	 * @return int <0 if KO, >0 if OK
359
-	 */
360
-	public function delete(User $user, $notrigger = false)
361
-	{
362
-		dol_syslog(__METHOD__, LOG_DEBUG);
363
-
364
-		$error = 0;
365
-
366
-		$this->db->begin();
367
-
368
-		// Uncomment this and change MYOBJECT to your own tag if you
369
-		// want this action calls a trigger.
370
-		//if (!$error && !$notrigger) {
371
-
372
-		//  // Call triggers
373
-		//  $result=$this->call_trigger('MYOBJECT_DELETE',$user);
374
-		//  if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
375
-		//  // End call triggers
376
-		//}
377
-
378
-		// If you need to delete child tables to, you can insert them here
379
-
380
-		if (!$error) {
381
-			$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element;
382
-			$sql .= ' WHERE rowid=' . $this->id;
383
-
384
-			$resql = $this->db->query($sql);
385
-			if (!$resql) {
386
-				$error ++;
387
-				$this->errors[] = 'Error ' . $this->db->lasterror();
388
-				dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
389
-			}
390
-		}
391
-
392
-		// Commit or rollback
393
-		if ($error) {
394
-			$this->db->rollback();
395
-
396
-			return - 1 * $error;
397
-		} else {
398
-			$this->db->commit();
399
-
400
-			return 1;
401
-		}
402
-	}
403
-
404
-	/**
405
-	 * Load an object from its id and create a new one in database
406
-	 *
407
-	 * @param int $fromid Id of object to clone
408
-	 *
409
-	 * @return int New id of clone
410
-	 */
411
-	public function createFromClone($fromid)
412
-	{
413
-		dol_syslog(__METHOD__, LOG_DEBUG);
414
-
415
-		global $user;
416
-		$error = 0;
417
-		$object = new Ctyperesource($this->db);
418
-
419
-		$this->db->begin();
420
-
421
-		// Load source object
422
-		$object->fetch($fromid);
423
-		// Reset object
424
-		$object->id = 0;
425
-
426
-		// Clear fields
427
-		// ...
428
-
429
-		// Create clone
430
-		$result = $object->create($user);
431
-
432
-		// Other options
433
-		if ($result < 0) {
434
-			$error ++;
435
-			$this->errors = $object->errors;
436
-			dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
437
-		}
438
-
439
-		// End
440
-		if (!$error) {
441
-			$this->db->commit();
442
-
443
-			return $object->id;
444
-		} else {
445
-			$this->db->rollback();
446
-
447
-			return - 1;
448
-		}
449
-	}
450
-
451
-	/**
452
-	 * Initialise object with example values
453
-	 * Id must be 0 if object instance is a specimen
454
-	 *
455
-	 * @return void
456
-	 */
457
-	public function initAsSpecimen()
458
-	{
459
-		$this->id = 0;
460
-
461
-		$this->code = '';
462
-		$this->label = '';
463
-		$this->active = '';
464
-	}
149
+            return $this->id;
150
+        }
151
+    }
152
+
153
+    /**
154
+     * Load object in memory from the database
155
+     *
156
+     * @param int    $id  Id object
157
+     * @param string $code code
158
+     * @param string $label Label
159
+     *
160
+     * @return int <0 if KO, 0 if not found, >0 if OK
161
+     */
162
+    public function fetch($id,$code='',$label='')
163
+    {
164
+        dol_syslog(__METHOD__, LOG_DEBUG);
165
+
166
+        $sql = 'SELECT';
167
+        $sql .= ' t.rowid,';
168
+
169
+        $sql .= " t.code,";
170
+        $sql .= " t.label,";
171
+        $sql .= " t.active";
172
+
173
+
174
+        $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
175
+        if ($id)   $sql.= " WHERE t.id = ".$id;
176
+        elseif ($code) $sql.= " WHERE t.code = '".$this->db->escape($code)."'";
177
+        elseif ($label) $sql.= " WHERE t.label = '".$this->db->escape($label)."'";
178
+
179
+
180
+        $resql = $this->db->query($sql);
181
+        if ($resql) {
182
+            $numrows = $this->db->num_rows($resql);
183
+            if ($numrows) {
184
+                $obj = $this->db->fetch_object($resql);
185
+
186
+                $this->id = $obj->rowid;
187
+
188
+                $this->code = $obj->code;
189
+                $this->label = $obj->label;
190
+                $this->active = $obj->active;
191
+            }
192
+
193
+            // Retrieve all extrafields for invoice
194
+            // fetch optionals attributes and labels
195
+            // $this->fetch_optionals();
196
+
197
+            // $this->fetch_lines();
198
+
199
+            $this->db->free($resql);
200
+
201
+            if ($numrows) {
202
+                return 1;
203
+            } else {
204
+                return 0;
205
+            }
206
+        } else {
207
+            $this->errors[] = 'Error ' . $this->db->lasterror();
208
+            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
209
+
210
+            return - 1;
211
+        }
212
+    }
213
+
214
+    /**
215
+     * Load object in memory from the database
216
+     *
217
+     * @param string $sortorder Sort Order
218
+     * @param string $sortfield Sort field
219
+     * @param int    $limit     offset limit
220
+     * @param int    $offset    offset limit
221
+     * @param array  $filter    filter array
222
+     * @param string $filtermode filter mode (AND or OR)
223
+     *
224
+     * @return int <0 if KO, >0 if OK
225
+     */
226
+    public function fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter = array(), $filtermode='AND')
227
+    {
228
+        dol_syslog(__METHOD__, LOG_DEBUG);
229
+
230
+        $sql = 'SELECT';
231
+        $sql .= ' t.rowid,';
232
+
233
+        $sql .= " t.code,";
234
+        $sql .= " t.label,";
235
+        $sql .= " t.active";
236
+
237
+
238
+        $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element. ' as t';
239
+
240
+        // Manage filter
241
+        $sqlwhere = array();
242
+        if (count($filter) > 0) {
243
+            foreach ($filter as $key => $value) {
244
+                $sqlwhere [] = $key . ' LIKE \'%' . $this->db->escape($value) . '%\'';
245
+            }
246
+        }
247
+
248
+        if (count($sqlwhere) > 0) {
249
+            $sql .= ' WHERE ' . implode(' '.$filtermode.' ', $sqlwhere);
250
+        }
251
+        if (!empty($sortfield)) {
252
+            $sql .= $this->db->order($sortfield,$sortorder);
253
+        }
254
+        if (!empty($limit)) {
255
+            $sql .=  ' ' . $this->db->plimit($limit, $offset);
256
+        }
257
+
258
+        $resql = $this->db->query($sql);
259
+        if ($resql) {
260
+            $num = $this->db->num_rows($resql);
261
+
262
+            while ($obj = $this->db->fetch_object($resql)) {
263
+                $line = new self($this->db);
264
+
265
+                $line->id = $obj->rowid;
266
+
267
+                $line->code = $obj->code;
268
+                $line->label = $obj->label;
269
+                $line->active = $obj->active;
270
+            }
271
+            $this->db->free($resql);
272
+
273
+            return $num;
274
+        } else {
275
+            $this->errors[] = 'Error ' . $this->db->lasterror();
276
+            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
277
+
278
+            return - 1;
279
+        }
280
+    }
281
+
282
+    /**
283
+     * Update object into database
284
+     *
285
+     * @param  User $user      User that modifies
286
+     * @param  bool $notrigger false=launch triggers after, true=disable triggers
287
+     *
288
+     * @return int <0 if KO, >0 if OK
289
+     */
290
+    public function update(User $user, $notrigger = false)
291
+    {
292
+        $error = 0;
293
+
294
+        dol_syslog(__METHOD__, LOG_DEBUG);
295
+
296
+        // Clean parameters
297
+
298
+        if (isset($this->code)) {
299
+                $this->code = trim($this->code);
300
+        }
301
+        if (isset($this->label)) {
302
+                $this->label = trim($this->label);
303
+        }
304
+        if (isset($this->active)) {
305
+                $this->active = trim($this->active);
306
+        }
307
+
308
+        // Check parameters
309
+        // Put here code to add a control on parameters values
310
+
311
+        // Update request
312
+        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . ' SET';
313
+
314
+        $sql .= ' code = '.(isset($this->code)?"'".$this->db->escape($this->code)."'":"null").',';
315
+        $sql .= ' label = '.(isset($this->label)?"'".$this->db->escape($this->label)."'":"null").',';
316
+        $sql .= ' active = '.(isset($this->active)?$this->active:"null");
317
+
318
+
319
+        $sql .= ' WHERE rowid=' . $this->id;
320
+
321
+        $this->db->begin();
322
+
323
+        $resql = $this->db->query($sql);
324
+        if (!$resql) {
325
+            $error ++;
326
+            $this->errors[] = 'Error ' . $this->db->lasterror();
327
+            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
328
+        }
329
+
330
+        // Uncomment this and change MYOBJECT to your own tag if you
331
+        // want this action calls a trigger.
332
+        //if (!$error && !$notrigger) {
333
+
334
+        //  // Call triggers
335
+        //  $result=$this->call_trigger('MYOBJECT_MODIFY',$user);
336
+        //  if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
337
+        //  // End call triggers
338
+        //}
339
+
340
+        // Commit or rollback
341
+        if ($error) {
342
+            $this->db->rollback();
343
+
344
+            return - 1 * $error;
345
+        } else {
346
+            $this->db->commit();
347
+
348
+            return 1;
349
+        }
350
+    }
351
+
352
+    /**
353
+     * Delete object in database
354
+     *
355
+     * @param User $user      User that deletes
356
+     * @param bool $notrigger false=launch triggers after, true=disable triggers
357
+     *
358
+     * @return int <0 if KO, >0 if OK
359
+     */
360
+    public function delete(User $user, $notrigger = false)
361
+    {
362
+        dol_syslog(__METHOD__, LOG_DEBUG);
363
+
364
+        $error = 0;
365
+
366
+        $this->db->begin();
367
+
368
+        // Uncomment this and change MYOBJECT to your own tag if you
369
+        // want this action calls a trigger.
370
+        //if (!$error && !$notrigger) {
371
+
372
+        //  // Call triggers
373
+        //  $result=$this->call_trigger('MYOBJECT_DELETE',$user);
374
+        //  if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
375
+        //  // End call triggers
376
+        //}
377
+
378
+        // If you need to delete child tables to, you can insert them here
379
+
380
+        if (!$error) {
381
+            $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element;
382
+            $sql .= ' WHERE rowid=' . $this->id;
383
+
384
+            $resql = $this->db->query($sql);
385
+            if (!$resql) {
386
+                $error ++;
387
+                $this->errors[] = 'Error ' . $this->db->lasterror();
388
+                dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
389
+            }
390
+        }
391
+
392
+        // Commit or rollback
393
+        if ($error) {
394
+            $this->db->rollback();
395
+
396
+            return - 1 * $error;
397
+        } else {
398
+            $this->db->commit();
399
+
400
+            return 1;
401
+        }
402
+    }
403
+
404
+    /**
405
+     * Load an object from its id and create a new one in database
406
+     *
407
+     * @param int $fromid Id of object to clone
408
+     *
409
+     * @return int New id of clone
410
+     */
411
+    public function createFromClone($fromid)
412
+    {
413
+        dol_syslog(__METHOD__, LOG_DEBUG);
414
+
415
+        global $user;
416
+        $error = 0;
417
+        $object = new Ctyperesource($this->db);
418
+
419
+        $this->db->begin();
420
+
421
+        // Load source object
422
+        $object->fetch($fromid);
423
+        // Reset object
424
+        $object->id = 0;
425
+
426
+        // Clear fields
427
+        // ...
428
+
429
+        // Create clone
430
+        $result = $object->create($user);
431
+
432
+        // Other options
433
+        if ($result < 0) {
434
+            $error ++;
435
+            $this->errors = $object->errors;
436
+            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
437
+        }
438
+
439
+        // End
440
+        if (!$error) {
441
+            $this->db->commit();
442
+
443
+            return $object->id;
444
+        } else {
445
+            $this->db->rollback();
446
+
447
+            return - 1;
448
+        }
449
+    }
450
+
451
+    /**
452
+     * Initialise object with example values
453
+     * Id must be 0 if object instance is a specimen
454
+     *
455
+     * @return void
456
+     */
457
+    public function initAsSpecimen()
458
+    {
459
+        $this->id = 0;
460
+
461
+        $this->code = '';
462
+        $this->label = '';
463
+        $this->active = '';
464
+    }
465 465
 }
466 466
 
467 467
 /**
@@ -469,24 +469,24 @@  discard block
 block discarded – undo
469 469
  */
470 470
 class CtyperesourceLine
471 471
 {
472
-	/**
473
-	 * @var int ID
474
-	 */
475
-	public $id;
472
+    /**
473
+     * @var int ID
474
+     */
475
+    public $id;
476 476
 
477
-	/**
478
-	 * @var mixed Sample line property 1
479
-	 */
480
-	public $code;
477
+    /**
478
+     * @var mixed Sample line property 1
479
+     */
480
+    public $code;
481 481
 
482
-	/**
482
+    /**
483 483
      * @var string Type resource line label
484 484
      */
485 485
     public $label;
486 486
 
487
-	public $active;
487
+    public $active;
488 488
 
489
-	/**
490
-	 * @var mixed Sample line property 2
491
-	 */
489
+    /**
490
+     * @var mixed Sample line property 2
491
+     */
492 492
 }
Please login to merge, or discard this patch.
dolibarr/htdocs/core/class/html.formsms.class.php 1 patch
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -102,7 +102,7 @@  discard block
 block discarded – undo
102 102
      */
103 103
     function show_form($morecss='titlefield', $showform=1)
104 104
     {
105
-     // phpcs:enable
105
+        // phpcs:enable
106 106
         global $conf, $langs, $user, $form;
107 107
 
108 108
         if (! is_object($form)) $form=new Form($this->db);
@@ -218,13 +218,13 @@  discard block
 block discarded – undo
218 218
                         $classname=ucfirst($classfile);
219 219
                         if (class_exists($classname))
220 220
                         {
221
-                        	$sms = new $classname($this->db);
222
-                        	$resultsender = $sms->SmsSenderList();
221
+                            $sms = new $classname($this->db);
222
+                            $resultsender = $sms->SmsSenderList();
223 223
                         }
224 224
                         else
225 225
                         {
226
-                        	$sms = new stdClass();
227
-                        	$sms->error='The SMS manager "'.$classfile.'" defined into SMS setup MAIN_SMS_SENDMODE is not found';
226
+                            $sms = new stdClass();
227
+                            $sms->error='The SMS manager "'.$classfile.'" defined into SMS setup MAIN_SMS_SENDMODE is not found';
228 228
                         }
229 229
                     }
230 230
                     catch(Exception $e)
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
                 else
237 237
                 {
238 238
                     dol_syslog("Warning: The SMS sending method has not been defined into MAIN_SMS_SENDMODE", LOG_WARNING);
239
-	                $resultsender=array();
239
+                    $resultsender=array();
240 240
                     $resultsender[0]->number=$this->fromsms;
241 241
                 }
242 242
 
Please login to merge, or discard this patch.
dolibarr/htdocs/core/class/rssparser.class.php 1 patch
Indentation   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -32,9 +32,9 @@  discard block
 block discarded – undo
32 32
     public $db;
33 33
 
34 34
     /**
35
-	 * @var string Error code (or message)
36
-	 */
37
-	public $error='';
35
+     * @var string Error code (or message)
36
+     */
37
+    public $error='';
38 38
 
39 39
     private $_format='';
40 40
     private $_urlRSS;
@@ -61,7 +61,7 @@  discard block
 block discarded – undo
61 61
      */
62 62
     public function __construct($db)
63 63
     {
64
-    	$this->db = $db;
64
+        $this->db = $db;
65 65
     }
66 66
 
67 67
     /**
@@ -252,28 +252,28 @@  discard block
 block discarded – undo
252 252
 
253 253
         if ($str !== false)
254 254
         {
255
-	        // Convert $str into xml
256
-	        if (! empty($conf->global->EXTERNALRSS_USE_SIMPLEXML))
257
-	        {
258
-	            //print 'xx'.LIBXML_NOCDATA;
259
-	            libxml_use_internal_errors(false);
260
-	            $rss = simplexml_load_string($str, "SimpleXMLElement", LIBXML_NOCDATA);
261
-	        }
262
-	        else
263
-	        {
264
-	            $xmlparser=xml_parser_create('');
265
-	            if (!is_resource($xmlparser)) {
266
-	                $this->error="ErrorFailedToCreateParser"; return -1;
267
-	            }
268
-
269
-	            xml_set_object($xmlparser, $this);
270
-	            xml_set_element_handler($xmlparser, 'feed_start_element', 'feed_end_element');
271
-	            xml_set_character_data_handler($xmlparser, 'feed_cdata');
272
-	            $status = xml_parse($xmlparser, $str);
273
-	            xml_parser_free($xmlparser);
274
-	            $rss=$this;
275
-	            //var_dump($rss->_format);exit;
276
-	        }
255
+            // Convert $str into xml
256
+            if (! empty($conf->global->EXTERNALRSS_USE_SIMPLEXML))
257
+            {
258
+                //print 'xx'.LIBXML_NOCDATA;
259
+                libxml_use_internal_errors(false);
260
+                $rss = simplexml_load_string($str, "SimpleXMLElement", LIBXML_NOCDATA);
261
+            }
262
+            else
263
+            {
264
+                $xmlparser=xml_parser_create('');
265
+                if (!is_resource($xmlparser)) {
266
+                    $this->error="ErrorFailedToCreateParser"; return -1;
267
+                }
268
+
269
+                xml_set_object($xmlparser, $this);
270
+                xml_set_element_handler($xmlparser, 'feed_start_element', 'feed_end_element');
271
+                xml_set_character_data_handler($xmlparser, 'feed_cdata');
272
+                $status = xml_parse($xmlparser, $str);
273
+                xml_parser_free($xmlparser);
274
+                $rss=$this;
275
+                //var_dump($rss->_format);exit;
276
+            }
277 277
         }
278 278
 
279 279
         // If $rss loaded
@@ -287,16 +287,16 @@  discard block
 block discarded – undo
287 287
                 $fp = fopen($newpathofdestfile, 'w');
288 288
                 if ($fp)
289 289
                 {
290
-                	fwrite($fp, $str);
291
-                	fclose($fp);
292
-                	if (! empty($conf->global->MAIN_UMASK)) $newmask=$conf->global->MAIN_UMASK;
293
-                	@chmod($newpathofdestfile, octdec($newmask));
290
+                    fwrite($fp, $str);
291
+                    fclose($fp);
292
+                    if (! empty($conf->global->MAIN_UMASK)) $newmask=$conf->global->MAIN_UMASK;
293
+                    @chmod($newpathofdestfile, octdec($newmask));
294 294
 
295
-	                $this->_lastfetchdate=$nowgmt;
295
+                    $this->_lastfetchdate=$nowgmt;
296 296
                 }
297 297
                 else
298 298
                 {
299
-                	print 'Error, failed to open file '.$newpathofdestfile.' for write';
299
+                    print 'Error, failed to open file '.$newpathofdestfile.' for write';
300 300
                 }
301 301
             }
302 302
 
@@ -435,13 +435,13 @@  discard block
 block discarded – undo
435 435
 
436 436
                     // Add record to result array
437 437
                     $this->_rssarray[$i] = array(
438
-    					'link'=>$itemLink,
439
-    					'title'=>$itemTitle,
440
-    					'description'=>$itemDescription,
441
-    					'pubDate'=>$itemPubDate,
442
-    					'category'=>$itemCategory,
443
-    				    'id'=>$itemId,
444
-    				    'author'=>$itemAuthor);
438
+                        'link'=>$itemLink,
439
+                        'title'=>$itemTitle,
440
+                        'description'=>$itemDescription,
441
+                        'pubDate'=>$itemPubDate,
442
+                        'category'=>$itemCategory,
443
+                        'id'=>$itemId,
444
+                        'author'=>$itemAuthor);
445 445
                     //var_dump($this->_rssarray);
446 446
 
447 447
                     $i++;
Please login to merge, or discard this patch.
dolibarr/htdocs/core/class/menu.class.php 1 patch
Indentation   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -31,11 +31,11 @@  discard block
 block discarded – undo
31 31
     var $liste;
32 32
 
33 33
     /**
34
-	 *	Constructor
34
+     *	Constructor
35 35
      */
36 36
     function __construct()
37 37
     {
38
-      	$this->liste = array();
38
+            $this->liste = array();
39 39
     }
40 40
 
41 41
     /**
@@ -67,7 +67,7 @@  discard block
 block discarded – undo
67 67
      */
68 68
     function add($url, $titre, $level=0, $enabled=1, $target='',$mainmenu='',$leftmenu='',$position=0, $id='', $idsel='', $classname='', $prefix='')
69 69
     {
70
-    	$this->liste[]=array('url'=>$url,'titre'=>$titre,'level'=>$level,'enabled'=>$enabled,'target'=>$target,'mainmenu'=>$mainmenu,'leftmenu'=>$leftmenu, 'position'=>$position, 'id'=>$id, 'idsel'=>$idsel, 'classname'=>$classname, 'prefix'=>$prefix);
70
+        $this->liste[]=array('url'=>$url,'titre'=>$titre,'level'=>$level,'enabled'=>$enabled,'target'=>$target,'mainmenu'=>$mainmenu,'leftmenu'=>$leftmenu, 'position'=>$position, 'id'=>$id, 'idsel'=>$idsel, 'classname'=>$classname, 'prefix'=>$prefix);
71 71
     }
72 72
 
73 73
     /**
Please login to merge, or discard this patch.