Passed
Push — master ( 3cffbe...0f9140 )
by Alxarafe
23:50
created

Base/AlCommonObject.php (101 issues)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
1949
				return 1;
1950
			}
1951
			else
1952
			{
1953
				dol_syslog(get_class($this).'::setPaymentTerms Erreur '.$sql.' - '.$this->db->error());
1954
				$this->error=$this->db->error();
1955
				return -1;
1956
			}
1957
		}
1958
		else
1959
		{
1960
			dol_syslog(get_class($this).'::setPaymentTerms, status of the object is incompatible');
1961
			$this->error='Status of the object is incompatible '.$this->statut;
1962
			return -2;
1963
		}
1964
	}
1965
1966
	/**
1967
	 *	Define delivery address
1968
	 *  @deprecated
1969
	 *
1970
	 *	@param      int		$id		Address id
1971
	 *	@return     int				<0 si ko, >0 si ok
1972
	 */
1973
	function setDeliveryAddress($id)
1974
	{
1975
		$fieldname = 'fk_delivery_address';
1976
		if ($this->element == 'delivery' || $this->element == 'shipping') $fieldname = 'fk_address';
1977
1978
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET ".$fieldname." = ".$id;
1979
		$sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
1980
1981
		if ($this->db->query($sql))
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
1982
		{
1983
			$this->fk_delivery_address = $id;
1984
			return 1;
1985
		}
1986
		else
1987
		{
1988
			$this->error=$this->db->error();
1989
			dol_syslog(get_class($this).'::setDeliveryAddress Erreur '.$sql.' - '.$this->error);
1990
			return -1;
1991
		}
1992
	}
1993
1994
1995
	/**
1996
	 *  Change the shipping method
1997
	 *
1998
	 *  @param      int     $shipping_method_id     Id of shipping method
1999
     *  @param      bool    $notrigger              false=launch triggers after, true=disable triggers
2000
     *  @param      User	$userused               Object user
2001
	 *
2002
	 *  @return     int              1 if OK, 0 if KO
2003
	 */
2004
	function setShippingMethod($shipping_method_id, $notrigger=false, $userused=null)
2005
	{
2006
        global $user;
2007
2008
        if (empty($userused)) $userused=$user;
2009
2010
        $error = 0;
2011
2012
		if (! $this->table_element) {
2013
			dol_syslog(get_class($this)."::setShippingMethod was called on objet with property table_element not defined",LOG_ERR);
2014
			return -1;
2015
		}
2016
2017
        $this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2018
2019
		if ($shipping_method_id<0) $shipping_method_id='NULL';
2020
		dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')');
2021
2022
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2023
		$sql.= " SET fk_shipping_method = ".$shipping_method_id;
2024
		$sql.= " WHERE rowid=".$this->id;
2025
        $resql = $this->db->query($sql);
2026
		if (! $resql) {
2027
			dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG);
2028
			$this->error = $this->db->lasterror();
2029
			$error++;
2030
        } else {
2031
            if (!$notrigger)
2032
            {
2033
                // Call trigger
2034
                $this->context=array('shippingmethodupdate'=>1);
2035
                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2036
                if ($result < 0) $error++;
2037
                // End call trigger
2038
            }
2039
        }
2040
        if ($error)
2041
        {
2042
            $this->db->rollback();
2043
            return -1;
2044
        } else {
2045
            $this->shipping_method_id = ($shipping_method_id=='NULL')?null:$shipping_method_id;
2046
            $this->db->commit();
2047
            return 1;
2048
        }
2049
	}
2050
2051
2052
	/**
2053
	 *  Change the warehouse
2054
	 *
2055
	 *  @param      int     $warehouse_id     Id of warehouse
2056
	 *  @return     int              1 if OK, 0 if KO
2057
	 */
2058
	function setWarehouse($warehouse_id)
2059
	{
2060
		if (! $this->table_element) {
2061
			dol_syslog(get_class($this)."::setWarehouse was called on objet with property table_element not defined",LOG_ERR);
2062
			return -1;
2063
		}
2064
		if ($warehouse_id<0) $warehouse_id='NULL';
2065
		dol_syslog(get_class($this).'::setWarehouse('.$warehouse_id.')');
2066
2067
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2068
		$sql.= " SET fk_warehouse = ".$warehouse_id;
2069
		$sql.= " WHERE rowid=".$this->id;
2070
2071
		if ($this->db->query($sql)) {
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2072
			$this->warehouse_id = ($warehouse_id=='NULL')?null:$warehouse_id;
2073
			return 1;
2074
		} else {
2075
			dol_syslog(get_class($this).'::setWarehouse Error ', LOG_DEBUG);
2076
			$this->error=$this->db->error();
2077
			return 0;
2078
		}
2079
	}
2080
2081
2082
	/**
2083
	 *		Set last model used by doc generator
2084
	 *
2085
	 *		@param		User	$user		User object that make change
2086
	 *		@param		string	$modelpdf	Modele name
2087
	 *		@return		int					<0 if KO, >0 if OK
2088
	 */
2089
	function setDocModel($user, $modelpdf)
2090
	{
2091
		if (! $this->table_element)
2092
		{
2093
			dol_syslog(get_class($this)."::setDocModel was called on objet with property table_element not defined",LOG_ERR);
2094
			return -1;
2095
		}
2096
2097
		$newmodelpdf=dol_trunc($modelpdf,255);
2098
2099
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2100
		$sql.= " SET model_pdf = '".$this->db->escape($newmodelpdf)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2101
		$sql.= " WHERE rowid = ".$this->id;
2102
		// if ($this->element == 'facture') $sql.= " AND fk_statut < 2";
2103
		// if ($this->element == 'propal')  $sql.= " AND fk_statut = 0";
2104
2105
		dol_syslog(get_class($this)."::setDocModel", LOG_DEBUG);
2106
		$resql=$this->db->query($sql);
2107
		if ($resql)
2108
		{
2109
			$this->modelpdf=$modelpdf;
2110
			return 1;
2111
		}
2112
		else
2113
		{
2114
			dol_print_error($this->db);
2115
			return 0;
2116
		}
2117
	}
2118
2119
2120
	/**
2121
	 *  Change the bank account
2122
	 *
2123
	 *  @param		int		$fk_account		Id of bank account
2124
	 *  @param      bool    $notrigger      false=launch triggers after, true=disable triggers
2125
	 *  @param      User	$userused		Object user
2126
	 *  @return		int				1 if OK, 0 if KO
2127
	 */
2128
	function setBankAccount($fk_account, $notrigger=false, $userused=null)
2129
	{
2130
        global $user;
2131
2132
        if (empty($userused)) $userused=$user;
2133
2134
        $error = 0;
2135
2136
		if (! $this->table_element) {
2137
			dol_syslog(get_class($this)."::setBankAccount was called on objet with property table_element not defined",LOG_ERR);
2138
			return -1;
2139
		}
2140
        $this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2141
2142
		if ($fk_account<0) $fk_account='NULL';
2143
		dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')');
2144
2145
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2146
		$sql.= " SET fk_account = ".$fk_account;
2147
		$sql.= " WHERE rowid=".$this->id;
2148
2149
        $resql = $this->db->query($sql);
2150
        if (! $resql)
2151
        {
2152
            dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error());
2153
            $this->error = $this->db->lasterror();
2154
            $error++;
2155
        }
2156
        else
2157
        {
2158
            if (!$notrigger)
2159
            {
2160
                // Call trigger
2161
                $this->context=array('bankaccountupdate'=>1);
2162
                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2163
                if ($result < 0) $error++;
2164
                // End call trigger
2165
            }
2166
        }
2167
        if ($error)
2168
        {
2169
            $this->db->rollback();
2170
            return -1;
2171
        }
2172
        else
2173
        {
2174
            $this->fk_account = ($fk_account=='NULL')?null:$fk_account;
2175
            $this->db->commit();
2176
            return 1;
2177
        }
2178
    }
2179
2180
2181
	// TODO: Move line related operations to CommonObjectLine?
2182
2183
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2184
	/**
2185
	 *  Save a new position (field rang) for details lines.
2186
	 *  You can choose to set position for lines with already a position or lines without any position defined.
2187
	 *
2188
	 * 	@param		boolean		$renum			   True to renum all already ordered lines, false to renum only not already ordered lines.
2189
	 * 	@param		string		$rowidorder		   ASC or DESC
2190
	 * 	@param		boolean		$fk_parent_line    Table with fk_parent_line field or not
2191
	 * 	@return		int                            <0 if KO, >0 if OK
2192
	 */
2193
	function line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
2194
	{
2195
        // phpcs:enable
2196
		if (! $this->table_element_line)
2197
		{
2198
			dol_syslog(get_class($this)."::line_order was called on objet with property table_element_line not defined",LOG_ERR);
2199
			return -1;
2200
		}
2201
		if (! $this->fk_element)
2202
		{
2203
			dol_syslog(get_class($this)."::line_order was called on objet with property fk_element not defined",LOG_ERR);
2204
			return -1;
2205
		}
2206
2207
		// Count number of lines to reorder (according to choice $renum)
2208
		$nl=0;
2209
		$sql = 'SELECT count(rowid) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2210
		$sql.= ' WHERE '.$this->fk_element.'='.$this->id;
2211
		if (! $renum) $sql.= ' AND rang = 0';
2212
		if ($renum) $sql.= ' AND rang <> 0';
2213
2214
		dol_syslog(get_class($this)."::line_order", LOG_DEBUG);
2215
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2216
		if ($resql)
2217
		{
2218
			$row = $this->db->fetch_row($resql);
2219
			$nl = $row[0];
2220
		}
2221
		else dol_print_error($this->db);
2222
		if ($nl > 0)
2223
		{
2224
			// The goal of this part is to reorder all lines, with all children lines sharing the same
2225
			// counter that parents.
2226
			$rows=array();
2227
2228
			// We first search all lines that are parent lines (for multilevel details lines)
2229
			$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2230
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2231
			if ($fk_parent_line) $sql.= ' AND fk_parent_line IS NULL';
2232
			$sql.= ' ORDER BY rang ASC, rowid '.$rowidorder;
2233
2234
			dol_syslog(get_class($this)."::line_order search all parent lines", LOG_DEBUG);
2235
			$resql = $this->db->query($sql);
2236
			if ($resql)
2237
			{
2238
				$i=0;
2239
				$num = $this->db->num_rows($resql);
2240
				while ($i < $num)
2241
				{
2242
					$row = $this->db->fetch_row($resql);
2243
					$rows[] = $row[0];	// Add parent line into array rows
2244
					$childrens = $this->getChildrenOfLine($row[0]);
2245
					if (! empty($childrens))
2246
					{
2247
						foreach($childrens as $child)
2248
						{
2249
							array_push($rows, $child);
2250
						}
2251
					}
2252
					$i++;
2253
				}
2254
2255
				// Now we set a new number for each lines (parent and children with children included into parent tree)
2256
				if (! empty($rows))
2257
				{
2258
					foreach($rows as $key => $row)
2259
					{
2260
						$this->updateRangOfLine($row, ($key+1));
2261
					}
2262
				}
2263
			}
2264
			else
2265
			{
2266
				dol_print_error($this->db);
2267
			}
2268
		}
2269
		return 1;
2270
	}
2271
2272
	/**
2273
	 * 	Get children of line
2274
	 *
2275
	 * 	@param	int		$id		Id of parent line
2276
	 * 	@return	array			Array with list of children lines id
2277
	 */
2278
	function getChildrenOfLine($id)
2279
	{
2280
		$rows=array();
2281
2282
		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2283
		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2284
		$sql.= ' AND fk_parent_line = '.$id;
2285
		$sql.= ' ORDER BY rang ASC';
2286
2287
		dol_syslog(get_class($this)."::getChildrenOfLine search children lines for line ".$id."", LOG_DEBUG);
2288
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2289
		if ($resql)
2290
		{
2291
			$i=0;
2292
			$num = $this->db->num_rows($resql);
2293
			while ($i < $num)
2294
			{
2295
				$row = $this->db->fetch_row($resql);
2296
				$rows[$i] = $row[0];
2297
				$i++;
2298
			}
2299
		}
2300
2301
		return $rows;
2302
	}
2303
2304
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2305
	/**
2306
	 * 	Update a line to have a lower rank
2307
	 *
2308
	 * 	@param 	int			$rowid				Id of line
2309
	 * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2310
	 * 	@return	void
2311
	 */
2312
	function line_up($rowid, $fk_parent_line=true)
2313
	{
2314
        // phpcs:enable
2315
		$this->line_order(false, 'ASC', $fk_parent_line);
2316
2317
		// Get rang of line
2318
		$rang = $this->getRangOfLine($rowid);
2319
2320
		// Update position of line
2321
		$this->updateLineUp($rowid, $rang);
2322
	}
2323
2324
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2325
	/**
2326
	 * 	Update a line to have a higher rank
2327
	 *
2328
	 * 	@param	int			$rowid				Id of line
2329
	 * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2330
	 * 	@return	void
2331
	 */
2332
	function line_down($rowid, $fk_parent_line=true)
2333
	{
2334
        // phpcs:enable
2335
		$this->line_order(false, 'ASC', $fk_parent_line);
2336
2337
		// Get rang of line
2338
		$rang = $this->getRangOfLine($rowid);
2339
2340
		// Get max value for rang
2341
		$max = $this->line_max();
2342
2343
		// Update position of line
2344
		$this->updateLineDown($rowid, $rang, $max);
2345
	}
2346
2347
	/**
2348
	 * 	Update position of line (rang)
2349
	 *
2350
	 * 	@param	int		$rowid		Id of line
2351
	 * 	@param	int		$rang		Position
2352
	 * 	@return	void
2353
	 */
2354
	function updateRangOfLine($rowid,$rang)
2355
	{
2356
		$fieldposition = 'rang';
2357
		if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2358
2359
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2360
		$sql.= ' WHERE rowid = '.$rowid;
2361
2362
		dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
2363
		if (! $this->db->query($sql))
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2364
		{
2365
			dol_print_error($this->db);
2366
		}
2367
	}
2368
2369
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2370
	/**
2371
	 * 	Update position of line with ajax (rang)
2372
	 *
2373
	 * 	@param	array	$rows	Array of rows
2374
	 * 	@return	void
2375
	 */
2376
	function line_ajaxorder($rows)
2377
	{
2378
        // phpcs:enable
2379
		$num = count($rows);
2380
		for ($i = 0 ; $i < $num ; $i++)
2381
		{
2382
			$this->updateRangOfLine($rows[$i], ($i+1));
2383
		}
2384
	}
2385
2386
	/**
2387
	 * 	Update position of line up (rang)
2388
	 *
2389
	 * 	@param	int		$rowid		Id of line
2390
	 * 	@param	int		$rang		Position
2391
	 * 	@return	void
2392
	 */
2393
	function updateLineUp($rowid,$rang)
2394
	{
2395
		if ($rang > 1)
2396
		{
2397
			$fieldposition = 'rang';
2398
			if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2399
2400
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang ;
2401
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2402
			$sql.= ' AND rang = '.($rang - 1);
2403
			if ($this->db->query($sql) )
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2404
			{
2405
				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang - 1);
2406
				$sql.= ' WHERE rowid = '.$rowid;
2407
				if (! $this->db->query($sql) )
2408
				{
2409
					dol_print_error($this->db);
2410
				}
2411
			}
2412
			else
2413
			{
2414
				dol_print_error($this->db);
2415
			}
2416
		}
2417
	}
2418
2419
	/**
2420
	 * 	Update position of line down (rang)
2421
	 *
2422
	 * 	@param	int		$rowid		Id of line
2423
	 * 	@param	int		$rang		Position
2424
	 * 	@param	int		$max		Max
2425
	 * 	@return	void
2426
	 */
2427
	function updateLineDown($rowid,$rang,$max)
2428
	{
2429
		if ($rang < $max)
2430
		{
2431
			$fieldposition = 'rang';
2432
			if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2433
2434
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2435
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2436
			$sql.= ' AND rang = '.($rang+1);
2437
			if ($this->db->query($sql) )
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2438
			{
2439
				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang+1);
2440
				$sql.= ' WHERE rowid = '.$rowid;
2441
				if (! $this->db->query($sql) )
2442
				{
2443
					dol_print_error($this->db);
2444
				}
2445
			}
2446
			else
2447
			{
2448
				dol_print_error($this->db);
2449
			}
2450
		}
2451
	}
2452
2453
	/**
2454
	 * 	Get position of line (rang)
2455
	 *
2456
	 * 	@param		int		$rowid		Id of line
2457
	 *  @return		int     			Value of rang in table of lines
2458
	 */
2459
	function getRangOfLine($rowid)
2460
	{
2461
		$sql = 'SELECT rang FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2462
		$sql.= ' WHERE rowid ='.$rowid;
2463
2464
		dol_syslog(get_class($this)."::getRangOfLine", LOG_DEBUG);
2465
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2466
		if ($resql)
2467
		{
2468
			$row = $this->db->fetch_row($resql);
2469
			return $row[0];
2470
		}
2471
	}
2472
2473
	/**
2474
	 * 	Get rowid of the line relative to its position
2475
	 *
2476
	 * 	@param		int		$rang		Rang value
2477
	 *  @return     int     			Rowid of the line
2478
	 */
2479
	function getIdOfLine($rang)
2480
	{
2481
		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2482
		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2483
		$sql.= ' AND rang = '.$rang;
2484
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2485
		if ($resql)
2486
		{
2487
			$row = $this->db->fetch_row($resql);
2488
			return $row[0];
2489
		}
2490
	}
2491
2492
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2493
	/**
2494
	 * 	Get max value used for position of line (rang)
2495
	 *
2496
	 * 	@param		int		$fk_parent_line		Parent line id
2497
	 *  @return     int  			   			Max value of rang in table of lines
2498
	 */
2499
	function line_max($fk_parent_line=0)
2500
	{
2501
        // phpcs:enable
2502
		// Search the last rang with fk_parent_line
2503
		if ($fk_parent_line)
2504
		{
2505
			$sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2506
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2507
			$sql.= ' AND fk_parent_line = '.$fk_parent_line;
2508
2509
			dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2510
			$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2511
			if ($resql)
2512
			{
2513
				$row = $this->db->fetch_row($resql);
2514
				if (! empty($row[0]))
2515
				{
2516
					return $row[0];
2517
				}
2518
				else
2519
				{
2520
					return $this->getRangOfLine($fk_parent_line);
2521
				}
2522
			}
2523
		}
2524
		// If not, search the last rang of element
2525
		else
2526
		{
2527
			$sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2528
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2529
2530
			dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2531
			$resql = $this->db->query($sql);
2532
			if ($resql)
2533
			{
2534
				$row = $this->db->fetch_row($resql);
2535
				return $row[0];
2536
			}
2537
		}
2538
	}
2539
2540
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2541
	/**
2542
	 *  Update external ref of element
2543
	 *
2544
	 *  @param      string		$ref_ext	Update field ref_ext
2545
	 *  @return     int      		   		<0 if KO, >0 if OK
2546
	 */
2547
	function update_ref_ext($ref_ext)
2548
	{
2549
        // phpcs:enable
2550
		if (! $this->table_element)
2551
		{
2552
			dol_syslog(get_class($this)."::update_ref_ext was called on objet with property table_element not defined", LOG_ERR);
2553
			return -1;
2554
		}
2555
2556
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2557
		$sql.= " SET ref_ext = '".$this->db->escape($ref_ext)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2558
		$sql.= " WHERE ".(isset($this->table_rowid)?$this->table_rowid:'rowid')." = ". $this->id;
2559
2560
		dol_syslog(get_class($this)."::update_ref_ext", LOG_DEBUG);
2561
		if ($this->db->query($sql))
2562
		{
2563
			$this->ref_ext = $ref_ext;
2564
			return 1;
2565
		}
2566
		else
2567
		{
2568
			$this->error=$this->db->error();
2569
			return -1;
2570
		}
2571
	}
2572
2573
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2574
	/**
2575
	 *  Update note of element
2576
	 *
2577
	 *  @param      string		$note		New value for note
2578
	 *  @param		string		$suffix		'', '_public' or '_private'
2579
	 *  @return     int      		   		<0 if KO, >0 if OK
2580
	 */
2581
	function update_note($note, $suffix='')
2582
	{
2583
        // phpcs:enable
2584
		global $user;
2585
2586
		if (! $this->table_element)
2587
		{
2588
			$this->error='update_note was called on objet with property table_element not defined';
2589
			dol_syslog(get_class($this)."::update_note was called on objet with property table_element not defined", LOG_ERR);
2590
			return -1;
2591
		}
2592
		if (! in_array($suffix,array('','_public','_private')))
2593
		{
2594
			$this->error='update_note Parameter suffix must be empty, \'_private\' or \'_public\'';
2595
			dol_syslog(get_class($this)."::update_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR);
2596
			return -2;
2597
		}
2598
		// Special cas
2599
		//var_dump($this->table_element);exit;
2600
		if ($this->table_element == 'product') $suffix='';
2601
2602
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2603
		$sql.= " SET note".$suffix." = ".(!empty($note)?("'".$this->db->escape($note)."'"):"NULL");
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2604
		$sql.= " ,".(in_array($this->table_element, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))?"fk_user_mod":"fk_user_modif")." = ".$user->id;
2605
		$sql.= " WHERE rowid =". $this->id;
2606
2607
		dol_syslog(get_class($this)."::update_note", LOG_DEBUG);
2608
		if ($this->db->query($sql))
2609
		{
2610
			if ($suffix == '_public') $this->note_public = $note;
2611
			else if ($suffix == '_private') $this->note_private = $note;
2612
			else
2613
			{
2614
				$this->note = $note;      // deprecated
2615
				$this->note_private = $note;
2616
			}
2617
			return 1;
2618
		}
2619
		else
2620
		{
2621
			$this->error=$this->db->lasterror();
2622
			return -1;
2623
		}
2624
	}
2625
2626
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2627
	/**
2628
	 * 	Update public note (kept for backward compatibility)
2629
	 *
2630
	 * @param      string		$note		New value for note
2631
	 * @return     int      		   		<0 if KO, >0 if OK
2632
	 * @deprecated
2633
	 * @see update_note()
2634
	 */
2635
	function update_note_public($note)
2636
	{
2637
        // phpcs:enable
2638
		return $this->update_note($note,'_public');
2639
	}
2640
2641
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2642
	/**
2643
	 *	Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
2644
	 *  Must be called at end of methods addline or updateline.
2645
	 *
2646
	 *	@param	int		$exclspec          	>0 = Exclude special product (product_type=9)
2647
	 *  @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
2648
	 *  @param	int		$nodatabaseupdate	1=Do not update database. Update only properties of object.
2649
	 *  @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.
2650
	 *	@return	int    			           	<0 if KO, >0 if OK
2651
	 */
2652
	function update_price($exclspec=0,$roundingadjust='none',$nodatabaseupdate=0,$seller=null)
2653
	{
2654
        // phpcs:enable
2655
		global $conf, $hookmanager, $action;
2656
2657
		// Some external module want no update price after a trigger because they have another method to calculate the total (ex: with an extrafield)
2658
		$MODULE = "";
2659
		if ($this->element == 'propal')
2660
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_PROPOSAL";
2661
		elseif ($this->element == 'order')
2662
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER";
2663
		elseif ($this->element == 'facture')
2664
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE";
2665
		elseif ($this->element == 'facture_fourn')
2666
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE";
2667
		elseif ($this->element == 'order_supplier')
2668
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER";
2669
		elseif ($this->element == 'supplier_proposal')
2670
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_PROPOSAL";
2671
2672
		if (! empty($MODULE)) {
2673
			if (!empty(Globals::$conf->global->$MODULE)) {
2674
                $modsactivated = explode(',', Globals::$conf->global->$MODULE);
2675
                foreach ($modsactivated as $mod) {
2676
					if (Globals::$conf->$mod->enabled)
2677
                        return 1; // update was disabled by specific setup
2678
				}
2679
			}
2680
		}
2681
2682
		include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2683
2684
		if ($roundingadjust == '-1') $roundingadjust='auto';	// For backward compatibility
2685
2686
		$forcedroundingmode=$roundingadjust;
2687
		if ($forcedroundingmode == 'auto' && isset(Globals::$conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND))
2688
            $forcedroundingmode = Globals::$conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND;
2689
        elseif ($forcedroundingmode == 'auto') $forcedroundingmode='0';
2690
2691
		$error=0;
2692
2693
		$multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1;
2694
2695
		// Define constants to find lines to sum
2696
		$fieldtva='total_tva';
2697
		$fieldlocaltax1='total_localtax1';
2698
		$fieldlocaltax2='total_localtax2';
2699
		$fieldup='subprice';
2700
		if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier')
2701
		{
2702
			$fieldtva='tva';
2703
			$fieldup='pu_ht';
2704
		}
2705
		if ($this->element == 'expensereport')
2706
		{
2707
			$fieldup='value_unit';
2708
		}
2709
2710
		$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,';
2711
		$sql.= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type';
2712
			if ($this->table_element_line == 'facturedet') $sql.= ', situation_percent';
2713
			$sql.= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
2714
		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2715
		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2716
		if ($exclspec)
2717
		{
2718
			$product_field='product_type';
2719
			if ($this->table_element_line == 'contratdet') $product_field='';    // contratdet table has no product_type field
2720
			if ($product_field) $sql.= ' AND '.$product_field.' <> 9';
2721
		}
2722
		$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
2723
2724
		dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2725
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2726
		if ($resql)
2727
		{
2728
			$this->total_ht  = 0;
2729
			$this->total_tva = 0;
2730
			$this->total_localtax1 = 0;
2731
			$this->total_localtax2 = 0;
2732
			$this->total_ttc = 0;
2733
			$total_ht_by_vats  = array();
2734
			$total_tva_by_vats = array();
2735
			$total_ttc_by_vats = array();
2736
			$this->multicurrency_total_ht	= 0;
2737
			$this->multicurrency_total_tva	= 0;
2738
			$this->multicurrency_total_ttc	= 0;
2739
2740
			$num = $this->db->num_rows($resql);
2741
			$i = 0;
2742
			while ($i < $num)
2743
			{
2744
				$obj = $this->db->fetch_object($resql);
2745
2746
				// Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none'
2747
				$parameters=array('fk_element' => $obj->rowid);
2748
				$reshook = $hookmanager->executeHooks('changeRoundingMode', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2749
2750
				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'
2751
				{
2752
					$localtax_array=array($obj->localtax1_type,$obj->localtax1_tx,$obj->localtax2_type,$obj->localtax2_tx);
2753
					$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);
2754
					$diff=price2num($tmpcal[1] - $obj->total_tva, 'MT', 1);
2755
					if ($diff)
2756
					{
2757
						$sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".$tmpcal[1].", total_ttc = ".$tmpcal[2]." WHERE rowid = ".$obj->rowid;
2758
						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);
2759
								$resqlfix=$this->db->query($sqlfix);
2760
								if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2761
								$obj->total_tva = $tmpcal[1];
2762
								$obj->total_ttc = $tmpcal[2];
2763
						//
2764
					}
2765
				}
2766
2767
				$this->total_ht        += $obj->total_ht;		// The field visible at end of line detail
2768
				$this->total_tva       += $obj->total_tva;
2769
				$this->total_localtax1 += $obj->total_localtax1;
2770
				$this->total_localtax2 += $obj->total_localtax2;
2771
				$this->total_ttc       += $obj->total_ttc;
2772
				$this->multicurrency_total_ht        += $obj->multicurrency_total_ht;		// The field visible at end of line detail
2773
				$this->multicurrency_total_tva       += $obj->multicurrency_total_tva;
2774
				$this->multicurrency_total_ttc       += $obj->multicurrency_total_ttc;
2775
2776
				if (! isset($total_ht_by_vats[$obj->vatrate]))  $total_ht_by_vats[$obj->vatrate]=0;
2777
				if (! isset($total_tva_by_vats[$obj->vatrate])) $total_tva_by_vats[$obj->vatrate]=0;
2778
				if (! isset($total_ttc_by_vats[$obj->vatrate])) $total_ttc_by_vats[$obj->vatrate]=0;
2779
				$total_ht_by_vats[$obj->vatrate]  += $obj->total_ht;
2780
				$total_tva_by_vats[$obj->vatrate] += $obj->total_tva;
2781
				$total_ttc_by_vats[$obj->vatrate] += $obj->total_ttc;
2782
2783
				if ($forcedroundingmode == '1')	// Check if we need adjustement onto line for vat. TODO This works on the company currency but not on multicurrency
2784
				{
2785
					$tmpvat=price2num($total_ht_by_vats[$obj->vatrate] * $obj->vatrate / 100, 'MT', 1);
2786
					$diff=price2num($total_tva_by_vats[$obj->vatrate]-$tmpvat, 'MT', 1);
2787
					//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";
2788
					if ($diff)
2789
					{
2790
						if (abs($diff) > 0.1) { dol_syslog('A rounding difference was detected into TOTAL but is too high to be corrected', LOG_WARNING); exit; }
2791
						$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;
2792
						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);
2793
								$resqlfix=$this->db->query($sqlfix);
2794
								if (! $resqlfix) dol_print_error($this->db,'Failed to update line');
2795
								$this->total_tva -= $diff;
2796
								$this->total_ttc -= $diff;
2797
								$total_tva_by_vats[$obj->vatrate] -= $diff;
2798
								$total_ttc_by_vats[$obj->vatrate] -= $diff;
2799
					}
2800
				}
2801
2802
				$i++;
2803
			}
2804
2805
			// Add revenue stamp to total
2806
			$this->total_ttc       			+= isset($this->revenuestamp)?$this->revenuestamp:0;
2807
			$this->multicurrency_total_ttc  += isset($this->revenuestamp)?($this->revenuestamp * $multicurrency_tx):0;
2808
2809
			// Situations totals
2810
			if ($this->situation_cycle_ref && $this->situation_counter > 1 && method_exists($this, 'get_prev_sits') && $this->type != $this::TYPE_CREDIT_NOTE )
0 ignored issues
show
Bug Best Practice introduced by
The property situation_counter does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
Bug Best Practice introduced by
The property situation_cycle_ref does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2811
			{
2812
				$prev_sits = $this->get_prev_sits();
2813
2814
				foreach ($prev_sits as $sit) {				// $sit is an object Facture loaded with a fetch.
2815
					$this->total_ht -= $sit->total_ht;
2816
					$this->total_tva -= $sit->total_tva;
2817
					$this->total_localtax1 -= $sit->total_localtax1;
2818
					$this->total_localtax2 -= $sit->total_localtax2;
2819
					$this->total_ttc -= $sit->total_ttc;
2820
					$this->multicurrency_total_ht -= $sit->multicurrency_total_ht;
2821
					$this->multicurrency_total_tva -= $sit->multicurrency_total_tva;
2822
					$this->multicurrency_total_ttc -= $sit->multicurrency_total_ttc;
2823
				}
2824
			}
2825
2826
			$this->db->free($resql);
2827
2828
			// Now update global field total_ht, total_ttc and tva
2829
			$fieldht='total_ht';
2830
			$fieldtva='tva';
2831
			$fieldlocaltax1='localtax1';
2832
			$fieldlocaltax2='localtax2';
2833
			$fieldttc='total_ttc';
2834
			// Specific code for backward compatibility with old field names
2835
			if ($this->element == 'facture' || $this->element == 'facturerec')             $fieldht='total';
2836
			if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva='total_tva';
2837
			if ($this->element == 'propal')                                                $fieldttc='total';
2838
			if ($this->element == 'expensereport')                                         $fieldtva='total_tva';
2839
			if ($this->element == 'supplier_proposal')                                     $fieldttc='total';
2840
2841
			if (empty($nodatabaseupdate))
2842
			{
2843
				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET';
2844
				$sql .= " ".$fieldht."='".price2num($this->total_ht)."',";
2845
				$sql .= " ".$fieldtva."='".price2num($this->total_tva)."',";
2846
				$sql .= " ".$fieldlocaltax1."='".price2num($this->total_localtax1)."',";
2847
				$sql .= " ".$fieldlocaltax2."='".price2num($this->total_localtax2)."',";
2848
				$sql .= " ".$fieldttc."='".price2num($this->total_ttc)."'";
2849
						$sql .= ", multicurrency_total_ht='".price2num($this->multicurrency_total_ht, 'MT', 1)."'";
2850
						$sql .= ", multicurrency_total_tva='".price2num($this->multicurrency_total_tva, 'MT', 1)."'";
2851
						$sql .= ", multicurrency_total_ttc='".price2num($this->multicurrency_total_ttc, 'MT', 1)."'";
2852
				$sql .= ' WHERE rowid = '.$this->id;
2853
2854
2855
				dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2856
				$resql=$this->db->query($sql);
2857
				if (! $resql)
2858
				{
2859
					$error++;
2860
					$this->error=$this->db->lasterror();
2861
					$this->errors[]=$this->db->lasterror();
2862
				}
2863
			}
2864
2865
			if (! $error)
2866
			{
2867
				return 1;
2868
			}
2869
			else
2870
			{
2871
				return -1;
2872
			}
2873
		}
2874
		else
2875
		{
2876
			dol_print_error($this->db,'Bad request in update_price');
2877
			return -1;
2878
		}
2879
	}
2880
2881
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2882
	/**
2883
	 *	Add objects linked in llx_element_element.
2884
	 *
2885
	 *	@param		string	$origin		Linked element type
2886
	 *	@param		int		$origin_id	Linked element id
2887
	 *	@return		int					<=0 if KO, >0 if OK
2888
	 *	@see		fetchObjectLinked, updateObjectLinked, deleteObjectLinked
2889
	 */
2890
	function add_object_linked($origin=null, $origin_id=null)
2891
	{
2892
        // phpcs:enable
2893
		$origin = (! empty($origin) ? $origin : $this->origin);
2894
		$origin_id = (! empty($origin_id) ? $origin_id : $this->origin_id);
2895
2896
		// Special case
2897
		if ($origin == 'order') $origin='commande';
2898
		if ($origin == 'invoice') $origin='facture';
2899
		if ($origin == 'invoice_template') $origin='facturerec';
2900
    	if ($origin == 'supplierorder') $origin='order_supplier';
2901
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
2902
2903
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."element_element (";
2904
		$sql.= "fk_source";
2905
		$sql.= ", sourcetype";
2906
		$sql.= ", fk_target";
2907
		$sql.= ", targettype";
2908
		$sql.= ") VALUES (";
2909
		$sql.= $origin_id;
2910
		$sql.= ", '".$this->db->escape($origin)."'";
2911
		$sql.= ", ".$this->id;
2912
		$sql.= ", '".$this->db->escape($this->element)."'";
2913
		$sql.= ")";
2914
2915
		dol_syslog(get_class($this)."::add_object_linked", LOG_DEBUG);
2916
		if ($this->db->query($sql))
2917
	  	{
2918
	  		$this->db->commit();
2919
	  		return 1;
2920
	  	}
2921
	  	else
2922
	  	{
2923
	  		$this->error=$this->db->lasterror();
2924
	  		$this->db->rollback();
2925
	  		return 0;
2926
	  	}
2927
	}
2928
2929
	/**
2930
	 *	Fetch array of objects linked to current object (object of enabled modules only). Links are loaded into
2931
	 *		this->linkedObjectsIds array and
2932
	 *		this->linkedObjects array if $loadalsoobjects = 1
2933
	 *  Possible usage for parameters:
2934
	 *  - all parameters empty -> we look all link to current object (current object can be source or target)
2935
	 *  - source id+type -> will get target list linked to source
2936
	 *  - target id+type -> will get source list linked to target
2937
	 *  - source id+type + target type -> will get target list of the type
2938
	 *  - target id+type + target source -> will get source list of the type
2939
	 *
2940
	 *	@param	int		$sourceid			Object source id (if not defined, id of object)
2941
	 *	@param  string	$sourcetype			Object source type (if not defined, element name of object)
2942
	 *	@param  int		$targetid			Object target id (if not defined, id of object)
2943
	 *	@param  string	$targettype			Object target type (if not defined, elemennt name of object)
2944
	 *	@param  string	$clause				'OR' or 'AND' clause used when both source id and target id are provided
2945
	 *  @param  int		$alsosametype		0=Return only links to object that differs from source type. 1=Include also link to objects of same type.
2946
	 *  @param  string	$orderby			SQL 'ORDER BY' clause
2947
	 *  @param	int		$loadalsoobjects	Load also array this->linkedObjects (Use 0 to increase performances)
2948
	 *	@return int							<0 if KO, >0 if OK
2949
	 *  @see	add_object_linked, updateObjectLinked, deleteObjectLinked
2950
	 */
2951
	function fetchObjectLinked($sourceid=null,$sourcetype='',$targetid=null,$targettype='',$clause='OR',$alsosametype=1,$orderby='sourcetype',$loadalsoobjects=1)
2952
	{
2953
		global $conf;
2954
2955
		$this->linkedObjectsIds=array();
2956
		$this->linkedObjects=array();
2957
2958
		$justsource=false;
2959
		$justtarget=false;
2960
		$withtargettype=false;
2961
		$withsourcetype=false;
2962
2963
		if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid))
2964
		{
2965
			$justsource=true;  // the source (id and type) is a search criteria
2966
			if (! empty($targettype)) $withtargettype=true;
2967
		}
2968
		if (! empty($targetid) && ! empty($targettype) && empty($sourceid))
2969
		{
2970
			$justtarget=true;  // the target (id and type) is a search criteria
2971
			if (! empty($sourcetype)) $withsourcetype=true;
2972
		}
2973
2974
		$sourceid = (! empty($sourceid) ? $sourceid : $this->id);
2975
		$targetid = (! empty($targetid) ? $targetid : $this->id);
2976
		$sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
2977
		$targettype = (! empty($targettype) ? $targettype : $this->element);
2978
2979
		/*if (empty($sourceid) && empty($targetid))
2980
		 {
2981
		 dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR);
2982
		 return -1;
2983
		 }*/
2984
2985
		// Links between objects are stored in table element_element
2986
		$sql = 'SELECT rowid, fk_source, sourcetype, fk_target, targettype';
2987
		$sql.= ' FROM '.MAIN_DB_PREFIX.'element_element';
2988
		$sql.= " WHERE ";
2989
		if ($justsource || $justtarget)
2990
		{
2991
			if ($justsource)
2992
			{
2993
				$sql.= "fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."'";
2994
				if ($withtargettype) $sql.= " AND targettype = '".$targettype."'";
2995
			}
2996
			else if ($justtarget)
2997
			{
2998
				$sql.= "fk_target = ".$targetid." AND targettype = '".$targettype."'";
2999
				if ($withsourcetype) $sql.= " AND sourcetype = '".$sourcetype."'";
3000
			}
3001
		}
3002
		else
3003
		{
3004
			$sql.= "(fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."')";
3005
			$sql.= " ".$clause." (fk_target = ".$targetid." AND targettype = '".$targettype."')";
3006
		}
3007
		$sql .= ' ORDER BY '.$orderby;
3008
3009
		dol_syslog(get_class($this)."::fetchObjectLink", LOG_DEBUG);
3010
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3011
		if ($resql)
3012
		{
3013
			$num = $this->db->num_rows($resql);
3014
			$i = 0;
3015
			while ($i < $num)
3016
			{
3017
				$obj = $this->db->fetch_object($resql);
3018
				if ($justsource || $justtarget)
3019
				{
3020
					if ($justsource)
3021
					{
3022
						$this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
3023
					}
3024
					else if ($justtarget)
3025
					{
3026
						$this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
3027
					}
3028
				}
3029
				else
3030
				{
3031
					if ($obj->fk_source == $sourceid && $obj->sourcetype == $sourcetype)
3032
					{
3033
						$this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target;
3034
					}
3035
					if ($obj->fk_target == $targetid && $obj->targettype == $targettype)
3036
					{
3037
						$this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source;
3038
					}
3039
				}
3040
				$i++;
3041
			}
3042
3043
			if (! empty($this->linkedObjectsIds))
3044
			{
3045
				$tmparray = $this->linkedObjectsIds;
3046
				foreach($tmparray as $objecttype => $objectids)       // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...)
3047
				{
3048
					// Parse element/subelement (ex: project_task, cabinetmed_consultation, ...)
3049
					$module = $element = $subelement = $objecttype;
3050
					if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier'
3051
						&& preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
3052
					{
3053
						$module = $element = $regs[1];
3054
						$subelement = $regs[2];
3055
					}
3056
3057
					$classpath = $element.'/class';
3058
					// To work with non standard classpath or module name
3059
					if ($objecttype == 'facture')			{
3060
						$classpath = 'compta/facture/class';
3061
					}
3062
					else if ($objecttype == 'facturerec')			{
3063
						$classpath = 'compta/facture/class'; $module = 'facture';
3064
					}
3065
					else if ($objecttype == 'propal')			{
3066
						$classpath = 'comm/propal/class';
3067
					}
3068
					else if ($objecttype == 'supplier_proposal')			{
3069
						$classpath = 'supplier_proposal/class';
3070
					}
3071
					else if ($objecttype == 'shipping')			{
3072
						$classpath = 'expedition/class'; $subelement = 'expedition'; $module = 'expedition_bon';
3073
					}
3074
					else if ($objecttype == 'delivery')			{
3075
						$classpath = 'livraison/class'; $subelement = 'livraison'; $module = 'livraison_bon';
3076
					}
3077
					else if ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier')	{
3078
						$classpath = 'fourn/class'; $module = 'fournisseur';
3079
					}
3080
					else if ($objecttype == 'fichinter')			{
3081
						$classpath = 'fichinter/class'; $subelement = 'fichinter'; $module = 'ficheinter';
3082
					}
3083
					else if ($objecttype == 'subscription')			{
3084
						$classpath = 'adherents/class'; $module = 'adherent';
3085
					}
3086
3087
					// Set classfile
3088
					$classfile = strtolower($subelement); $classname = ucfirst($subelement);
3089
3090
					if ($objecttype == 'order') {
3091
						$classfile = 'commande'; $classname = 'Commande';
3092
					}
3093
					else if ($objecttype == 'invoice_supplier') {
3094
						$classfile = 'fournisseur.facture'; $classname = 'FactureFournisseur';
3095
					}
3096
					else if ($objecttype == 'order_supplier')   {
3097
						$classfile = 'fournisseur.commande'; $classname = 'CommandeFournisseur';
3098
					}
3099
					else if ($objecttype == 'supplier_proposal')   {
3100
						$classfile = 'supplier_proposal'; $classname = 'SupplierProposal';
3101
					}
3102
					else if ($objecttype == 'facturerec')   {
3103
						$classfile = 'facture-rec'; $classname = 'FactureRec';
3104
					}
3105
					else if ($objecttype == 'subscription')   {
3106
						$classfile = 'subscription'; $classname = 'Subscription';
3107
					}
3108
3109
					// Here $module, $classfile and $classname are set
3110
					if (Globals::$conf->$module->enabled && (($element != $this->element) || $alsosametype)) {
3111
						if ($loadalsoobjects)
3112
						{
3113
							dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
3114
							//print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname);
3115
							if (class_exists($classname))
3116
							{
3117
								foreach($objectids as $i => $objectid)	// $i is rowid into llx_element_element
3118
								{
3119
									$object = new $classname($this->db);
3120
									$ret = $object->fetch($objectid);
3121
									if ($ret >= 0)
3122
									{
3123
										$this->linkedObjects[$objecttype][$i] = $object;
3124
									}
3125
								}
3126
							}
3127
						}
3128
					}
3129
					else
3130
					{
3131
						unset($this->linkedObjectsIds[$objecttype]);
3132
					}
3133
				}
3134
			}
3135
			return 1;
3136
		}
3137
		else
3138
		{
3139
			dol_print_error($this->db);
3140
			return -1;
3141
		}
3142
	}
3143
3144
	/**
3145
	 *	Update object linked of a current object
3146
	 *
3147
	 *	@param	int		$sourceid		Object source id
3148
	 *	@param  string	$sourcetype		Object source type
3149
	 *	@param  int		$targetid		Object target id
3150
	 *	@param  string	$targettype		Object target type
3151
	 *	@return							int	>0 if OK, <0 if KO
3152
	 *	@see	add_object_linked, fetObjectLinked, deleteObjectLinked
3153
	 */
3154
	function updateObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='')
3155
	{
3156
		$updatesource=false;
3157
		$updatetarget=false;
3158
3159
		if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $updatesource=true;
3160
		else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $updatetarget=true;
3161
3162
		$sql = "UPDATE ".MAIN_DB_PREFIX."element_element SET ";
3163
		if ($updatesource)
3164
		{
3165
			$sql.= "fk_source = ".$sourceid;
3166
			$sql.= ", sourcetype = '".$this->db->escape($sourcetype)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3167
			$sql.= " WHERE fk_target = ".$this->id;
3168
			$sql.= " AND targettype = '".$this->db->escape($this->element)."'";
3169
		}
3170
		else if ($updatetarget)
3171
		{
3172
			$sql.= "fk_target = ".$targetid;
3173
			$sql.= ", targettype = '".$this->db->escape($targettype)."'";
3174
			$sql.= " WHERE fk_source = ".$this->id;
3175
			$sql.= " AND sourcetype = '".$this->db->escape($this->element)."'";
3176
		}
3177
3178
		dol_syslog(get_class($this)."::updateObjectLinked", LOG_DEBUG);
3179
		if ($this->db->query($sql))
3180
		{
3181
			return 1;
3182
		}
3183
		else
3184
		{
3185
			$this->error=$this->db->lasterror();
3186
			return -1;
3187
		}
3188
	}
3189
3190
	/**
3191
	 *	Delete all links between an object $this
3192
	 *
3193
	 *	@param	int		$sourceid		Object source id
3194
	 *	@param  string	$sourcetype		Object source type
3195
	 *	@param  int		$targetid		Object target id
3196
	 *	@param  string	$targettype		Object target type
3197
	 *  @param	int		$rowid			Row id of line to delete. If defined, other parameters are not used.
3198
	 *	@return     					int	>0 if OK, <0 if KO
3199
	 *	@see	add_object_linked, updateObjectLinked, fetchObjectLinked
3200
	 */
3201
	function deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
3202
	{
3203
		$deletesource=false;
3204
		$deletetarget=false;
3205
3206
		if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $deletesource=true;
3207
		else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $deletetarget=true;
3208
3209
		$sourceid = (! empty($sourceid) ? $sourceid : $this->id);
3210
		$sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element);
3211
		$targetid = (! empty($targetid) ? $targetid : $this->id);
3212
		$targettype = (! empty($targettype) ? $targettype : $this->element);
3213
3214
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_element";
3215
		$sql.= " WHERE";
3216
		if ($rowid > 0)
3217
		{
3218
			$sql.=" rowid = ".$rowid;
3219
		}
3220
		else
3221
		{
3222
			if ($deletesource)
3223
			{
3224
				$sql.= " fk_source = ".$sourceid." AND sourcetype = '".$this->db->escape($sourcetype)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3225
				$sql.= " AND fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."'";
3226
			}
3227
			else if ($deletetarget)
3228
			{
3229
				$sql.= " fk_target = ".$targetid." AND targettype = '".$this->db->escape($targettype)."'";
3230
				$sql.= " AND fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."'";
3231
			}
3232
			else
3233
			{
3234
				$sql.= " (fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."')";
3235
				$sql.= " OR";
3236
				$sql.= " (fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."')";
3237
			}
3238
		}
3239
3240
		dol_syslog(get_class($this)."::deleteObjectLinked", LOG_DEBUG);
3241
		if ($this->db->query($sql))
3242
		{
3243
			return 1;
3244
		}
3245
		else
3246
		{
3247
			$this->error=$this->db->lasterror();
3248
			$this->errors[]=$this->error;
3249
			return -1;
3250
		}
3251
	}
3252
3253
	/**
3254
	 *      Set status of an object
3255
	 *
3256
	 *      @param	int		$status			Status to set
3257
	 *      @param	int		$elementId		Id of element to force (use this->id by default)
3258
	 *      @param	string	$elementType	Type of element to force (use this->table_element by default)
3259
	 *      @param	string	$trigkey		Trigger key to use for trigger
3260
	 *      @return int						<0 if KO, >0 if OK
3261
	 */
3262
	function setStatut($status, $elementId=null, $elementType='', $trigkey='')
3263
	{
3264
		global $user,$langs,$conf;
3265
3266
		$savElementId=$elementId;  // To be used later to know if we were using the method using the id of this or not.
3267
3268
		$elementId = (!empty($elementId)?$elementId:$this->id);
3269
		$elementTable = (!empty($elementType)?$elementType:$this->table_element);
3270
3271
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3272
3273
		$fieldstatus="fk_statut";
3274
		if ($elementTable == 'facture_rec') $fieldstatus="suspended";
3275
		if ($elementTable == 'mailing') $fieldstatus="statut";
3276
		if ($elementTable == 'cronjob') $fieldstatus="status";
3277
		if ($elementTable == 'user') $fieldstatus="statut";
3278
		if ($elementTable == 'expensereport') $fieldstatus="fk_statut";
3279
		if ($elementTable == 'commande_fournisseur_dispatch') $fieldstatus="status";
3280
3281
		$sql = "UPDATE ".MAIN_DB_PREFIX.$elementTable;
3282
		$sql.= " SET ".$fieldstatus." = ".$status;
3283
		// If status = 1 = validated, update also fk_user_valid
3284
		if ($status == 1 && $elementTable == 'expensereport') $sql.=", fk_user_valid = ".$user->id;
3285
		$sql.= " WHERE rowid=".$elementId;
3286
3287
		dol_syslog(get_class($this)."::setStatut", LOG_DEBUG);
3288
		if ($this->db->query($sql))
3289
		{
3290
			$error = 0;
3291
3292
			// Try autoset of trigkey
3293
			if (empty($trigkey))
3294
			{
3295
				if ($this->element == 'supplier_proposal' && $status == 2) $trigkey='SUPPLIER_PROPOSAL_SIGN';   // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class
3296
				if ($this->element == 'supplier_proposal' && $status == 3) $trigkey='SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class
3297
				if ($this->element == 'supplier_proposal' && $status == 4) $trigkey='SUPPLIER_PROPOSAL_CLOSE';  // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class
3298
				if ($this->element == 'fichinter' && $status == 3) $trigkey='FICHINTER_CLASSIFY_DONE';
3299
				if ($this->element == 'fichinter' && $status == 2) $trigkey='FICHINTER_CLASSIFY_BILLED';
3300
				if ($this->element == 'fichinter' && $status == 1) $trigkey='FICHINTER_CLASSIFY_UNBILLED';
3301
			}
3302
3303
			if ($trigkey)
3304
			{
3305
				// Appel des triggers
3306
				include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
3307
				$interface=new Interfaces($this->db);
0 ignored issues
show
The type Alixar\Base\Interfaces was not found. Did you mean Interfaces? If so, make sure to prefix the type with \.
Loading history...
3308
				$result=$interface->run_triggers($trigkey,$this,$user,$langs,$conf);
3309
				if ($result < 0) {
3310
					$error++; $this->errors=$interface->errors;
3311
				}
3312
				// Fin appel triggers
3313
			}
3314
3315
			if (! $error)
3316
			{
3317
				$this->db->commit();
3318
3319
				if (empty($savElementId))    // If the element we update was $this (so $elementId is null)
3320
				{
3321
					$this->statut = $status;
3322
					$this->status = $status;
3323
				}
3324
3325
				return 1;
3326
			}
3327
			else
3328
			{
3329
				$this->db->rollback();
3330
				dol_syslog(get_class($this)."::setStatus ".$this->error,LOG_ERR);
3331
				return -1;
3332
			}
3333
		}
3334
		else
3335
		{
3336
			$this->error=$this->db->lasterror();
3337
			$this->db->rollback();
3338
			return -1;
3339
		}
3340
	}
3341
3342
3343
	/**
3344
	 *  Load type of canvas of an object if it exists
3345
	 *
3346
	 *  @param      int		$id     Record id
3347
	 *  @param      string	$ref    Record ref
3348
	 *  @return		int				<0 if KO, 0 if nothing done, >0 if OK
3349
	 */
3350
	function getCanvas($id=0,$ref='')
3351
	{
3352
		global $conf;
3353
3354
		if (empty($id) && empty($ref)) return 0;
3355
		if (!empty(Globals::$conf->global->MAIN_DISABLE_CANVAS))
3356
            return 0;    // To increase speed. Not enabled by default.
3357
3358
            // Clean parameters
3359
		$ref = trim($ref);
3360
3361
		$sql = "SELECT rowid, canvas";
3362
		$sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element;
3363
		$sql.= " WHERE entity IN (".getEntity($this->element).")";
3364
		if (! empty($id))  $sql.= " AND rowid = ".$id;
3365
		if (! empty($ref)) $sql.= " AND ref = '".$this->db->escape($ref)."'";
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3366
3367
		$resql = $this->db->query($sql);
3368
		if ($resql)
3369
		{
3370
			$obj = $this->db->fetch_object($resql);
3371
			if ($obj)
3372
			{
3373
				$this->canvas   = $obj->canvas;
3374
				return 1;
3375
			}
3376
			else return 0;
3377
		}
3378
		else
3379
		{
3380
			dol_print_error($this->db);
3381
			return -1;
3382
		}
3383
	}
3384
3385
3386
	/**
3387
	 * 	Get special code of a line
3388
	 *
3389
	 * 	@param	int		$lineid		Id of line
3390
	 * 	@return	int					Special code
3391
	 */
3392
	function getSpecialCode($lineid)
3393
	{
3394
		$sql = 'SELECT special_code FROM '.MAIN_DB_PREFIX.$this->table_element_line;
3395
		$sql.= ' WHERE rowid = '.$lineid;
3396
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3397
		if ($resql)
3398
		{
3399
			$row = $this->db->fetch_row($resql);
3400
			return $row[0];
3401
		}
3402
	}
3403
3404
	/**
3405
	 *  Function to check if an object is used by others.
3406
	 *  Check is done into this->childtables. There is no check into llx_element_element.
3407
	 *
3408
	 *  @param	int		$id			Force id of object
3409
	 *  @return	int					<0 if KO, 0 if not used, >0 if already used
3410
	 */
3411
	function isObjectUsed($id=0)
3412
	{
3413
		global $langs;
3414
3415
		if (empty($id)) $id=$this->id;
3416
3417
		// Check parameters
3418
		if (! isset($this->childtables) || ! is_array($this->childtables) || count($this->childtables) == 0)
3419
		{
3420
			dol_print_error('Called isObjectUsed on a class with property this->childtables not defined');
3421
			return -1;
3422
		}
3423
3424
		$arraytoscan = $this->childtables;
3425
		// For backward compatibility, we check if array is old format array('table1', 'table2', ...)
3426
		$tmparray=array_keys($this->childtables);
3427
		if (is_numeric($tmparray[0]))
3428
		{
3429
			$arraytoscan = array_flip($this->childtables);
3430
		}
3431
3432
		// Test if child exists
3433
		$haschild=0;
3434
		foreach($arraytoscan as $table => $elementname)
3435
		{
3436
			//print $id.'-'.$table.'-'.$elementname.'<br>';
3437
			// Check if third party can be deleted
3438
			$sql = "SELECT COUNT(*) as nb from ".MAIN_DB_PREFIX.$table;
3439
			$sql.= " WHERE ".$this->fk_element." = ".$id;
3440
			$resql=$this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3441
			if ($resql)
3442
			{
3443
				$obj=$this->db->fetch_object($resql);
3444
				if ($obj->nb > 0)
3445
				{
3446
					$langs->load("errors");
3447
					//print 'Found into table '.$table.', type '.$langs->transnoentitiesnoconv($elementname).', haschild='.$haschild;
3448
					$haschild += $obj->nb;
3449
					if (is_numeric($elementname))	// old usage
3450
					{
3451
						$this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $table);
3452
					}
3453
					else	// new usage: $elementname=Translation key
3454
					{
3455
						$this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $langs->transnoentitiesnoconv($elementname));
3456
					}
3457
					break;    // We found at least one, we stop here
3458
				}
3459
			}
3460
			else
3461
			{
3462
				$this->errors[]=$this->db->lasterror();
3463
				return -1;
3464
			}
3465
		}
3466
		if ($haschild > 0)
3467
		{
3468
			$this->errors[]="ErrorRecordHasChildren";
3469
			return $haschild;
3470
		}
3471
		else return 0;
3472
	}
3473
3474
	/**
3475
	 *  Function to say how many lines object contains
3476
	 *
3477
	 *	@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
3478
	 *  @return	int						<0 if KO, 0 if no predefined products, nb of lines with predefined products if found
3479
	 */
3480
	function hasProductsOrServices($predefined=-1)
3481
	{
3482
		$nb=0;
3483
3484
		foreach($this->lines as $key => $val)
3485
		{
3486
			$qualified=0;
3487
			if ($predefined == -1) $qualified=1;
3488
			if ($predefined == 1 && $val->fk_product > 0) $qualified=1;
3489
			if ($predefined == 0 && $val->fk_product <= 0) $qualified=1;
3490
			if ($predefined == 2 && $val->fk_product > 0 && $val->product_type==0) $qualified=1;
3491
			if ($predefined == 3 && $val->fk_product > 0 && $val->product_type==1) $qualified=1;
3492
			if ($qualified) $nb++;
3493
		}
3494
		dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies');
3495
		return $nb;
3496
	}
3497
3498
	/**
3499
	 * Function that returns the total amount HT of discounts applied for all lines.
3500
	 *
3501
	 * @return 	float
3502
	 */
3503
	function getTotalDiscount()
3504
	{
3505
		$total_discount=0.00;
3506
3507
		$sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht";
3508
		$sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element."det";
3509
		$sql.= " WHERE ".$this->fk_element." = ".$this->id;
3510
3511
		dol_syslog(get_class($this).'::getTotalDiscount', LOG_DEBUG);
3512
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3513
		if ($resql)
3514
		{
3515
			$num=$this->db->num_rows($resql);
3516
			$i=0;
3517
			while ($i < $num)
3518
			{
3519
				$obj = $this->db->fetch_object($resql);
3520
3521
				$pu_ht = $obj->pu_ht;
3522
				$qty= $obj->qty;
3523
				$total_ht = $obj->total_ht;
3524
3525
				$total_discount_line = floatval(price2num(($pu_ht * $qty) - $total_ht, 'MT'));
3526
				$total_discount += $total_discount_line;
3527
3528
				$i++;
3529
			}
3530
		}
3531
3532
		//print $total_discount; exit;
3533
		return price2num($total_discount);
3534
	}
3535
3536
3537
	/**
3538
	 * Return into unit=0, the calculated total of weight and volume of all lines * qty
3539
	 * Calculate by adding weight and volume of each product line, so properties ->volume/volume_units/weight/weight_units must be loaded on line.
3540
	 *
3541
	 * @return  array                           array('weight'=>...,'volume'=>...)
3542
	 */
3543
	function getTotalWeightVolume()
3544
	{
3545
		$totalWeight = 0;
3546
		$totalVolume = 0;
3547
		// defined for shipment only
3548
		$totalOrdered = '';
3549
		// defined for shipment only
3550
		$totalToShip = '';
3551
3552
		foreach ($this->lines as $line)
3553
		{
3554
			if (isset($line->qty_asked))
3555
			{
3556
				if (empty($totalOrdered)) $totalOrdered=0;  // Avoid warning because $totalOrdered is ''
3557
				$totalOrdered+=$line->qty_asked;    // defined for shipment only
3558
			}
3559
			if (isset($line->qty_shipped))
3560
			{
3561
				if (empty($totalToShip)) $totalToShip=0;    // Avoid warning because $totalToShip is ''
3562
				$totalToShip+=$line->qty_shipped;   // defined for shipment only
3563
            }else if ($line->element == 'commandefournisseurdispatch' && isset($line->qty))
3564
            {
3565
                if (empty($totalToShip)) $totalToShip=0;
3566
                $totalToShip+=$line->qty;   // defined for reception only
3567
			}
3568
3569
			// Define qty, weight, volume, weight_units, volume_units
3570
			if ($this->element == 'shipping') {
3571
				// for shipments
3572
				$qty = $line->qty_shipped ? $line->qty_shipped : 0;
3573
			}
3574
			else {
3575
				$qty = $line->qty ? $line->qty : 0;
3576
			}
3577
3578
			$weight = $line->weight ? $line->weight : 0;
3579
            ($weight==0 && !empty($line->product->weight))? $weight=$line->product->weight: 0;
3580
			$volume = $line->volume ? $line->volume : 0;
3581
			($volume==0 && !empty($line->product->volume))? $volume=$line->product->volume: 0;
3582
3583
			$weight_units=$line->weight_units;
3584
			($weight_units==0 && !empty($line->product->weight_units))? $weight_units=$line->product->weight_units: 0;
3585
			$volume_units=$line->volume_units;
3586
			($volume_units==0 && !empty($line->product->volume_units))? $volume_units=$line->product->volume_units: 0;
3587
3588
			$weightUnit=0;
3589
			$volumeUnit=0;
3590
			if (! empty($weight_units)) $weightUnit = $weight_units;
3591
			if (! empty($volume_units)) $volumeUnit = $volume_units;
3592
3593
			if (empty($totalWeight)) $totalWeight=0;  // Avoid warning because $totalWeight is ''
3594
			if (empty($totalVolume)) $totalVolume=0;  // Avoid warning because $totalVolume is ''
3595
3596
			//var_dump($line->volume_units);
3597
			if ($weight_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3598
			{
3599
				$trueWeightUnit=pow(10, $weightUnit);
3600
				$totalWeight += $weight * $qty * $trueWeightUnit;
3601
			}
3602
			else {
3603
		if ($weight_units == 99) {
3604
			// conversion 1 Pound = 0.45359237 KG
3605
			$trueWeightUnit = 0.45359237;
3606
			$totalWeight += $weight * $qty * $trueWeightUnit;
3607
		} elseif ($weight_units == 98) {
3608
			// conversion 1 Ounce = 0.0283495 KG
3609
			$trueWeightUnit = 0.0283495;
3610
			$totalWeight += $weight * $qty * $trueWeightUnit;
3611
		}
3612
		else
3613
					$totalWeight += $weight * $qty;   // This may be wrong if we mix different units
3614
			}
3615
			if ($volume_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3616
			{
3617
				//print $line->volume."x".$line->volume_units."x".($line->volume_units < 50)."x".$volumeUnit;
3618
				$trueVolumeUnit=pow(10, $volumeUnit);
3619
				//print $line->volume;
3620
				$totalVolume += $volume * $qty * $trueVolumeUnit;
3621
			}
3622
			else
3623
			{
3624
				$totalVolume += $volume * $qty;   // This may be wrong if we mix different units
3625
			}
3626
		}
3627
3628
		return array('weight'=>$totalWeight, 'volume'=>$totalVolume, 'ordered'=>$totalOrdered, 'toship'=>$totalToShip);
3629
	}
3630
3631
3632
	/**
3633
	 *	Set extra parameters
3634
	 *
3635
	 *	@return	int      <0 if KO, >0 if OK
3636
	 */
3637
	function setExtraParameters()
3638
	{
3639
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3640
3641
		$extraparams = (! empty($this->extraparams) ? json_encode($this->extraparams) : null);
0 ignored issues
show
Bug Best Practice introduced by
The property extraparams does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3642
3643
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3644
		$sql.= " SET extraparams = ".(! empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null");
3645
		$sql.= " WHERE rowid = ".$this->id;
3646
3647
		dol_syslog(get_class($this)."::setExtraParameters", LOG_DEBUG);
3648
		$resql = $this->db->query($sql);
3649
		if (! $resql)
3650
		{
3651
			$this->error=$this->db->lasterror();
3652
			$this->db->rollback();
3653
			return -1;
3654
		}
3655
		else
3656
		{
3657
			$this->db->commit();
3658
			return 1;
3659
		}
3660
	}
3661
3662
3663
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3664
	/**
3665
	 *    Return incoterms informations
3666
	 *    TODO Use a cache for label get
3667
	 *
3668
	 *    @return	string	incoterms info
3669
	 */
3670
	function display_incoterms()
3671
	{
3672
        // phpcs:enable
3673
		$out = '';
3674
		$this->libelle_incoterms = '';
3675
		if (!empty($this->fk_incoterms))
3676
		{
3677
			$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3678
			$result = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3679
			if ($result)
3680
			{
3681
				$res = $this->db->fetch_object($result);
3682
				$out .= $res->code;
3683
			}
3684
		}
3685
3686
		$out .= (($res->code && $this->location_incoterms)?' - ':'').$this->location_incoterms;
3687
3688
		return $out;
3689
	}
3690
3691
	/**
3692
	 *    Return incoterms informations for pdf display
3693
	 *
3694
	 *    @return	string		incoterms info
3695
	 */
3696
	function getIncotermsForPDF()
3697
	{
3698
		$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3699
		$resql = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3700
		if ($resql)
3701
		{
3702
			$num = $this->db->num_rows($resql);
3703
			if ($num > 0)
3704
			{
3705
				$res = $this->db->fetch_object($resql);
3706
				return 'Incoterm : '.$res->code.' - '.$this->location_incoterms;
3707
			}
3708
			else
3709
			{
3710
				return '';
3711
			}
3712
		}
3713
		else
3714
		{
3715
			$this->errors[] = $this->db->lasterror();
3716
			return false;
3717
		}
3718
	}
3719
3720
	/**
3721
	 *    Define incoterms values of current object
3722
	 *
3723
	 *    @param	int		$id_incoterm     Id of incoterm to set or '' to remove
3724
	 * 	  @param 	string  $location		 location of incoterm
3725
	 *    @return	int     		<0 if KO, >0 if OK
3726
	 */
3727
	function setIncoterms($id_incoterm, $location)
3728
	{
3729
		if ($this->id && $this->table_element)
3730
		{
3731
			$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
3732
			$sql.= " SET fk_incoterms = ".($id_incoterm > 0 ? $id_incoterm : "null");
3733
			$sql.= ", location_incoterms = ".($id_incoterm > 0 ? "'".$this->db->escape($location)."'" : "null");
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3734
			$sql.= " WHERE rowid = " . $this->id;
3735
			dol_syslog(get_class($this).'::setIncoterms', LOG_DEBUG);
3736
			$resql=$this->db->query($sql);
3737
			if ($resql)
3738
			{
3739
				$this->fk_incoterms = $id_incoterm;
3740
				$this->location_incoterms = $location;
3741
3742
				$sql = 'SELECT libelle FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms;
3743
				$res = $this->db->query($sql);
3744
				if ($res)
3745
				{
3746
					$obj = $this->db->fetch_object($res);
3747
					$this->libelle_incoterms = $obj->libelle;
3748
				}
3749
				return 1;
3750
			}
3751
			else
3752
			{
3753
				$this->errors[] = $this->db->lasterror();
3754
				return -1;
3755
			}
3756
		}
3757
		else return -1;
3758
	}
3759
3760
3761
	// --------------------
3762
	// TODO: All functions here must be redesigned and moved as they are not business functions but output functions
3763
	// --------------------
3764
3765
	/* This is to show add lines */
3766
3767
	/**
3768
	 *	Show add free and predefined products/services form
3769
	 *
3770
	 *  @param	int		        $dateSelector       1=Show also date range input fields
3771
	 *  @param	Societe			$seller				Object thirdparty who sell
3772
	 *  @param	Societe			$buyer				Object thirdparty who buy
3773
	 *	@return	void
3774
	 */
3775
	function formAddObjectLine($dateSelector, $seller, $buyer)
3776
	{
3777
		global $conf,$user,$langs,$object,$hookmanager;
3778
		global $form,$bcnd,$var;
3779
3780
		// Line extrafield
3781
		require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3782
		$extrafieldsline = new AlExtraFields($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3783
        $extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3784
3785
		// Output template part (modules that overwrite templates must declare this into descriptor)
3786
		// Use global variables + $dateSelector + $seller and $buyer
3787
		$dirtpls = array_merge(Globals::$conf->modules_parts['tpl'], array('/core/tpl'));
3788
        foreach($dirtpls as $reldir)
3789
		{
3790
			$tpl = dol_buildpath($reldir.'/objectline_create.tpl.php');
3791
			if (empty(Globals::$conf->file->strict_mode)) {
3792
                $res=@include $tpl;
3793
			} else {
3794
				$res=include $tpl; // for debug
3795
			}
3796
			if ($res) break;
3797
		}
3798
	}
3799
3800
3801
3802
	/* This is to show array of line of details */
3803
3804
3805
	/**
3806
	 *	Return HTML table for object lines
3807
	 *	TODO Move this into an output class file (htmlline.class.php)
3808
	 *	If lines are into a template, title must also be into a template
3809
	 *	But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
3810
	 *
3811
	 *	@param	string		$action				Action code
3812
	 *	@param  string		$seller            	Object of seller third party
3813
	 *	@param  string  	$buyer             	Object of buyer third party
3814
	 *	@param	int			$selected		   	Object line selected
3815
	 *	@param  int	    	$dateSelector      	1=Show also date range input fields
3816
	 *	@return	void
3817
	 */
3818
	function printObjectLines($action, $seller, $buyer, $selected=0, $dateSelector=0)
3819
	{
3820
		global $conf, $hookmanager, $langs, $user;
3821
		// TODO We should not use global var for this !
3822
		global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax;
3823
3824
		// Define usemargins
3825
		$usemargins=0;
3826
		if (!empty(Globals::$conf->margin->enabled) && !empty($this->element) && in_array($this->element, array('facture', 'propal', 'commande')))
3827
            $usemargins = 1;
3828
3829
        $num = count($this->lines);
3830
3831
		// Line extrafield
3832
		require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
3833
		$extrafieldsline = new AlExtraFields($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3834
        $extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3835
3836
		$parameters = array('num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3837
		$reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3838
		if (empty($reshook))
3839
		{
3840
			// Title line
3841
		    print "<thead>\n";
3842
3843
			print '<tr class="liste_titre nodrag nodrop">';
3844
3845
			// Adds a line numbering column
3846
			if (!empty(Globals::$conf->global->MAIN_VIEW_LINE_NUMBER))
3847
                print '<td class="linecolnum" align="center" width="5">&nbsp;</td>';
3848
3849
            // Description
3850
			print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
3851
3852
			if ($this->element == 'supplier_proposal' || $this->element == 'order_supplier' || $this->element == 'invoice_supplier')
3853
			{
3854
				print '<td class="linerefsupplier"><span id="title_fourn_ref">'.$langs->trans("SupplierRef").'</span></td>';
3855
			}
3856
3857
			// VAT
3858
			print '<td class="linecolvat" align="right" width="80">'.$langs->trans('VAT').'</td>';
3859
3860
			// Price HT
3861
			print '<td class="linecoluht" align="right" width="80">'.$langs->trans('PriceUHT').'</td>';
3862
3863
			// Multicurrency
3864
			if (!empty(Globals::$conf->multicurrency->enabled) && $this->multicurrency_code != Globals::$conf->currency)
3865
                print '<td class="linecoluht_currency" align="right" width="80">' . $langs->trans('PriceUHTCurrency', $this->multicurrency_code) . '</td>';
3866
3867
            if ($inputalsopricewithtax) print '<td align="right" width="80">'.$langs->trans('PriceUTTC').'</td>';
3868
3869
			// Qty
3870
			print '<td class="linecolqty" align="right">'.$langs->trans('Qty').'</td>';
3871
3872
			if (Globals::$conf->global->PRODUCT_USE_UNITS) {
3873
				print '<td class="linecoluseunit" align="left">'.$langs->trans('Unit').'</td>';
3874
			}
3875
3876
			// Reduction short
3877
			print '<td class="linecoldiscount" align="right">'.$langs->trans('ReductionShort').'</td>';
3878
3879
			if ($this->situation_cycle_ref) {
0 ignored issues
show
Bug Best Practice introduced by
The property situation_cycle_ref does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3880
				print '<td class="linecolcycleref" align="right">' . $langs->trans('Progress') . '</td>';
3881
			}
3882
3883
			if ($usemargins && !empty(Globals::$conf->margin->enabled) && empty($user->societe_id)) {
3884
				if (!empty($user->rights->margins->creer))
3885
				{
3886
					if (Globals::$conf->global->MARGIN_TYPE == "1")
3887
                        print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('BuyingPrice').'</td>';
3888
					else
3889
						print '<td class="linecolmargin1 margininfos" align="right" width="80">'.$langs->trans('CostPrice').'</td>';
3890
				}
3891
3892
				if (!empty(Globals::$conf->global->DISPLAY_MARGIN_RATES) && $user->rights->margins->liretous)
3893
                    print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarginRate').'</td>';
3894
				if (!empty(Globals::$conf->global->DISPLAY_MARK_RATES) && $user->rights->margins->liretous)
3895
                    print '<td class="linecolmargin2 margininfos" align="right" width="50">'.$langs->trans('MarkRate').'</td>';
3896
			}
3897
3898
			// Total HT
3899
			print '<td class="linecolht" align="right">'.$langs->trans('TotalHTShort').'</td>';
3900
3901
			// Multicurrency
3902
			if (!empty(Globals::$conf->multicurrency->enabled) && $this->multicurrency_code != Globals::$conf->currency)
3903
                print '<td class="linecoltotalht_currency" align="right">' . $langs->trans('TotalHTShortCurrency', $this->multicurrency_code) . '</td>';
3904
3905
            if ($outputalsopricetotalwithtax) print '<td align="right" width="80">'.$langs->trans('TotalTTCShort').'</td>';
3906
3907
			print '<td class="linecoledit"></td>';  // No width to allow autodim
3908
3909
			print '<td class="linecoldelete" width="10"></td>';
3910
3911
			print '<td class="linecolmove" width="10"></td>';
3912
3913
			if($action == 'selectlines')
3914
			{
3915
			    print '<td class="linecolcheckall" align="center">';
3916
			    print '<input type="checkbox" class="linecheckboxtoggle" />';
3917
			    print '<script type="text/javascript">$(document).ready(function() {$(".linecheckboxtoggle").click(function() {var checkBoxes = $(".linecheckbox");checkBoxes.prop("checked", this.checked);})});</script>';
3918
			    print '</td>';
3919
			}
3920
3921
			print "</tr>\n";
3922
			print "</thead>\n";
3923
		}
3924
3925
		$var = true;
3926
		$i	 = 0;
3927
3928
		print "<tbody>\n";
3929
		foreach ($this->lines as $line)
3930
		{
3931
			//Line extrafield
3932
			$line->fetch_optionals();
3933
3934
			//if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
3935
			if (is_object($hookmanager))   // Old code is commented on preceding line.
3936
			{
3937
				if (empty($line->fk_parent_line))
3938
				{
3939
					$parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline);
3940
					$reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3941
				}
3942
				else
3943
				{
3944
					$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);
3945
					$reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3946
				}
3947
			}
3948
			if (empty($reshook))
3949
			{
3950
				$this->printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected,$extrafieldsline);
3951
			}
3952
3953
			$i++;
3954
		}
3955
		print "</tbody>\n";
3956
	}
3957
3958
	/**
3959
	 *	Return HTML content of a detail line
3960
	 *	TODO Move this into an output class file (htmlline.class.php)
3961
	 *
3962
	 *	@param	string		$action				GET/POST action
3963
	 *	@param CommonObjectLine $line		       	Selected object line to output
3964
	 *	@param  string	    $var               	Is it a an odd line (true)
3965
	 *	@param  int		    $num               	Number of line (0)
3966
	 *	@param  int		    $i					I
3967
	 *	@param  int		    $dateSelector      	1=Show also date range input fields
3968
	 *	@param  string	    $seller            	Object of seller third party
3969
	 *	@param  string	    $buyer             	Object of buyer third party
3970
	 *	@param	int			$selected		   	Object line selected
3971
	 *  @param  int			$extrafieldsline	Object of extrafield line attribute
3972
	 *	@return	void
3973
	 */
3974
	function printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected=0,$extrafieldsline=0)
3975
	{
3976
		global $conf,$langs,$user,$object,$hookmanager;
3977
		global $form,$bc,$bcdd;
3978
		global $object_rights, $disableedit, $disablemove, $disableremove;   // TODO We should not use global var for this !
3979
3980
		$object_rights = $this->getRights();
3981
3982
		$element=$this->element;
3983
3984
		$text=''; $description=''; $type=0;
3985
3986
		// Show product and description
3987
		$type=(! empty($line->product_type)?$line->product_type:$line->fk_product_type);
3988
		// Try to enhance type detection using date_start and date_end for free lines where type was not saved.
3989
		if (! empty($line->date_start)) $type=1; // deprecated
3990
		if (! empty($line->date_end)) $type=1; // deprecated
3991
3992
		// Ligne en mode visu
3993
		if ($action != 'editline' || $selected != $line->id)
3994
		{
3995
			// Product
3996
			if ($line->fk_product > 0)
3997
			{
3998
				$product_static = new Product($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
3999
				$product_static->fetch($line->fk_product);
4000
4001
				$product_static->ref = $line->ref; //can change ref in hook
4002
				$product_static->label = $line->label; //can change label in hook
4003
				$text=$product_static->getNomUrl(1);
4004
4005
				// Define output language and label
4006
				if (!empty(Globals::$conf->global->MAIN_MULTILANGS)) {
4007
					if (! is_object($this->thirdparty))
4008
					{
4009
						dol_print_error('','Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before');
4010
						return;
4011
					}
4012
4013
					$prod = new Product($this->db);
4014
					$prod->fetch($line->fk_product);
4015
4016
					$outputlangs = $langs;
4017
					$newlang='';
4018
					if (empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09');
4019
					if (!empty(Globals::$conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && empty($newlang))
4020
                        $newlang = $this->thirdparty->default_lang;  // For language to language of customer
4021
                    if (! empty($newlang))
4022
					{
4023
						$outputlangs = new Translate("",$conf);
4024
						$outputlangs->setDefaultLang($newlang);
4025
					}
4026
4027
					$label = (! empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $line->product_label;
4028
				}
4029
				else
4030
				{
4031
					$label = $line->product_label;
4032
				}
4033
4034
				$text.= ' - '.(! empty($line->label)?$line->label:$label);
4035
				$description .= (!empty(Globals::$conf->global->PRODUIT_DESC_IN_FORM) ? '' : dol_htmlentitiesbr($line->description)); // Description is what to show on popup. We shown nothing if already into desc.
4036
            }
4037
4038
			$line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
4039
4040
			// Output template part (modules that overwrite templates must declare this into descriptor)
4041
			// Use global variables + $dateSelector + $seller and $buyer
4042
			$dirtpls = array_merge(Globals::$conf->modules_parts['tpl'], array('/core/tpl'));
4043
            foreach($dirtpls as $reldir)
4044
			{
4045
				$tpl = dol_buildpath($reldir.'/objectline_view.tpl.php');
4046
				if (empty(Globals::$conf->file->strict_mode)) {
4047
                    $res=@include $tpl;
4048
				} else {
4049
					$res=include $tpl; // for debug
4050
				}
4051
				if ($res) break;
4052
			}
4053
		}
4054
4055
		// Ligne en mode update
4056
		if ($this->statut == 0 && $action == 'editline' && $selected == $line->id)
4057
		{
4058
			$label = (! empty($line->label) ? $line->label : (($line->fk_product > 0) ? $line->product_label : ''));
4059
			$placeholder=' placeholder="'.$langs->trans("Label").'"';
4060
4061
			$line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU');
4062
4063
			// Output template part (modules that overwrite templates must declare this into descriptor)
4064
			// Use global variables + $dateSelector + $seller and $buyer
4065
			$dirtpls = array_merge(Globals::$conf->modules_parts['tpl'], array('/core/tpl'));
4066
            foreach($dirtpls as $reldir)
4067
			{
4068
				$tpl = dol_buildpath($reldir.'/objectline_edit.tpl.php');
4069
				if (empty(Globals::$conf->file->strict_mode)) {
4070
                    $res=@include $tpl;
4071
				} else {
4072
					$res=include $tpl; // for debug
4073
				}
4074
				if ($res) break;
4075
			}
4076
		}
4077
	}
4078
4079
4080
	/* This is to show array of line of details of source object */
4081
4082
4083
	/**
4084
	 * 	Return HTML table table of source object lines
4085
	 *  TODO Move this and previous function into output html class file (htmlline.class.php).
4086
	 *  If lines are into a template, title must also be into a template
4087
	 *  But for the moment we don't know if it's possible, so we keep the method available on overloaded objects.
4088
	 *
4089
	 *	@param	string		$restrictlist		''=All lines, 'services'=Restrict to services only
4090
	 *  @return	void
4091
	 */
4092
	function printOriginLinesList($restrictlist='')
4093
	{
4094
		global $langs, $hookmanager, $conf;
4095
4096
		print '<tr class="liste_titre">';
4097
		print '<td>'.$langs->trans('Ref').'</td>';
4098
		print '<td>'.$langs->trans('Description').'</td>';
4099
		print '<td align="right">'.$langs->trans('VATRate').'</td>';
4100
		print '<td align="right">'.$langs->trans('PriceUHT').'</td>';
4101
		if (!empty(Globals::$conf->multicurrency->enabled))
4102
            print '<td align="right">' . $langs->trans('PriceUHTCurrency') . '</td>';
4103
        print '<td align="right">'.$langs->trans('Qty').'</td>';
4104
		if (Globals::$conf->global->PRODUCT_USE_UNITS) {
4105
			print '<td align="left">'.$langs->trans('Unit').'</td>';
4106
		}
4107
		print '<td align="right">'.$langs->trans('ReductionShort').'</td></tr>';
4108
4109
		$var = true;
4110
		$i	 = 0;
4111
4112
		if (! empty($this->lines))
4113
		{
4114
			foreach ($this->lines as $line)
4115
			{
4116
				if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
4117
				{
4118
					if (empty($line->fk_parent_line))
4119
					{
4120
						$parameters=array('line'=>$line,'var'=>$var,'i'=>$i);
4121
						$action='';
4122
						$hookmanager->executeHooks('printOriginObjectLine',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
4123
					}
4124
				}
4125
				else
4126
				{
4127
					$this->printOriginLine($line, $var, $restrictlist);
4128
				}
4129
4130
				$i++;
4131
			}
4132
		}
4133
	}
4134
4135
	/**
4136
	 * 	Return HTML with a line of table array of source object lines
4137
	 *  TODO Move this and previous function into output html class file (htmlline.class.php).
4138
	 *  If lines are into a template, title must also be into a template
4139
	 *  But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
4140
	 *
4141
	 * 	@param	CommonObjectLine	$line				Line
4142
	 * 	@param	string				$var				Var
4143
	 *	@param	string				$restrictlist		''=All lines, 'services'=Restrict to services only (strike line if not)
4144
	 * 	@return	void
4145
	 */
4146
	function printOriginLine($line, $var, $restrictlist='')
4147
	{
4148
		global $langs, $conf;
4149
4150
		//var_dump($line);
4151
		if (!empty($line->date_start))
4152
		{
4153
			$date_start=$line->date_start;
4154
		}
4155
		else
4156
		{
4157
			$date_start=$line->date_debut_prevue;
4158
			if ($line->date_debut_reel) $date_start=$line->date_debut_reel;
4159
		}
4160
		if (!empty($line->date_end))
4161
		{
4162
			$date_end=$line->date_end;
4163
		}
4164
		else
4165
		{
4166
			$date_end=$line->date_fin_prevue;
4167
			if ($line->date_fin_reel) $date_end=$line->date_fin_reel;
4168
		}
4169
4170
		$this->tpl['label'] = '';
4171
		if (! empty($line->fk_parent_line)) $this->tpl['label'].= img_picto('', 'rightarrow');
4172
4173
		if (($line->info_bits & 2) == 2)  // TODO Not sure this is used for source object
4174
		{
4175
			$discount=new DiscountAbsolute($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
4176
			$discount->fk_soc = $this->socid;
4177
			$this->tpl['label'].= $discount->getNomUrl(0,'discount');
4178
		}
4179
		else if (! empty($line->fk_product))
4180
		{
4181
			$productstatic = new Product($this->db);
4182
			$productstatic->id = $line->fk_product;
4183
			$productstatic->ref = $line->ref;
4184
			$productstatic->type = $line->fk_product_type;
4185
            if(empty($productstatic->ref)){
4186
				$line->fetch_product();
4187
				$productstatic = $line->product;
4188
			}
4189
			
4190
			$this->tpl['label'].= $productstatic->getNomUrl(1);
4191
			$this->tpl['label'].= ' - '.(! empty($line->label)?$line->label:$line->product_label);
4192
			// Dates
4193
			if ($line->product_type == 1 && ($date_start || $date_end))
4194
			{
4195
				$this->tpl['label'].= get_date_range($date_start,$date_end);
4196
			}
4197
		}
4198
		else
4199
		{
4200
			$this->tpl['label'].= ($line->product_type == -1 ? '&nbsp;' : ($line->product_type == 1 ? img_object($langs->trans(''),'service') : img_object($langs->trans(''),'product')));
4201
			if (!empty($line->desc)) {
4202
				$this->tpl['label'].=$line->desc;
4203
			}else {
4204
				$this->tpl['label'].= ($line->label ? '&nbsp;'.$line->label : '');
4205
			}
4206
			
4207
			// Dates
4208
			if ($line->product_type == 1 && ($date_start || $date_end))
4209
			{
4210
				$this->tpl['label'].= get_date_range($date_start,$date_end);
4211
			}
4212
		}
4213
4214
		if (! empty($line->desc))
4215
		{
4216
			if ($line->desc == '(CREDIT_NOTE)')  // TODO Not sure this is used for source object
4217
			{
4218
				$discount=new DiscountAbsolute($this->db);
4219
				$discount->fetch($line->fk_remise_except);
4220
				$this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote",$discount->getNomUrl(0));
4221
			}
4222
			elseif ($line->desc == '(DEPOSIT)')  // TODO Not sure this is used for source object
4223
			{
4224
				$discount=new DiscountAbsolute($this->db);
4225
				$discount->fetch($line->fk_remise_except);
4226
				$this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit",$discount->getNomUrl(0));
4227
			}
4228
			elseif ($line->desc == '(EXCESS RECEIVED)')
4229
			{
4230
				$discount=new DiscountAbsolute($this->db);
4231
				$discount->fetch($line->fk_remise_except);
4232
				$this->tpl['description'] = $langs->transnoentities("DiscountFromExcessReceived",$discount->getNomUrl(0));
4233
			}
4234
			elseif ($line->desc == '(EXCESS PAID)')
4235
			{
4236
				$discount=new DiscountAbsolute($this->db);
4237
				$discount->fetch($line->fk_remise_except);
4238
				$this->tpl['description'] = $langs->transnoentities("DiscountFromExcessPaid",$discount->getNomUrl(0));
4239
			}
4240
			else
4241
			{
4242
				$this->tpl['description'] = dol_trunc($line->desc,60);
4243
			}
4244
		}
4245
		else
4246
		{
4247
			$this->tpl['description'] = '&nbsp;';
4248
		}
4249
4250
        // VAT Rate
4251
        $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
4252
        $this->tpl['vat_rate'] .= (($line->info_bits & 1) == 1) ? '*' : '';
4253
        if (! empty($line->vat_src_code) && ! preg_match('/\(/', $this->tpl['vat_rate'])) $this->tpl['vat_rate'].=' ('.$line->vat_src_code.')';
4254
4255
		$this->tpl['price'] = price($line->subprice);
4256
		$this->tpl['multicurrency_price'] = price($line->multicurrency_subprice);
4257
		$this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : '&nbsp;';
4258
		if (Globals::$conf->global->PRODUCT_USE_UNITS)
4259
            $this->tpl['unit'] = $langs->transnoentities($line->getLabelOfUnit('long'));
4260
        $this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : '&nbsp;';
4261
4262
		// Is the line strike or not
4263
		$this->tpl['strike']=0;
4264
		if ($restrictlist == 'services' && $line->product_type != Product::TYPE_SERVICE) $this->tpl['strike']=1;
4265
4266
		// Output template part (modules that overwrite templates must declare this into descriptor)
4267
		// Use global variables + $dateSelector + $seller and $buyer
4268
		$dirtpls = array_merge(Globals::$conf->modules_parts['tpl'], array('/core/tpl'));
4269
        foreach($dirtpls as $reldir)
4270
		{
4271
			$tpl = dol_buildpath($reldir.'/originproductline.tpl.php');
4272
			if (empty(Globals::$conf->file->strict_mode)) {
4273
                $res=@include $tpl;
4274
			} else {
4275
				$res=include $tpl; // for debug
4276
			}
4277
			if ($res) break;
4278
		}
4279
	}
4280
4281
4282
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4283
	/**
4284
	 *	Add resources to the current object : add entry into llx_element_resources
4285
	 *	Need $this->element & $this->id
4286
	 *
4287
	 *	@param		int		$resource_id		Resource id
4288
	 *	@param		string	$resource_type		'resource'
4289
	 *	@param		int		$busy				Busy or not
4290
	 *	@param		int		$mandatory			Mandatory or not
4291
	 *	@return		int							<=0 if KO, >0 if OK
4292
	 */
4293
	function add_element_resource($resource_id, $resource_type, $busy=0, $mandatory=0)
4294
	{
4295
        // phpcs:enable
4296
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
4297
4298
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."element_resources (";
4299
		$sql.= "resource_id";
4300
		$sql.= ", resource_type";
4301
		$sql.= ", element_id";
4302
		$sql.= ", element_type";
4303
		$sql.= ", busy";
4304
		$sql.= ", mandatory";
4305
		$sql.= ") VALUES (";
4306
		$sql.= $resource_id;
4307
		$sql.= ", '".$this->db->escape($resource_type)."'";
4308
		$sql.= ", '".$this->db->escape($this->id)."'";
4309
		$sql.= ", '".$this->db->escape($this->element)."'";
4310
		$sql.= ", '".$this->db->escape($busy)."'";
4311
		$sql.= ", '".$this->db->escape($mandatory)."'";
4312
		$sql.= ")";
4313
4314
		dol_syslog(get_class($this)."::add_element_resource", LOG_DEBUG);
4315
		if ($this->db->query($sql))
4316
		{
4317
			$this->db->commit();
4318
			return 1;
4319
		}
4320
		else
4321
		{
4322
			$this->error=$this->db->lasterror();
4323
			$this->db->rollback();
4324
			return  0;
4325
		}
4326
	}
4327
4328
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4329
	/**
4330
	 *    Delete a link to resource line
4331
	 *
4332
	 *    @param	int		$rowid			Id of resource line to delete
4333
	 *    @param	int		$element		element name (for trigger) TODO: use $this->element into commonobject class
4334
	 *    @param	int		$notrigger		Disable all triggers
4335
	 *    @return   int						>0 if OK, <0 if KO
4336
	 */
4337
	function delete_resource($rowid, $element, $notrigger=0)
4338
	{
4339
        // phpcs:enable
4340
		global $user;
4341
4342
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
4343
4344
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_resources";
4345
		$sql.= " WHERE rowid=".$rowid;
4346
4347
		dol_syslog(get_class($this)."::delete_resource", LOG_DEBUG);
4348
4349
		$resql=$this->db->query($sql);
4350
		if (! $resql)
4351
		{
4352
			$this->error=$this->db->lasterror();
4353
			$this->db->rollback();
4354
			return -1;
4355
		}
4356
		else
4357
		{
4358
			if (! $notrigger)
4359
			{
4360
				$result=$this->call_trigger(strtoupper($element).'_DELETE_RESOURCE', $user);
4361
				if ($result < 0) { $this->db->rollback(); return -1; }
4362
			}
4363
			$this->db->commit();
4364
			return 1;
4365
		}
4366
	}
4367
4368
4369
	/**
4370
	 * Overwrite magic function to solve problem of cloning object that are kept as references
4371
	 *
4372
	 * @return void
4373
	 */
4374
	function __clone()
4375
	{
4376
		// Force a copy of this->lines, otherwise it will point to same object.
4377
		if (isset($this->lines) && is_array($this->lines))
4378
		{
4379
			$nboflines=count($this->lines);
4380
			for($i=0; $i < $nboflines; $i++)
4381
			{
4382
				$this->lines[$i] = clone $this->lines[$i];
4383
			}
4384
		}
4385
	}
4386
4387
	/**
4388
	 * Common function for all objects extending CommonObject for generating documents
4389
	 *
4390
	 * @param 	string 		$modelspath 	Relative folder where generators are placed
4391
	 * @param 	string 		$modele 		Generator to use. Caller must set it to obj->modelpdf or GETPOST('modelpdf') for example.
4392
	 * @param 	Translate 	$outputlangs 	Output language to use
4393
	 * @param 	int 		$hidedetails 	1 to hide details. 0 by default
4394
	 * @param 	int 		$hidedesc 		1 to hide product description. 0 by default
4395
	 * @param 	int 		$hideref 		1 to hide product reference. 0 by default
4396
	 * @param   null|array  $moreparams     Array to provide more information
4397
	 * @return 	int 						>0 if OK, <0 if KO
4398
	 * @see	addFileIntoDatabaseIndex
4399
	 */
4400
	protected function commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
4401
	{
4402
		global $conf, $langs, $user;
4403
4404
		$srctemplatepath='';
4405
4406
		// Increase limit for PDF build
4407
		$err=error_reporting();
4408
		error_reporting(0);
4409
		@set_time_limit(120);
4410
		error_reporting($err);
4411
4412
		// If selected model is a filename template (then $modele="modelname" or "modelname:filename")
4413
		$tmp=explode(':',$modele,2);
4414
		if (! empty($tmp[1]))
4415
		{
4416
			$modele=$tmp[0];
4417
			$srctemplatepath=$tmp[1];
4418
		}
4419
4420
		// Search template files
4421
		$file=''; $classname=''; $filefound=0;
4422
		$dirmodels=array('/');
4423
		if (is_array(Globals::$conf->modules_parts['models']))
4424
            $dirmodels = array_merge($dirmodels, Globals::$conf->modules_parts['models']);
4425
        foreach($dirmodels as $reldir)
4426
		{
4427
			foreach(array('doc','pdf') as $prefix)
4428
			{
4429
				if (in_array(get_class($this), array('Adherent'))) $file = $prefix."_".$modele.".class.php";     // Member module use prefix_module.class.php
4430
				else $file = $prefix."_".$modele.".modules.php";
4431
4432
				// On verifie l'emplacement du modele
4433
				$file=dol_buildpath($reldir.$modelspath.$file,0);
4434
				if (file_exists($file))
4435
				{
4436
					$filefound=1;
4437
					$classname=$prefix.'_'.$modele;
4438
					break;
4439
				}
4440
			}
4441
			if ($filefound) break;
4442
		}
4443
4444
		// If generator was found
4445
		if ($filefound)
4446
		{
4447
			global $db;  // Required to solve a conception default in commonstickergenerator.class.php making an include of code using $db
4448
4449
			require_once $file;
4450
4451
			$obj = new $classname($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
4452
4453
			// If generator is ODT, we must have srctemplatepath defined, if not we set it.
4454
			if ($obj->type == 'odt' && empty($srctemplatepath))
4455
			{
4456
				$varfortemplatedir=$obj->scandir;
4457
				if ($varfortemplatedir && !empty(Globals::$conf->global->$varfortemplatedir)) {
4458
					$dirtoscan = Globals::$conf->global->$varfortemplatedir;
4459
4460
                    $listoffiles=array();
4461
4462
					// Now we add first model found in directories scanned
4463
					$listofdir=explode(',',$dirtoscan);
4464
					foreach($listofdir as $key => $tmpdir)
4465
					{
4466
						$tmpdir=trim($tmpdir);
4467
						$tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir);
4468
						if (! $tmpdir) { unset($listofdir[$key]); continue; }
4469
						if (is_dir($tmpdir))
4470
						{
4471
							$tmpfiles=dol_dir_list($tmpdir,'files',0,'\.od(s|t)$','','name',SORT_ASC,0);
4472
							if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles);
4473
						}
4474
					}
4475
4476
					if (count($listoffiles))
4477
					{
4478
						foreach($listoffiles as $record)
4479
						{
4480
							$srctemplatepath=$record['fullname'];
4481
							break;
4482
						}
4483
					}
4484
				}
4485
4486
				if (empty($srctemplatepath))
4487
				{
4488
					$this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotDefined';
4489
					return -1;
4490
				}
4491
			}
4492
4493
			if ($obj->type == 'odt' && ! empty($srctemplatepath))
4494
			{
4495
				if (! dol_is_file($srctemplatepath))
4496
				{
4497
					$this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotFound';
4498
					return -1;
4499
				}
4500
			}
4501
4502
			// We save charset_output to restore it because write_file can change it if needed for
4503
			// output format that does not support UTF8.
4504
			$sav_charset_output=$outputlangs->charset_output;
4505
4506
			if (in_array(get_class($this), array('Adherent')))
4507
			{
4508
				$arrayofrecords = array();   // The write_file of templates of adherent class need this var
4509
				$resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, $moreparams);
4510
			}
4511
			else
4512
			{
4513
				$resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams);
4514
			}
4515
			// After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index.
4516
4517
			if ($resultwritefile > 0)
4518
			{
4519
				$outputlangs->charset_output=$sav_charset_output;
4520
4521
				// We delete old preview
4522
				require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
4523
				dol_delete_preview($this);
4524
4525
				// Index file in database
4526
				if (! empty($obj->result['fullpath']))
4527
				{
4528
					$destfull = $obj->result['fullpath'];
4529
					$upload_dir = dirname($destfull);
4530
					$destfile = basename($destfull);
4531
					$rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $upload_dir);
4532
4533
					if (! preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir))     // If not a tmp dir
4534
					{
4535
						$filename = basename($destfile);
4536
						$rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
4537
						$rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
4538
4539
						include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
4540
						$ecmfile=new EcmFiles($this->db);
4541
						$result = $ecmfile->fetch(0, '', ($rel_dir?$rel_dir.'/':'').$filename);
4542
4543
						// Set the public "share" key
4544
						$setsharekey = false;
4545
						if ($this->element == 'propal')
4546
						{
4547
							$useonlinesignature = Globals::$conf->global->MAIN_FEATURES_LEVEL; // Replace this with 1 when feature to make online signature is ok
4548
                            if ($useonlinesignature) $setsharekey=true;
4549
							if (!empty(Globals::$conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD))
4550
                                $setsharekey = true;
4551
                        }
4552
						if ($this->element == 'commande' && !empty(Globals::$conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD))
4553
                            $setsharekey = true;
4554
                        if ($this->element == 'facture' && !empty(Globals::$conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD))
4555
                            $setsharekey = true;
4556
                        if ($this->element == 'bank_account' && !empty(Globals::$conf->global->BANK_ACCOUNT_ALLOW_EXTERNAL_DOWNLOAD))
4557
                            $setsharekey = true;
4558
4559
                        if ($setsharekey)
4560
						{
4561
							if (empty($ecmfile->share))	// Because object not found or share not set yet
4562
							{
4563
								require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
4564
								$ecmfile->share = getRandomPassword(true);
4565
							}
4566
						}
4567
4568
						if ($result > 0)
4569
						{
4570
							$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
4571
							$ecmfile->fullpath_orig = '';
4572
							$ecmfile->gen_or_uploaded = 'generated';
4573
							$ecmfile->description = '';    // indexed content
4574
							$ecmfile->keyword = '';        // keyword content
4575
							$result = $ecmfile->update($user);
4576
							if ($result < 0)
4577
							{
4578
								setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4579
							}
4580
						}
4581
						else
4582
						{
4583
							$ecmfile->entity = Globals::$conf->entity;
4584
                            $ecmfile->filepath = $rel_dir;
4585
							$ecmfile->filename = $filename;
4586
							$ecmfile->label = md5_file(dol_osencode($destfull));	// hash of file content
4587
							$ecmfile->fullpath_orig = '';
4588
							$ecmfile->gen_or_uploaded = 'generated';
4589
							$ecmfile->description = '';    // indexed content
4590
							$ecmfile->keyword = '';        // keyword content
4591
							$ecmfile->src_object_type = $this->table_element;
4592
							$ecmfile->src_object_id   = $this->id;
4593
4594
							$result = $ecmfile->create($user);
4595
							if ($result < 0)
4596
							{
4597
								setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
4598
							}
4599
						}
4600
4601
						/*$this->result['fullname']=$destfull;
4602
						$this->result['filepath']=$ecmfile->filepath;
4603
						$this->result['filename']=$ecmfile->filename;*/
4604
						//var_dump($obj->update_main_doc_field);exit;
4605
4606
						// Update the last_main_doc field into main object (if documenent generator has property ->update_main_doc_field set)
4607
						$update_main_doc_field=0;
4608
						if (! empty($obj->update_main_doc_field)) $update_main_doc_field=1;
4609
						if ($update_main_doc_field && ! empty($this->table_element))
4610
						{
4611
							$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET last_main_doc = '".($ecmfile->filepath.'/'.$ecmfile->filename)."'";
4612
							$sql.= ' WHERE rowid = '.$this->id;
4613
							$resql = $this->db->query($sql);
4614
							if (! $resql) dol_print_error($this->db);
4615
						}
4616
					}
4617
				}
4618
				else
4619
				{
4620
					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);
4621
				}
4622
4623
				// Success in building document. We build meta file.
4624
				dol_meta_create($this);
4625
4626
				return 1;
4627
			}
4628
			else
4629
			{
4630
				$outputlangs->charset_output=$sav_charset_output;
4631
				dol_print_error($this->db, "Error generating document for ".__CLASS__.". Error: ".$obj->error, $obj->errors);
4632
				return -1;
4633
			}
4634
		}
4635
		else
4636
		{
4637
			$this->error=$langs->trans("Error")." ".$langs->trans("ErrorFileDoesNotExists",$file);
4638
			dol_print_error('',$this->error);
4639
			return -1;
4640
		}
4641
	}
4642
4643
	/**
4644
	 *  Build thumb
4645
	 *  @TODO Move this into files.lib.php
4646
	 *
4647
	 *  @param      string	$file           Path file in UTF8 to original file to create thumbs from.
4648
	 *	@return		void
4649
	 */
4650
	function addThumbs($file)
4651
	{
4652
		global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini, $quality;
4653
4654
		require_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';		// This define also $maxwidthsmall, $quality, ...
4655
4656
		$file_osencoded=dol_osencode($file);
4657
		if (file_exists($file_osencoded))
4658
		{
4659
			// Create small thumbs for company (Ratio is near 16/9)
4660
			// Used on logon for example
4661
			vignette($file_osencoded, $maxwidthsmall, $maxheightsmall, '_small', $quality);
4662
4663
			// Create mini thumbs for company (Ratio is near 16/9)
4664
			// Used on menu or for setup page for example
4665
			vignette($file_osencoded, $maxwidthmini, $maxheightmini, '_mini', $quality);
4666
		}
4667
	}
4668
4669
4670
	/* Functions common to commonobject and commonobjectline */
4671
4672
	/* For default values */
4673
4674
	/**
4675
	 * Return the default value to use for a field when showing the create form of object.
4676
	 * Return values in this order:
4677
	 * 1) If parameter is available into POST, we return it first.
4678
	 * 2) If not but an alternate value was provided as parameter of function, we return it.
4679
	 * 3) If not but a constant Globals::$conf->global->OBJECTELEMENT_FIELDNAME is set, we return it (It is better to use the dedicated table).
4680
	 * 4) Return value found into database (TODO No yet implemented)
4681
	 *
4682
	 * @param   string              $fieldname          Name of field
4683
	 * @param   string              $alternatevalue     Alternate value to use
4684
	 * @return  string|string[]                         Default value (can be an array if the GETPOST return an array)
4685
	 **/
4686
	function getDefaultCreateValueFor($fieldname, $alternatevalue=null)
4687
	{
4688
		global $conf, $_POST;
4689
4690
		// If param here has been posted, we use this value first.
4691
		if (isset($_POST[$fieldname])) return GETPOST($fieldname, 2);
4692
4693
		if (isset($alternatevalue)) return $alternatevalue;
4694
4695
		$newelement=$this->element;
4696
		if ($newelement == 'facture') $newelement='invoice';
4697
		if ($newelement == 'commande') $newelement='order';
4698
		if (empty($newelement))
4699
		{
4700
			dol_syslog("Ask a default value using common method getDefaultCreateValueForField on an object with no property ->element defined. Return empty string.", LOG_WARNING);
4701
			return '';
4702
		}
4703
4704
		$keyforfieldname=strtoupper($newelement.'_DEFAULT_'.$fieldname);
4705
		//var_dump($keyforfieldname);
4706
		if (isset(Globals::$conf->global->$keyforfieldname))
4707
            return Globals::$conf->global->$keyforfieldname;
4708
4709
        // TODO Ad here a scan into table llx_overwrite_default with a filter on $this->element and $fieldname
4710
	}
4711
4712
4713
	/* For triggers */
4714
4715
4716
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4717
	/**
4718
	 * Call trigger based on this instance.
4719
	 * Some context information may also be provided into array property this->context.
4720
	 * NB:  Error from trigger are stacked in interface->errors
4721
	 * NB2: If return code of triggers are < 0, action calling trigger should cancel all transaction.
4722
	 *
4723
	 * @param   string    $trigger_name   trigger's name to execute
4724
	 * @param   User      $user           Object user
4725
	 * @return  int                       Result of run_triggers
4726
	 */
4727
	function call_trigger($trigger_name, $user)
4728
	{
4729
        // phpcs:enable
4730
		global $langs,$conf;
4731
4732
		include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
4733
		$interface=new Interfaces($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
4734
		$result=$interface->run_triggers($trigger_name,$this,$user,$langs,$conf);
4735
4736
		if ($result < 0)
4737
		{
4738
			if (!empty($this->errors))
4739
			{
4740
				$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.
4741
			}
4742
			else
4743
			{
4744
				$this->errors=$interface->errors;
4745
			}
4746
		}
4747
		return $result;
4748
	}
4749
4750
4751
	/* Functions for extrafields */
4752
4753
4754
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4755
	/**
4756
	 *  Function to get extra fields of an object into $this->array_options
4757
	 *  This method is in most cases called by method fetch of objects but you can call it separately.
4758
	 *
4759
	 *  @param	int		$rowid			Id of line. Use the id of object if not defined. Deprecated. Function must be called without parameters.
4760
	 *  @param  array	$optionsArray   Array resulting of call of extrafields->fetch_name_optionals_label(). Deprecated. Function must be called without parameters.
4761
	 *  @return	int						<0 if error, 0 if no values of extrafield to find nor found, 1 if an attribute is found and value loaded
4762
	 */
4763
	function fetch_optionals($rowid=null, $optionsArray=null)
4764
	{
4765
        // phpcs:enable
4766
		if (empty($rowid)) {
4767
            $rowid = $this->id;
4768
        }
4769
4770
        // To avoid SQL errors. Probably not the better solution though
4771
		if (!$this->table_element) {
4772
			return 0;
4773
		}
4774
4775
		$this->array_options=array();
4776
4777
		if (! is_array($optionsArray))
4778
		{
4779
			// If $extrafields is not a known object, we initialize it. Best practice is to have $extrafields defined into card.php or list.php page.
4780
			// TODO Use of existing $extrafield is not yet ready (must mutualize code that use extrafields in form first)
4781
			// global $extrafields;
4782
			//if (! is_object($extrafields))
4783
			//{
4784
				// require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4785
            $extrafields = new AlExtraFields();
4786
            //}
4787
4788
			// Load array of extrafields for elementype = $this->table_element
4789
			if (empty($extrafields->attributes[$this->table_element]['loaded']))
4790
			{
4791
				$extrafields->fetch_name_optionals_label($this->table_element);
4792
			}
4793
			$optionsArray = (! empty($extrafields->attributes[$this->table_element]['label'])?$extrafields->attributes[$this->table_element]['label']:null);
4794
		}
4795
		else
4796
		{
4797
			// global $extrafields;
4798
            dol_syslog("Warning: fetch_optionals was called with param optionsArray defined when you should pass null now", LOG_WARNING);
4799
		}
4800
4801
		$table_element = $this->table_element;
4802
		if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4803
4804
		// Request to get complementary values
4805
		if (is_array($optionsArray) && count($optionsArray) > 0)
4806
		{
4807
			$sql = "SELECT rowid";
4808
			foreach ($optionsArray as $name => $label)
4809
			{
4810
				if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] != 'separate')
4811
				{
4812
					$sql.= ", ".$name;
4813
				}
4814
			}
4815
			$sql.= " FROM ".MAIN_DB_PREFIX.$table_element."_extrafields";
4816
			$sql.= " WHERE fk_object = ".$rowid;
4817
4818
			//dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG);		// Too verbose
4819
			$resql=$this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
4820
			if ($resql)
4821
			{
4822
				$this->array_options = array();
4823
				$numrows=$this->db->num_rows($resql);
4824
				if ($numrows)
4825
				{
4826
					$tab = $this->db->fetch_array($resql);
4827
4828
					foreach ($tab as $key => $value)
4829
					{
4830
						// 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)
4831
						if ($key != 'rowid' && $key != 'tms' && $key != 'fk_member' && ! is_int($key))
4832
						{
4833
							// we can add this attribute to object
4834
							if (! empty($extrafields) && in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date','datetime')))
4835
							{
4836
								//var_dump($extrafields->attributes[$this->table_element]['type'][$key]);
4837
								$this->array_options["options_".$key]=$this->db->jdate($value);
4838
							}
4839
							else
4840
							{
4841
								$this->array_options["options_".$key]=$value;
4842
							}
4843
4844
							//var_dump('key '.$key.' '.$value.' type='.$extrafields->attributes[$this->table_element]['type'][$key].' '.$this->array_options["options_".$key]);
4845
						}
4846
					}
4847
				}
4848
4849
				$this->db->free($resql);
4850
4851
				if ($numrows) return $numrows;
4852
				else return 0;
4853
			}
4854
			else
4855
			{
4856
				dol_print_error($this->db);
4857
				return -1;
4858
			}
4859
		}
4860
		return 0;
4861
	}
4862
4863
	/**
4864
	 *	Delete all extra fields values for the current object.
4865
	 *
4866
	 *  @return	int		<0 if KO, >0 if OK
4867
	 */
4868
	function deleteExtraFields()
4869
	{
4870
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
4871
4872
		$table_element = $this->table_element;
4873
		if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4874
4875
		$sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
4876
		dol_syslog(get_class($this)."::deleteExtraFields delete", LOG_DEBUG);
4877
		$resql=$this->db->query($sql_del);
4878
		if (! $resql)
4879
		{
4880
			$this->error=$this->db->lasterror();
4881
			$this->db->rollback();
4882
			return -1;
4883
		}
4884
		else
4885
		{
4886
			$this->db->commit();
4887
			return 1;
4888
		}
4889
	}
4890
4891
	/**
4892
	 *	Add/Update all extra fields values for the current object.
4893
	 *  Data to describe values to insert/update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
4894
	 *  This function delete record with all extrafields and insert them again from the array $this->array_options.
4895
	 *
4896
	 *  @param	string		$trigger		If defined, call also the trigger (for example COMPANY_MODIFY)
4897
	 *  @param	User		$userused		Object user
4898
	 *  @return int 						-1=error, O=did nothing, 1=OK
4899
	 *  @see updateExtraField, setValueFrom
4900
	 */
4901
	function insertExtraFields($trigger='', $userused=null)
4902
	{
4903
		global $conf,$langs,$user;
4904
4905
		if (empty($userused)) $userused=$user;
4906
4907
		$error=0;
4908
4909
		if (!empty(Globals::$conf->global->MAIN_EXTRAFIELDS_DISABLED))
4910
            return 0; // For avoid conflicts if trigger used
4911
4912
        if (! empty($this->array_options))
4913
		{
4914
			// Check parameters
4915
			$langs->load('admin');
4916
			require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
4917
			$extrafields = new AlExtraFields($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
4918
            $target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
4919
4920
			//Eliminate copied source object extra_fields that do not exist in target object
4921
			$new_array_options=array();
4922
			foreach ($this->array_options as $key => $value) {
4923
				if (in_array(substr($key,8), array_keys($target_extrafields)))	// We remove the 'options_' from $key for test
4924
					$new_array_options[$key] = $value;
4925
				elseif (in_array($key, array_keys($target_extrafields)))		// We test on $key that does not contains the 'options_' prefix
4926
					$new_array_options['options_'.$key] = $value;
4927
			}
4928
4929
			foreach($new_array_options as $key => $value)
4930
			{
4931
			   	$attributeKey      = substr($key,8);   // Remove 'options_' prefix
4932
			   	$attributeType     = $extrafields->attributes[$this->table_element]['type'][$attributeKey];
4933
			   	$attributeLabel    = $extrafields->attributes[$this->table_element]['label'][$attributeKey];
4934
			   	$attributeParam    = $extrafields->attributes[$this->table_element]['param'][$attributeKey];
4935
			   	$attributeRequired = $extrafields->attributes[$this->table_element]['required'][$attributeKey];
4936
4937
			   	if ($attributeRequired)
4938
			   	{
4939
			   		$mandatorypb=false;
4940
			   		if ($attributeType == 'link' && $this->array_options[$key] == '-1') $mandatorypb=true;
4941
			   		if ($this->array_options[$key] === '') $mandatorypb=true;
4942
			   		if ($mandatorypb)
4943
			   		{
4944
			   			dol_syslog($this->error);
4945
			   			$this->errors[]=$langs->trans('ErrorFieldRequired', $attributeLabel);
4946
			   			return -1;
4947
			   		}
4948
			   	}
4949
4950
				//dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
4951
				//dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
4952
4953
			   	switch ($attributeType)
4954
			   	{
4955
			   		case 'int':
4956
			  			if (!is_numeric($value) && $value!='')
4957
			   			{
4958
			   				$this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4959
			   				return -1;
4960
			  			}
4961
			   			elseif ($value=='')
4962
			   			{
4963
			   				$new_array_options[$key] = null;
4964
			   			}
4965
			 			break;
4966
					case 'double':
4967
						$value = price2num($value);
4968
						if (!is_numeric($value) && $value!='')
4969
						{
4970
							dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
4971
							$this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4972
							return -1;
4973
						}
4974
						elseif ($value=='')
4975
						{
4976
							$new_array_options[$key] = null;
4977
						}
4978
						//dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
4979
						$new_array_options[$key] = $value;
4980
						break;
4981
			 		/*case 'select':	// Not required, we chosed value='0' for undefined values
4982
             			if ($value=='-1')
4983
             			{
4984
             				$this->array_options[$key] = null;
4985
             			}
4986
             			break;*/
4987
			   		case 'password':
4988
			   			$algo='';
4989
			   			if ($this->array_options[$key] != '' && is_array($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']))
4990
			   			{
4991
			   				// If there is an encryption choice, we use it to crypt data before insert
4992
			   				$tmparrays = array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']);
4993
			   				$algo=reset($tmparrays);
4994
			   				if ($algo != '')
4995
			   				{
4996
			   					//global $action;		// $action may be 'create', 'update', 'update_extras'...
4997
			   					//var_dump($action);
4998
			   					//var_dump($this->oldcopy);exit;
4999
			   					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
5000
			   					{
5001
			   						//var_dump($this->oldcopy->array_options[$key]); var_dump($this->array_options[$key]);
5002
				   					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.
5003
				   					{
5004
				   						$new_array_options[$key] = $this->array_options[$key];	// Value is kept
5005
				   					}
5006
									else
5007
									{
5008
										// var_dump($algo);
5009
										$newvalue = dol_hash($this->array_options[$key], $algo);
5010
										$new_array_options[$key] = $newvalue;
5011
									}
5012
			   					}
5013
			   					else
5014
			   					{
5015
			   						$new_array_options[$key] = $this->array_options[$key];	// Value is kept
5016
			   					}
5017
			   				}
5018
			   			}
5019
			   			else	// Common usage
5020
			   			{
5021
			   				$new_array_options[$key] = $this->array_options[$key];
5022
			   			}
5023
			   			break;
5024
			   		case 'price':
5025
						$new_array_options[$key] = price2num($this->array_options[$key]);
5026
						break;
5027
					case 'date':
5028
						$new_array_options[$key] = $this->db->idate($this->array_options[$key]);
5029
						break;
5030
					case 'datetime':
5031
						// If data is a string instead of a timestamp, we convert it
5032
						if (! is_int($this->array_options[$key])) {
5033
							$this->array_options[$key] = strtotime($this->array_options[$key]);
5034
						}
5035
						$new_array_options[$key] = $this->db->idate($this->array_options[$key]);
5036
						break;
5037
		   			case 'link':
5038
						$param_list=array_keys($attributeParam['options']);
5039
						// 0 : ObjectName
5040
						// 1 : classPath
5041
						$InfoFieldList = explode(":", $param_list[0]);
5042
						dol_include_once($InfoFieldList[1]);
5043
						if ($InfoFieldList[0] && class_exists($InfoFieldList[0]))
5044
						{
5045
							if ($value == '-1')	// -1 is key for no defined in combo list of objects
5046
							{
5047
								$new_array_options[$key]='';
5048
							}
5049
							elseif ($value)
5050
							{
5051
								$object = new $InfoFieldList[0]($this->db);
5052
								if (is_numeric($value)) $res=$object->fetch($value);
5053
								else $res=$object->fetch('',$value);
5054
5055
								if ($res > 0) $new_array_options[$key]=$object->id;
5056
								else
5057
								{
5058
									$this->error="Id/Ref '".$value."' for object '".$object->element."' not found";
5059
									$this->db->rollback();
5060
									return -1;
5061
								}
5062
							}
5063
						}
5064
						else
5065
						{
5066
							dol_syslog('Error bad setup of extrafield', LOG_WARNING);
5067
						}
5068
						break;
5069
			   	}
5070
			}
5071
5072
			$this->db->begin();
5073
5074
			$table_element = $this->table_element;
5075
			if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
5076
5077
			$sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id;
5078
			dol_syslog(get_class($this)."::insertExtraFields delete", LOG_DEBUG);
5079
			$this->db->query($sql_del);
5080
5081
			$sql = "INSERT INTO ".MAIN_DB_PREFIX.$table_element."_extrafields (fk_object";
5082
			foreach($new_array_options as $key => $value)
5083
			{
5084
				$attributeKey = substr($key,8);   // Remove 'options_' prefix
5085
				// Add field of attribut
5086
				if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator
5087
					$sql.=",".$attributeKey;
5088
			}
5089
			$sql .= ") VALUES (".$this->id;
5090
5091
			foreach($new_array_options as $key => $value)
5092
			{
5093
				$attributeKey = substr($key,8);   // Remove 'options_' prefix
5094
				// Add field of attribute
5095
				if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator)
5096
				{
5097
					if ($new_array_options[$key] != '')
5098
					{
5099
						$sql.=",'".$this->db->escape($new_array_options[$key])."'";
5100
					}
5101
					else
5102
					{
5103
						$sql.=",null";
5104
					}
5105
				}
5106
			}
5107
			$sql.=")";
5108
5109
			dol_syslog(get_class($this)."::insertExtraFields insert", LOG_DEBUG);
5110
			$resql = $this->db->query($sql);
5111
			if (! $resql)
5112
			{
5113
				$this->error=$this->db->lasterror();
5114
				$error++;
5115
			}
5116
5117
			if (! $error && $trigger)
5118
			{
5119
				// Call trigger
5120
				$this->context=array('extrafieldaddupdate'=>1);
5121
				$result=$this->call_trigger($trigger, $userused);
5122
				if ($result < 0) $error++;
5123
				// End call trigger
5124
			}
5125
5126
			if ($error)
5127
			{
5128
				$this->db->rollback();
5129
				return -1;
5130
			}
5131
			else
5132
			{
5133
				$this->db->commit();
5134
				return 1;
5135
			}
5136
		}
5137
		else return 0;
5138
	}
5139
5140
	/**
5141
	 *	Update an extra field value for the current object.
5142
	 *  Data to describe values to update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
5143
	 *
5144
	 *  @param  string      $key    		Key of the extrafield (without starting 'options_')
5145
	 *  @param	string		$trigger		If defined, call also the trigger (for example COMPANY_MODIFY)
5146
	 *  @param	User		$userused		Object user
5147
	 *  @return int                 		-1=error, O=did nothing, 1=OK
5148
	 *  @see setValueFrom, insertExtraFields
5149
	 */
5150
	function updateExtraField($key, $trigger=null, $userused=null)
5151
	{
5152
		global $conf,$langs,$user;
5153
5154
		if (empty($userused)) $userused=$user;
5155
5156
		$error=0;
5157
5158
		if (!empty(Globals::$conf->global->MAIN_EXTRAFIELDS_DISABLED))
5159
            return 0; // For avoid conflicts if trigger used
5160
5161
        if (! empty($this->array_options) && isset($this->array_options["options_".$key]))
5162
		{
5163
			// Check parameters
5164
			$langs->load('admin');
5165
			require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
5166
			$extrafields = new AlExtraFields($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
5167
            $target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element);
5168
5169
			$value=$this->array_options["options_".$key];
5170
5171
			$attributeType     = $extrafields->attributes[$this->table_element]['type'][$key];
5172
			$attributeLabel    = $extrafields->attributes[$this->table_element]['label'][$key];
5173
			$attributeParam    = $extrafields->attributes[$this->table_element]['param'][$key];
5174
			$attributeRequired = $extrafields->attributes[$this->table_element]['required'][$key];
5175
5176
			//dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
5177
			//dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
5178
5179
			switch ($attributeType)
5180
			{
5181
				case 'int':
5182
					if (!is_numeric($value) && $value!='')
5183
					{
5184
						$this->errors[]=$langs->trans("ExtraFieldHasWrongValue",$attributeLabel);
5185
						return -1;
5186
					}
5187
					elseif ($value=='')
5188
					{
5189
						$this->array_options["options_".$key] = null;
5190
					}
5191
					break;
5192
				case 'double':
5193
					$value = price2num($value);
5194
					if (!is_numeric($value) && $value!='')
5195
					{
5196
						dol_syslog($langs->trans("ExtraFieldHasWrongValue")." sur ".$attributeLabel."(".$value."is not '".$attributeType."')", LOG_DEBUG);
5197
						$this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
5198
						return -1;
5199
					}
5200
					elseif ($value=='')
5201
					{
5202
						$this->array_options["options_".$key] = null;
5203
					}
5204
					//dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
5205
					$this->array_options["options_".$key] = $value;
5206
					break;
5207
			 	/*case 'select':	// Not required, we chosed value='0' for undefined values
5208
             		if ($value=='-1')
5209
             		{
5210
             			$this->array_options[$key] = null;
5211
             		}
5212
             		break;*/
5213
				case 'price':
5214
					$this->array_options["options_".$key] = price2num($this->array_options["options_".$key]);
5215
					break;
5216
				case 'date':
5217
					$this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
5218
					break;
5219
				case 'datetime':
5220
					$this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]);
5221
					break;
5222
				case 'link':
5223
					$param_list=array_keys($attributeParam['options']);
5224
					// 0 : ObjectName
5225
					// 1 : classPath
5226
					$InfoFieldList = explode(":", $param_list[0]);
5227
					dol_include_once($InfoFieldList[1]);
5228
					if ($value)
5229
					{
5230
						$object = new $InfoFieldList[0]($this->db);
5231
						$object->fetch(0,$value);
5232
						$this->array_options["options_".$key]=$object->id;
5233
					}
5234
					break;
5235
			}
5236
5237
			$this->db->begin();
5238
			$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element."_extrafields SET ".$key."='".$this->db->escape($this->array_options["options_".$key])."'";
5239
			$sql .= " WHERE fk_object = ".$this->id;
5240
			$resql = $this->db->query($sql);
5241
			if (! $resql)
5242
			{
5243
				$error++;
5244
				$this->error=$this->db->lasterror();
5245
			}
5246
5247
			if (! $error && $trigger)
5248
			{
5249
				// Call trigger
5250
				$this->context=array('extrafieldupdate'=>1);
5251
				$result=$this->call_trigger($trigger, $userused);
5252
				if ($result < 0) $error++;
5253
				// End call trigger
5254
			}
5255
5256
			if ($error)
5257
			{
5258
				dol_syslog(get_class($this) . "::".__METHOD__ . $this->error, LOG_ERR);
5259
				$this->db->rollback();
5260
				return -1;
5261
			}
5262
			else
5263
			{
5264
				$this->db->commit();
5265
				return 1;
5266
			}
5267
		}
5268
		else return 0;
5269
	}
5270
5271
5272
	/**
5273
	 * Return HTML string to put an input field into a page
5274
	 * Code very similar with showInputField of extra fields
5275
	 *
5276
	 * @param  array   		$val	       Array of properties for field to show
5277
	 * @param  string  		$key           Key of attribute
5278
	 * @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)
5279
	 * @param  string  		$moreparam     To add more parameters on html input tag
5280
	 * @param  string  		$keysuffix     Prefix string to add into name and id of field (can be used to avoid duplicate names)
5281
	 * @param  string  		$keyprefix     Suffix string to add into name and id of field (can be used to avoid duplicate names)
5282
	 * @param  string|int		$morecss       Value for css to define style/length of field. May also be a numeric.
5283
	 * @return string
5284
	 */
5285
	function showInputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $morecss=0)
5286
	{
5287
		global $conf,$langs,$form;
5288
5289
		if (! is_object($form))
5290
		{
5291
			require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5292
			$form=new Form($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
The type Alixar\Base\Form was not found. Did you mean Form? If so, make sure to prefix the type with \.
Loading history...
5293
		}
5294
5295
		$val=$this->fields[$key];
5296
5297
		$out='';
5298
        $type='';
5299
        $param = array();
5300
        $param['options']=array();
5301
        $size =$this->fields[$key]['size'];
5302
        // Because we work on extrafields
5303
        if(preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)){
5304
            $param['options']=array($reg[1].':'.$reg[2]=>'N');
5305
            $type ='link';
5306
        } elseif(preg_match('/^link:(.*):(.*)/i', $val['type'], $reg)) {
5307
            $param['options']=array($reg[1].':'.$reg[2]=>'N');
5308
            $type ='link';
5309
        } elseif(preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
5310
            $param['options']=array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4]=>'N');
5311
            $type ='sellist';
5312
        } elseif(preg_match('/varchar\((\d+)\)/', $val['type'],$reg)) {
5313
            $param['options']=array();
5314
            $type ='varchar';
5315
            $size=$reg[1];
5316
        } elseif(preg_match('/varchar/', $val['type'])) {
5317
            $param['options']=array();
5318
            $type ='varchar';
5319
        } elseif(is_array($this->fields[$key]['arrayofkeyval'])) {
5320
            $param['options']=$this->fields[$key]['arrayofkeyval'];
5321
            $type ='select';
5322
        } else {
5323
            $param['options']=array();
5324
            $type =$this->fields[$key]['type'];
5325
        }
5326
5327
		$label=$this->fields[$key]['label'];
5328
		//$elementtype=$this->fields[$key]['elementtype'];	// Seems not used
5329
		$default=$this->fields[$key]['default'];
5330
		$computed=$this->fields[$key]['computed'];
5331
		$unique=$this->fields[$key]['unique'];
5332
		$required=$this->fields[$key]['required'];
5333
5334
		$langfile=$this->fields[$key]['langfile'];
5335
		$list=$this->fields[$key]['list'];
5336
		$hidden=abs($this->fields[$key]['visible'])!=1?1:0;
5337
5338
		$objectid = $this->id;
5339
5340
5341
		if ($computed)
5342
		{
5343
			if (! preg_match('/^search_/', $keyprefix)) return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
5344
			else return '';
5345
		}
5346
5347
5348
		// Use in priority showsize from parameters, then $val['css'] then autodefine
5349
		if (empty($morecss) && ! empty($val['css']))
5350
		{
5351
			$showsize = $val['css'];
5352
		}
5353
		if (empty($morecss))
5354
		{
5355
			if ($type == 'date')
5356
			{
5357
				$morecss = 'minwidth100imp';
5358
			}
5359
			elseif ($type == 'datetime')
5360
			{
5361
				$morecss = 'minwidth200imp';
5362
			}
5363
			elseif (in_array($type,array('int','integer','price')) || preg_match('/^double(\([0-9],[0-9]\)){0,1}/',$type))
5364
			{
5365
				$morecss = 'maxwidth75';
5366
                        }elseif ($type == 'url')
5367
			{
5368
				$morecss='minwidth400';
5369
			}
5370
			elseif ($type == 'boolean')
5371
			{
5372
				$morecss='';
5373
			}
5374
			else
5375
			{
5376
				if (round($size) < 12)
5377
				{
5378
					$morecss = 'minwidth100';
5379
				}
5380
				else if (round($size) <= 48)
5381
				{
5382
					$morecss = 'minwidth200';
5383
				}
5384
				else
5385
				{
5386
					$morecss = 'minwidth400';
5387
				}
5388
			}
5389
		}
5390
5391
		if (in_array($type,array('date','datetime')))
5392
		{
5393
			$tmp=explode(',',$size);
5394
			$newsize=$tmp[0];
5395
5396
			$showtime = in_array($type,array('datetime')) ? 1 : 0;
5397
5398
			// Do not show current date when field not required (see selectDate() method)
5399
			if (!$required && $value == '') $value = '-1';
5400
5401
			// TODO Must also support $moreparam
5402
			$out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
5403
		}
5404
		elseif (in_array($type,array('int','integer')))
5405
		{
5406
			$tmp=explode(',',$size);
5407
			$newsize=$tmp[0];
5408
			$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:'').'>';
5409
		}
5410
		elseif (preg_match('/varchar/', $type))
5411
		{
5412
			$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:'').'>';
5413
		}
5414
		elseif (in_array($type, array('mail', 'phone', 'url')))
5415
		{
5416
			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5417
		}
5418
		elseif ($type == 'text')
5419
		{
5420
			if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
5421
			{
5422
				require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
5423
				$doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,false,ROWS_5,'90%');
5424
				$out=$doleditor->Create(1);
5425
			}
5426
			else
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
		}
5431
		elseif ($type == 'html')
5432
		{
5433
			if (! preg_match('/search_/', $keyprefix))		// If keyprefix is search_ or search_options_, we must just use a simple text field
5434
			{
5435
				require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
5436
				$doleditor = new DolEditor($keyprefix . $key . $keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, !empty(Globals::$conf->fckeditor->enabled) && Globals::$conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_5, '90%');
5437
                $out=$doleditor->Create(1);
5438
			}
5439
			else
5440
			{
5441
				$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam?$moreparam:'').'>';
5442
			}
5443
		}
5444
		elseif ($type == 'boolean')
5445
		{
5446
			$checked='';
5447
			if (!empty($value)) {
5448
				$checked=' checked value="1" ';
5449
			} else {
5450
				$checked=' value="1" ';
5451
			}
5452
			$out='<input type="checkbox" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam?$moreparam:'').'>';
5453
		}
5454
		elseif ($type == 'price')
5455
		{
5456
			if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
5457
				$value=price($value);
5458
			}
5459
			$out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . $value . '" ' . ($moreparam ? $moreparam : '') . '> ' . $langs->getCurrencySymbol(Globals::$conf->currency);
5460
        }
5461
		elseif (preg_match('/^double(\([0-9],[0-9]\)){0,1}/',$type))
5462
		{
5463
			if (!empty($value)) {		// $value in memory is a php numeric, we format it into user number format.
5464
				$value=price($value);
5465
			}
5466
			$out='<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> ';
5467
		}
5468
		elseif ($type == 'select')
5469
		{
5470
			$out = '';
5471
			if (!empty(Globals::$conf->use_javascript_ajax) && !empty(Globals::$conf->global->MAIN_EXTRAFIELDS_USE_SELECT2)) {
5472
				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5473
				$out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
5474
			}
5475
5476
			$out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
5477
                if((! isset($this->fields[$key]['default'])) ||($this->fields[$key]['notnull']!=1))$out.='<option value="0">&nbsp;</option>';
5478
			foreach ($param['options'] as $key => $val)
5479
			{
5480
				if ((string) $key == '') continue;
5481
				list($val, $parent) = explode('|', $val);
5482
				$out.='<option value="'.$key.'"';
5483
				$out.= (((string) $value == (string) $key)?' selected':'');
5484
				$out.= (!empty($parent)?' parent="'.$parent.'"':'');
5485
				$out.='>'.$val.'</option>';
5486
			}
5487
			$out.='</select>';
5488
		}
5489
		elseif ($type == 'sellist')
5490
		{
5491
			$out = '';
5492
			if (!empty(Globals::$conf->use_javascript_ajax) && !empty(Globals::$conf->global->MAIN_EXTRAFIELDS_USE_SELECT2)) {
5493
				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5494
				$out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
5495
			}
5496
5497
			$out.='<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'').'>';
5498
			if (is_array($param['options']))
5499
			{
5500
				$param_list=array_keys($param['options']);
5501
				$InfoFieldList = explode(":", $param_list[0]);
5502
				$parentName='';
5503
				$parentField='';
5504
				// 0 : tableName
5505
				// 1 : label field name
5506
				// 2 : key fields name (if differ of rowid)
5507
				// 3 : key field parent (for dependent lists)
5508
				// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5509
				$keyList=(empty($InfoFieldList[2])?'rowid':$InfoFieldList[2].' as rowid');
5510
5511
5512
				if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4]))
5513
				{
5514
					if (strpos($InfoFieldList[4], 'extra.') !== false)
5515
					{
5516
						$keyList='main.'.$InfoFieldList[2].' as rowid';
5517
					} else {
5518
						$keyList=$InfoFieldList[2].' as rowid';
5519
					}
5520
				}
5521
				if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3]))
5522
				{
5523
					list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
5524
					$keyList.= ', '.$parentField;
5525
				}
5526
5527
				$fields_label = explode('|',$InfoFieldList[1]);
5528
				if (is_array($fields_label))
5529
				{
5530
					$keyList .=', ';
5531
					$keyList .= implode(', ', $fields_label);
5532
				}
5533
5534
				$sqlwhere='';
5535
				$sql = 'SELECT '.$keyList;
5536
				$sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
5537
				if (!empty($InfoFieldList[4]))
5538
				{
5539
					// can use SELECT request
5540
					if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5541
						$InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5542
					}
5543
5544
					// current object id can be use into filter
5545
					if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5546
						$InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5547
					} else {
5548
						$InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5549
					}
5550
					//We have to join on extrafield table
5551
					if (strpos($InfoFieldList[4], 'extra')!==false)
5552
					{
5553
						$sql.= ' as main, '.MAIN_DB_PREFIX .$InfoFieldList[0].'_extrafields as extra';
5554
						$sqlwhere.= ' WHERE extra.fk_object=main.'.$InfoFieldList[2]. ' AND '.$InfoFieldList[4];
5555
					}
5556
					else
5557
					{
5558
						$sqlwhere.= ' WHERE '.$InfoFieldList[4];
5559
					}
5560
				}
5561
				else
5562
				{
5563
					$sqlwhere.= ' WHERE 1=1';
5564
				}
5565
				// Some tables may have field, some other not. For the moment we disable it.
5566
				if (in_array($InfoFieldList[0],array('tablewithentity')))
5567
				{
5568
					$sqlwhere .= ' AND entity = ' . Globals::$conf->entity;
5569
                }
5570
				$sql.=$sqlwhere;
5571
				//print $sql;
5572
5573
				$sql .= ' ORDER BY ' . implode(', ', $fields_label);
5574
5575
				dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
5576
				$resql = $this->db->query($sql);
5577
				if ($resql)
5578
				{
5579
					$out.='<option value="0">&nbsp;</option>';
5580
					$num = $this->db->num_rows($resql);
5581
					$i = 0;
5582
					while ($i < $num)
5583
					{
5584
						$labeltoshow='';
5585
						$obj = $this->db->fetch_object($resql);
5586
5587
						// Several field into label (eq table:code|libelle:rowid)
5588
						$notrans = false;
5589
						$fields_label = explode('|',$InfoFieldList[1]);
5590
						if (is_array($fields_label))
5591
						{
5592
							$notrans = true;
5593
							foreach ($fields_label as $field_toshow)
5594
							{
5595
								$labeltoshow.= $obj->$field_toshow.' ';
5596
							}
5597
						}
5598
						else
5599
						{
5600
							$labeltoshow=$obj->{$InfoFieldList[1]};
5601
						}
5602
						$labeltoshow=dol_trunc($labeltoshow,45);
5603
5604
						if ($value == $obj->rowid)
5605
						{
5606
							foreach ($fields_label as $field_toshow)
5607
							{
5608
								$translabel=$langs->trans($obj->$field_toshow);
5609
								if ($translabel!=$obj->$field_toshow) {
5610
									$labeltoshow=dol_trunc($translabel,18).' ';
5611
								}else {
5612
									$labeltoshow=dol_trunc($obj->$field_toshow,18).' ';
5613
								}
5614
							}
5615
							$out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5616
						}
5617
						else
5618
						{
5619
							if (! $notrans)
5620
							{
5621
								$translabel=$langs->trans($obj->{$InfoFieldList[1]});
5622
								if ($translabel!=$obj->{$InfoFieldList[1]}) {
5623
									$labeltoshow=dol_trunc($translabel,18);
5624
								}
5625
								else {
5626
									$labeltoshow=dol_trunc($obj->{$InfoFieldList[1]},18);
5627
								}
5628
							}
5629
							if (empty($labeltoshow)) $labeltoshow='(not defined)';
5630
							if ($value==$obj->rowid)
5631
							{
5632
								$out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
5633
							}
5634
5635
							if (!empty($InfoFieldList[3]) && $parentField)
5636
							{
5637
								$parent = $parentName.':'.$obj->{$parentField};
5638
							}
5639
5640
							$out.='<option value="'.$obj->rowid.'"';
5641
							$out.= ($value==$obj->rowid?' selected':'');
5642
							$out.= (!empty($parent)?' parent="'.$parent.'"':'');
5643
							$out.='>'.$labeltoshow.'</option>';
5644
						}
5645
5646
						$i++;
5647
					}
5648
					$this->db->free($resql);
5649
				}
5650
				else {
5651
					print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
5652
				}
5653
			}
5654
			$out.='</select>';
5655
		}
5656
		elseif ($type == 'checkbox')
5657
		{
5658
			$value_arr=explode(',',$value);
5659
			$out=$form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options'])?null:$param['options']), $value_arr, '', 0, '', 0, '100%');
5660
		}
5661
		elseif ($type == 'radio')
5662
		{
5663
			$out='';
5664
			foreach ($param['options'] as $keyopt => $val)
5665
			{
5666
				$out.='<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam?$moreparam:'');
5667
				$out.=' value="'.$keyopt.'"';
5668
				$out.=' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
5669
				$out.= ($value==$keyopt?'checked':'');
5670
				$out.='/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$val.'</label><br>';
5671
			}
5672
		}
5673
		elseif ($type == 'chkbxlst')
5674
		{
5675
			if (is_array($value)) {
5676
				$value_arr = $value;
5677
			}
5678
			else {
5679
				$value_arr = explode(',', $value);
5680
			}
5681
5682
			if (is_array($param['options'])) {
5683
				$param_list = array_keys($param['options']);
5684
				$InfoFieldList = explode(":", $param_list[0]);
5685
				$parentName='';
5686
				$parentField='';
5687
				// 0 : tableName
5688
				// 1 : label field name
5689
				// 2 : key fields name (if differ of rowid)
5690
				// 3 : key field parent (for dependent lists)
5691
				// 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
5692
				$keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
5693
5694
				if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3])) {
5695
					list ( $parentName, $parentField ) = explode('|', $InfoFieldList[3]);
5696
					$keyList .= ', ' . $parentField;
5697
				}
5698
				if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4])) {
5699
					if (strpos($InfoFieldList[4], 'extra.') !== false) {
5700
						$keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
5701
					} else {
5702
						$keyList = $InfoFieldList[2] . ' as rowid';
5703
					}
5704
				}
5705
5706
				$fields_label = explode('|', $InfoFieldList[1]);
5707
				if (is_array($fields_label)) {
5708
					$keyList .= ', ';
5709
					$keyList .= implode(', ', $fields_label);
5710
				}
5711
5712
				$sqlwhere = '';
5713
				$sql = 'SELECT ' . $keyList;
5714
				$sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
5715
				if (! empty($InfoFieldList[4])) {
5716
5717
					// can use SELECT request
5718
					if (strpos($InfoFieldList[4], '$SEL$')!==false) {
5719
						$InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
5720
					}
5721
5722
					// current object id can be use into filter
5723
					if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
5724
						$InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
5725
					} else {
5726
						$InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
5727
					}
5728
5729
					// We have to join on extrafield table
5730
					if (strpos($InfoFieldList[4], 'extra') !== false) {
5731
						$sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
5732
						$sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
5733
					} else {
5734
						$sqlwhere .= ' WHERE ' . $InfoFieldList[4];
5735
					}
5736
				} else {
5737
					$sqlwhere .= ' WHERE 1=1';
5738
				}
5739
				// Some tables may have field, some other not. For the moment we disable it.
5740
				if (in_array($InfoFieldList[0], array ('tablewithentity')))
5741
				{
5742
					$sqlwhere .= ' AND entity = ' . Globals::$conf->entity;
5743
                }
5744
				// $sql.=preg_replace('/^ AND /','',$sqlwhere);
5745
				// print $sql;
5746
5747
				$sql .= $sqlwhere;
5748
				dol_syslog(get_class($this) . '::showInputField type=chkbxlst',LOG_DEBUG);
5749
				$resql = $this->db->query($sql);
5750
				if ($resql) {
5751
					$num = $this->db->num_rows($resql);
5752
					$i = 0;
5753
5754
					$data=array();
5755
5756
					while ( $i < $num ) {
5757
						$labeltoshow = '';
5758
						$obj = $this->db->fetch_object($resql);
5759
5760
						$notrans = false;
5761
						// Several field into label (eq table:code|libelle:rowid)
5762
						$fields_label = explode('|', $InfoFieldList[1]);
5763
						if (is_array($fields_label)) {
5764
							$notrans = true;
5765
							foreach ( $fields_label as $field_toshow ) {
5766
								$labeltoshow .= $obj->$field_toshow . ' ';
5767
							}
5768
						} else {
5769
							$labeltoshow = $obj->{$InfoFieldList[1]};
5770
						}
5771
						$labeltoshow = dol_trunc($labeltoshow, 45);
5772
5773
						if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5774
							foreach ( $fields_label as $field_toshow ) {
5775
								$translabel = $langs->trans($obj->$field_toshow);
5776
								if ($translabel != $obj->$field_toshow) {
5777
									$labeltoshow = dol_trunc($translabel, 18) . ' ';
5778
								} else {
5779
									$labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
5780
								}
5781
							}
5782
5783
							$data[$obj->rowid]=$labeltoshow;
5784
						} else {
5785
							if (! $notrans) {
5786
								$translabel = $langs->trans($obj->{$InfoFieldList[1]});
5787
								if ($translabel != $obj->{$InfoFieldList[1]}) {
5788
									$labeltoshow = dol_trunc($translabel, 18);
5789
								} else {
5790
									$labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
5791
								}
5792
							}
5793
							if (empty($labeltoshow))
5794
								$labeltoshow = '(not defined)';
5795
5796
								if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5797
									$data[$obj->rowid]=$labeltoshow;
5798
								}
5799
5800
								if (! empty($InfoFieldList[3]) && $parentField) {
5801
									$parent = $parentName . ':' . $obj->{$parentField};
5802
								}
5803
5804
								$data[$obj->rowid]=$labeltoshow;
5805
						}
5806
5807
						$i ++;
5808
					}
5809
					$this->db->free($resql);
5810
5811
					$out=$form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
5812
				} else {
5813
					print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
5814
				}
5815
			}
5816
		}
5817
		elseif ($type == 'link')
5818
		{
5819
			$param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
5820
			$showempty=(($required && $default != '')?0:1);
5821
			$out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty);
5822
			if (Globals::$conf->global->MAIN_FEATURES_LEVEL >= 2) {
5823
            			list($class,$classfile)=explode(':',$param_list[0]);
5824
            			if (file_exists(dol_buildpath(dirname(dirname($classfile)).'/card.php'))) $url_path=dol_buildpath(dirname(dirname($classfile)).'/card.php',1);
5825
            			else $url_path=dol_buildpath(dirname(dirname($classfile)).'/'.$class.'_card.php',1);
5826
            			$out.='<a class="butActionNew" href="'.$url_path.'?action=create&backtopage='.$_SERVER['PHP_SELF'].'"><span class="fa fa-plus-circle valignmiddle"></span></a>';
5827
            			// TODO Add Javascript code to add input fields contents to new elements urls
5828
			}
5829
		}
5830
		elseif ($type == 'password')
5831
		{
5832
			// If prefix is 'search_', field is used as a filter, we use a common text field.
5833
			$out='<input type="'.($keyprefix=='search_'?'text':'password').'" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'>';
5834
		}
5835
		elseif ($type == 'array')
5836
		{
5837
			$newval = $val;
5838
			$newval['type'] = 'varchar(256)';
5839
5840
			$out='';
5841
5842
			$inputs = array();
5843
			if(! empty($value)) {
5844
				foreach($value as $option) {
5845
					$out.= '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
5846
					$out.= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', $option, $moreparam, '', '', $showsize).'<br></span>';
5847
				}
5848
			}
5849
5850
			$out.= '<a id="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_add" href="javascript:;"><span class="fa fa-plus-circle valignmiddle"></span></a>';
5851
5852
			$newInput = '<span><a class="'.dol_escape_htmltag($keyprefix.$key.$keysuffix).'_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
5853
			$newInput.= $this->showInputField($newval, $keyprefix.$key.$keysuffix.'[]', '', $moreparam, '', '', $showsize).'<br></span>';
5854
5855
			if (!empty(Globals::$conf->use_javascript_ajax)) {
5856
                $out.= '
5857
					<script type="text/javascript">
5858
					$(document).ready(function() {
5859
						$("a#'.dol_escape_js($keyprefix.$key.$keysuffix).'_add").click(function() {
5860
							$("'.dol_escape_js($newInput).'").insertBefore(this);
5861
						});
5862
5863
						$(document).on("click", "a.'.dol_escape_js($keyprefix.$key.$keysuffix).'_del", function() {
5864
							$(this).parent().remove();
5865
						});
5866
					});
5867
					</script>';
5868
			}
5869
		}
5870
		if (!empty($hidden)) {
5871
			$out='<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
5872
		}
5873
		/* Add comments
5874
		 if ($type == 'date') $out.=' (YYYY-MM-DD)';
5875
		 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
5876
		 */
5877
		return $out;
5878
	}
5879
5880
	/**
5881
	 * Return HTML string to show a field into a page
5882
	 * Code very similar with showOutputField of extra fields
5883
	 *
5884
	 * @param  array   $val		       Array of properties of field to show
5885
	 * @param  string  $key            Key of attribute
5886
	 * @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)
5887
	 * @param  string  $moreparam      To add more parametes on html input tag
5888
	 * @param  string  $keysuffix      Prefix string to add into name and id of field (can be used to avoid duplicate names)
5889
	 * @param  string  $keyprefix      Suffix string to add into name and id of field (can be used to avoid duplicate names)
5890
	 * @param  mixed   $showsize       Value for css to define size. May also be a numeric.
5891
	 * @return string
5892
	 */
5893
	function showOutputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $showsize=0)
5894
	{
5895
		global $conf,$langs,$form;
5896
5897
		if (! is_object($form))
5898
		{
5899
			require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
5900
			$form=new Form($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
5901
		}
5902
5903
		$objectid = $this->id;
5904
		$label = $val['label'];
5905
		$type  = $val['type'];
5906
		$size  = $val['css'];
5907
5908
		// Convert var to be able to share same code than showOutputField of extrafields
5909
		if (preg_match('/varchar\((\d+)\)/', $type, $reg))
5910
		{
5911
			$type = 'varchar';		// convert varchar(xx) int varchar
5912
			$size = $reg[1];
5913
		}
5914
		elseif (preg_match('/varchar/', $type)) $type = 'varchar';		// convert varchar(xx) int varchar
5915
		if (is_array($val['arrayofkeyval'])) $type='select';
5916
		if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) $type='link';
5917
5918
		$default=$val['default'];
5919
		$computed=$val['computed'];
5920
		$unique=$val['unique'];
5921
		$required=$val['required'];
5922
		$param=$val['param'];
5923
		if (is_array($val['arrayofkeyval'])) $param['options'] = $val['arrayofkeyval'];
5924
		if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg))
5925
		{
5926
			$type='link';
5927
			$param['options']=array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
5928
		}
5929
		$langfile=$val['langfile'];
5930
		$list=$val['list'];
5931
		$help=$val['help'];
5932
		$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)
5933
5934
		if ($hidden) return '';
5935
5936
		// If field is a computed field, value must become result of compute
5937
		if ($computed)
5938
		{
5939
			// Make the eval of compute string
5940
			//var_dump($computed);
5941
			$value = dol_eval($computed, 1, 0);
5942
		}
5943
5944
		if (empty($showsize))
5945
		{
5946
			if ($type == 'date')
5947
			{
5948
				//$showsize=10;
5949
				$showsize = 'minwidth100imp';
5950
			}
5951
			elseif ($type == 'datetime')
5952
			{
5953
				//$showsize=19;
5954
				$showsize = 'minwidth200imp';
5955
			}
5956
			elseif (in_array($type,array('int','double','price')))
5957
			{
5958
				//$showsize=10;
5959
				$showsize = 'maxwidth75';
5960
			}
5961
			elseif ($type == 'url')
5962
			{
5963
				$showsize='minwidth400';
5964
			}
5965
			elseif ($type == 'boolean')
5966
			{
5967
				$showsize='';
5968
			}
5969
			else
5970
			{
5971
				if (round($size) < 12)
5972
				{
5973
					$showsize = 'minwidth100';
5974
				}
5975
				else if (round($size) <= 48)
5976
				{
5977
					$showsize = 'minwidth200';
5978
				}
5979
				else
5980
				{
5981
					//$showsize=48;
5982
					$showsize = 'minwidth400';
5983
				}
5984
			}
5985
		}
5986
5987
		// Format output value differently according to properties of field
5988
		if ($key == 'ref' && method_exists($this, 'getNomUrl')) $value=$this->getNomUrl(1, '', 0, '', 1);
5989
		elseif ($key == 'status' && method_exists($this, 'getLibStatut')) $value=$this->getLibStatut(3);
5990
		elseif ($type == 'date')
5991
		{
5992
			if(! empty($value)) {
5993
				$value=dol_print_date($value,'day');
5994
			} else {
5995
				$value='';
5996
			}
5997
		}
5998
		elseif ($type == 'datetime')
5999
		{
6000
			if(! empty($value)) {
6001
				$value=dol_print_date($value,'dayhour');
6002
			} else {
6003
				$value='';
6004
			}
6005
		}
6006
		elseif ($type == 'double')
6007
		{
6008
			if (!empty($value)) {
6009
				$value=price($value);
6010
			}
6011
		}
6012
		elseif ($type == 'boolean')
6013
		{
6014
			$checked='';
6015
			if (!empty($value)) {
6016
				$checked=' checked ';
6017
			}
6018
			$value='<input type="checkbox" '.$checked.' '.($moreparam?$moreparam:'').' readonly disabled>';
6019
		}
6020
		elseif ($type == 'mail')
6021
		{
6022
			$value=dol_print_email($value,0,0,0,64,1,1);
6023
		}
6024
		elseif ($type == 'url')
6025
		{
6026
			$value=dol_print_url($value,'_blank',32,1);
6027
		}
6028
		elseif ($type == 'phone')
6029
		{
6030
			$value=dol_print_phone($value, '', 0, 0, '', '&nbsp;', 1);
6031
		}
6032
		elseif ($type == 'price')
6033
		{
6034
			$value = price($value, 0, $langs, 0, 0, -1, Globals::$conf->currency);
6035
        }
6036
		elseif ($type == 'select')
6037
		{
6038
			$value=$param['options'][$value];
6039
		}
6040
		elseif ($type == 'sellist')
6041
		{
6042
			$param_list=array_keys($param['options']);
6043
			$InfoFieldList = explode(":", $param_list[0]);
6044
6045
			$selectkey="rowid";
6046
			$keyList='rowid';
6047
6048
			if (count($InfoFieldList)>=3)
6049
			{
6050
				$selectkey = $InfoFieldList[2];
6051
				$keyList=$InfoFieldList[2].' as rowid';
6052
			}
6053
6054
			$fields_label = explode('|',$InfoFieldList[1]);
6055
			if(is_array($fields_label)) {
6056
				$keyList .=', ';
6057
				$keyList .= implode(', ', $fields_label);
6058
			}
6059
6060
			$sql = 'SELECT '.$keyList;
6061
			$sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
6062
			if (strpos($InfoFieldList[4], 'extra')!==false)
6063
			{
6064
				$sql.= ' as main';
6065
			}
6066
			if ($selectkey=='rowid' && empty($value)) {
6067
				$sql.= " WHERE ".$selectkey."=0";
6068
			} elseif ($selectkey=='rowid') {
6069
				$sql.= " WHERE ".$selectkey."=".$this->db->escape($value);
6070
			}else {
6071
				$sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
6072
			}
6073
6074
			//$sql.= ' AND entity = '.Globals::$conf->entity;
6075
6076
            dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
6077
			$resql = $this->db->query($sql);
6078
			if ($resql)
6079
			{
6080
				$value='';	// value was used, so now we reste it to use it to build final output
6081
6082
				$obj = $this->db->fetch_object($resql);
6083
6084
				// Several field into label (eq table:code|libelle:rowid)
6085
				$fields_label = explode('|',$InfoFieldList[1]);
6086
6087
				if(is_array($fields_label) && count($fields_label)>1)
6088
				{
6089
					foreach ($fields_label as $field_toshow)
6090
					{
6091
						$translabel='';
6092
						if (!empty($obj->$field_toshow)) {
6093
							$translabel=$langs->trans($obj->$field_toshow);
6094
						}
6095
						if ($translabel!=$field_toshow) {
6096
							$value.=dol_trunc($translabel,18).' ';
6097
						}else {
6098
							$value.=$obj->$field_toshow.' ';
6099
						}
6100
					}
6101
				}
6102
				else
6103
				{
6104
					$translabel='';
6105
					if (!empty($obj->{$InfoFieldList[1]})) {
6106
						$translabel=$langs->trans($obj->{$InfoFieldList[1]});
6107
					}
6108
					if ($translabel!=$obj->{$InfoFieldList[1]}) {
6109
						$value=dol_trunc($translabel,18);
6110
					}else {
6111
						$value=$obj->{$InfoFieldList[1]};
6112
					}
6113
				}
6114
			}
6115
			else dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
6116
		}
6117
		elseif ($type == 'radio')
6118
		{
6119
			$value=$param['options'][$value];
6120
		}
6121
		elseif ($type == 'checkbox')
6122
		{
6123
			$value_arr=explode(',',$value);
6124
			$value='';
6125
			if (is_array($value_arr) && count($value_arr)>0)
6126
			{
6127
				foreach ($value_arr as $keyval=>$valueval) {
6128
					$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$param['options'][$valueval].'</li>';
6129
				}
6130
				$value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6131
			}
6132
		}
6133
		elseif ($type == 'chkbxlst')
6134
		{
6135
			$value_arr = explode(',', $value);
6136
6137
			$param_list = array_keys($param['options']);
6138
			$InfoFieldList = explode(":", $param_list[0]);
6139
6140
			$selectkey = "rowid";
6141
			$keyList = 'rowid';
6142
6143
			if (count($InfoFieldList) >= 3) {
6144
				$selectkey = $InfoFieldList[2];
6145
				$keyList = $InfoFieldList[2] . ' as rowid';
6146
			}
6147
6148
			$fields_label = explode('|', $InfoFieldList[1]);
6149
			if (is_array($fields_label)) {
6150
				$keyList .= ', ';
6151
				$keyList .= implode(', ', $fields_label);
6152
			}
6153
6154
			$sql = 'SELECT ' . $keyList;
6155
			$sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
6156
			if (strpos($InfoFieldList[4], 'extra') !== false) {
6157
				$sql .= ' as main';
6158
			}
6159
			// $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
6160
			// $sql.= ' AND entity = '.Globals::$conf->entity;
6161
6162
            dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst',LOG_DEBUG);
6163
			$resql = $this->db->query($sql);
6164
			if ($resql) {
6165
				$value = ''; // value was used, so now we reste it to use it to build final output
6166
				$toprint=array();
6167
				while ( $obj = $this->db->fetch_object($resql) ) {
6168
6169
					// Several field into label (eq table:code|libelle:rowid)
6170
					$fields_label = explode('|', $InfoFieldList[1]);
6171
					if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
6172
						if (is_array($fields_label) && count($fields_label) > 1) {
6173
							foreach ( $fields_label as $field_toshow ) {
6174
								$translabel = '';
6175
								if (! empty($obj->$field_toshow)) {
6176
									$translabel = $langs->trans($obj->$field_toshow);
6177
								}
6178
								if ($translabel != $field_toshow) {
6179
									$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
6180
								} else {
6181
									$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->$field_toshow.'</li>';
6182
								}
6183
							}
6184
						} else {
6185
							$translabel = '';
6186
							if (! empty($obj->{$InfoFieldList[1]})) {
6187
								$translabel = $langs->trans($obj->{$InfoFieldList[1]});
6188
							}
6189
							if ($translabel != $obj->{$InfoFieldList[1]}) {
6190
								$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
6191
							} else {
6192
								$toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->{$InfoFieldList[1]}.'</li>';
6193
							}
6194
						}
6195
					}
6196
				}
6197
				$value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6198
			} else {
6199
				dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING);
6200
			}
6201
		}
6202
		elseif ($type == 'link')
6203
		{
6204
			$out='';
6205
6206
			// only if something to display (perf)
6207
			if ($value)
6208
			{
6209
				$param_list=array_keys($param['options']);				// $param_list='ObjectName:classPath'
6210
6211
				$InfoFieldList = explode(":", $param_list[0]);
6212
				$classname=$InfoFieldList[0];
6213
				$classpath=$InfoFieldList[1];
6214
				$getnomurlparam=(empty($InfoFieldList[2]) ? 3 : $InfoFieldList[2]);
6215
				if (! empty($classpath))
6216
				{
6217
					dol_include_once($InfoFieldList[1]);
6218
					if ($classname && class_exists($classname))
6219
					{
6220
						$object = new $classname($this->db);
6221
						$object->fetch($value);
6222
						$value=$object->getNomUrl($getnomurlparam);
6223
					}
6224
				}
6225
				else
6226
				{
6227
					dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6228
					return 'Error bad setup of extrafield';
6229
				}
6230
			}
6231
			else $value='';
6232
		}
6233
		elseif ($type == 'text' || $type == 'html')
6234
		{
6235
			$value=dol_htmlentitiesbr($value);
6236
		}
6237
		elseif ($type == 'password')
6238
		{
6239
			$value=preg_replace('/./i','*',$value);
6240
		}
6241
		elseif ($type == 'array')
6242
		{
6243
			$value = implode('<br>', $value);
6244
		}
6245
6246
		//print $type.'-'.$size;
6247
		$out=$value;
6248
6249
		return $out;
6250
	}
6251
6252
6253
	/**
6254
	 * Function to show lines of extrafields with output datas
6255
	 *
6256
	 * @param 	Extrafields $extrafields    Extrafield Object
0 ignored issues
show
The type Alixar\Base\Extrafields was not found. Did you mean Extrafields? If so, make sure to prefix the type with \.
Loading history...
6257
	 * @param 	string      $mode           Show output (view) or input (edit) for extrafield
6258
	 * @param 	array       $params         Optional parameters. Example: array('style'=>'class="oddeven"', 'colspan'=>$colspan)
6259
	 * @param 	string      $keysuffix      Suffix string to add after name and id of field (can be used to avoid duplicate names)
6260
	 * @param 	string      $keyprefix      Prefix string to add before name and id of field (can be used to avoid duplicate names)
6261
	 * @param	string		$onetrtd		All fields in same tr td
6262
	 * @return 	string
6263
	 */
6264
	function showOptionals($extrafields, $mode='view', $params=null, $keysuffix='', $keyprefix='', $onetrtd=0)
6265
	{
6266
		global $db, $conf, $langs, $action, $form;
6267
6268
		if (! is_object($form)) $form=new Form($db);
6269
6270
		$out = '';
6271
6272
		if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label']) > 0)
6273
		{
6274
			$out .= "\n";
6275
			$out .= '<!-- showOptionalsInput --> ';
6276
			$out .= "\n";
6277
6278
			$e = 0;
6279
			foreach($extrafields->attributes[$this->table_element]['label'] as $key=>$label)
6280
			{
6281
				// Show only the key field in params
6282
				if (is_array($params) && array_key_exists('onlykey',$params) && $key != $params['onlykey']) continue;
6283
6284
				$enabled = 1;
6285
				if ($enabled && isset($extrafields->attributes[$this->table_element]['list'][$key]))
6286
				{
6287
					$enabled = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1);
6288
				}
6289
6290
				$perms = 1;
6291
				if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key]))
6292
				{
6293
					$perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1);
6294
				}
6295
6296
				if (($mode == 'create' || $mode == 'edit') && abs($enabled) != 1 && abs($enabled) != 3) continue;	// <> -1 and <> 1 and <> 3 = not visible on forms, only on list
6297
				if (empty($perms)) continue;
6298
6299
				// Load language if required
6300
				if (! empty($extrafields->attributes[$this->table_element]['langfile'][$key])) $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
6301
6302
				$colspan='3';
6303
				if (is_array($params) && count($params)>0) {
6304
					if (array_key_exists('colspan',$params)) {
6305
						$colspan=$params['colspan'];
6306
					}
6307
				}
6308
6309
				switch($mode) {
6310
					case "view":
6311
						$value=$this->array_options["options_".$key.$keysuffix];
6312
						break;
6313
					case "edit":
6314
						$getposttemp = GETPOST($keyprefix.'options_'.$key.$keysuffix, 'none');				// GETPOST can get value from GET, POST or setup of default values.
6315
						// GETPOST("options_" . $key) can be 'abc' or array(0=>'abc')
6316
						if (is_array($getposttemp) || $getposttemp != '' || GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix))
6317
						{
6318
							if (is_array($getposttemp)) {
6319
								// $getposttemp is an array but following code expects a comma separated string
6320
								$value = implode(",", $getposttemp);
6321
							} else {
6322
								$value = $getposttemp;
6323
							}
6324
						} else {
6325
							$value = $this->array_options["options_" . $key];			// No GET, no POST, no default value, so we take value of object.
6326
						}
6327
						//var_dump($keyprefix.' - '.$key.' - '.$keysuffix.' - '.$keyprefix.'options_'.$key.$keysuffix.' - '.$this->array_options["options_".$key.$keysuffix].' - '.$getposttemp.' - '.$value);
6328
						break;
6329
				}
6330
6331
				if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate')
6332
				{
6333
					$out .= $extrafields->showSeparator($key, $this);
6334
				}
6335
				else
6336
				{
6337
					$csstyle='';
6338
					$class=(!empty($extrafields->attributes[$this->table_element]['hidden'][$key]) ? 'hideobject ' : '');
6339
					if (is_array($params) && count($params)>0) {
6340
						if (array_key_exists('style',$params)) {
6341
							$csstyle=$params['style'];
6342
						}
6343
					}
6344
6345
					// add html5 elements
6346
					$domData  = ' data-element="extrafield"';
6347
					$domData .= ' data-targetelement="'.$this->element.'"';
6348
					$domData .= ' data-targetid="'.$this->id.'"';
6349
6350
					$html_id = !empty($this->id) ? 'extrarow-'.$this->element.'_'.$key.'_'.$this->id : '';
6351
6352
					$out .= '<tr id="'.$html_id.'" '.$csstyle.' class="'.$class.$this->element.'_extras_'.$key.'" '.$domData.' >';
6353
6354
					if (!empty(Globals::$conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) {
6355
						if (!empty(Globals::$conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) {
6356
                            $colspan = '0';
6357
                        }
6358
                    }
6359
6360
					if ($action == 'selectlines') { $colspan++; }
6361
6362
					// Convert date into timestamp format (value in memory must be a timestamp)
6363
					if (in_array($extrafields->attributes[$this->table_element]['type'][$key],array('date','datetime')))
6364
					{
6365
						$datenotinstring = $this->array_options['options_' . $key];
6366
						if (! is_numeric($this->array_options['options_' . $key]))	// For backward compatibility
6367
						{
6368
							$datenotinstring = $this->db->jdate($datenotinstring);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
6369
						}
6370
						$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;
6371
					}
6372
					// Convert float submited string into real php numeric (value in memory must be a php numeric)
6373
					if (in_array($extrafields->attributes[$this->table_element]['type'][$key],array('price','double')))
6374
					{
6375
						$value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?price2num(GETPOST($keyprefix.'options_'.$key.$keysuffix, 'alpha', 3)):$this->array_options['options_'.$key];
6376
					}
6377
6378
					$labeltoshow = $langs->trans($label);
6379
6380
					$out .= '<td class="titlefield';
6381
					if (GETPOST('action','none') == 'create') $out.='create';
6382
					if ($mode != 'view' && ! empty($extrafields->attributes[$this->table_element]['required'][$key])) $out .= ' fieldrequired';
6383
					$out .= '">';
6384
					if (! empty($extrafields->attributes[$object->table_element]['help'][$key])) $out .= $form->textwithpicto($labeltoshow, $extrafields->attributes[$object->table_element]['help'][$key]);
6385
					else $out .= $labeltoshow;
6386
					$out .= '</td>';
6387
6388
					$html_id = !empty($this->id) ? $this->element.'_extras_'.$key.'_'.$this->id : '';
6389
					$out .='<td id="'.$html_id.'" class="'.$this->element.'_extras_'.$key.'" '.($colspan?' colspan="'.$colspan.'"':'').'>';
6390
6391
					switch($mode) {
6392
						case "view":
6393
							$out .= $extrafields->showOutputField($key, $value);
6394
							break;
6395
						case "edit":
6396
							$out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id);
6397
							break;
6398
					}
6399
6400
					$out .= '</td>';
6401
6402
					if (!empty(Globals::$conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && (($e % 2) == 1))
6403
                        $out .= '</tr>';
6404
                    else $out .= '</tr>';
6405
					$e++;
6406
				}
6407
			}
6408
			$out .= "\n";
6409
			// Add code to manage list depending on others
6410
			if (!empty(Globals::$conf->use_javascript_ajax)) {
6411
                $out .= '
6412
				<script type="text/javascript">
6413
				    jQuery(document).ready(function() {
6414
				    	function showOptions(child_list, parent_list)
6415
				    	{
6416
				    		var val = $("select[name=\"options_"+parent_list+"\"]").val();
6417
				    		var parentVal = parent_list + ":" + val;
6418
							if(val > 0) {
6419
					    		$("select[name=\""+child_list+"\"] option[parent]").hide();
6420
					    		$("select[name=\""+child_list+"\"] option[parent=\""+parentVal+"\"]").show();
6421
							} else {
6422
								$("select[name=\""+child_list+"\"] option").show();
6423
							}
6424
				    	}
6425
						function setListDependencies() {
6426
					    	jQuery("select option[parent]").parent().each(function() {
6427
					    		var child_list = $(this).attr("name");
6428
								var parent = $(this).find("option[parent]:first").attr("parent");
6429
								var infos = parent.split(":");
6430
								var parent_list = infos[0];
6431
								$("select[name=\""+parent_list+"\"]").change(function() {
6432
									showOptions(child_list, parent_list);
6433
								});
6434
					    	});
6435
						}
6436
6437
						setListDependencies();
6438
				    });
6439
				</script>'."\n";
6440
				$out .= '<!-- /showOptionalsInput --> '."\n";
6441
			}
6442
		}
6443
		return $out;
6444
	}
6445
6446
6447
	/**
6448
	 * Returns the rights used for this class
6449
	 * @return stdClass
6450
	 */
6451
	public function getRights()
6452
	{
6453
		global $user;
6454
6455
		$element = $this->element;
6456
		if ($element == 'facturerec') $element='facture';
6457
6458
		return $user->rights->{$element};
6459
	}
6460
6461
	/**
6462
	 * Function used to replace a thirdparty id with another one.
6463
	 * This function is meant to be called from replaceThirdparty with the appropiate tables
6464
	 * Column name fk_soc MUST be used to identify thirdparties
6465
	 *
6466
	 * @param  DoliDB 	   $db 			  Database handler
6467
	 * @param  int 		   $origin_id     Old thirdparty id (the thirdparty to delete)
6468
	 * @param  int 		   $dest_id       New thirdparty id (the thirdparty that will received element of the other)
6469
	 * @param  string[]    $tables        Tables that need to be changed
6470
	 * @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)
6471
	 * @return bool						  True if success, False if error
6472
	 */
6473
	public static function commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
6474
	{
6475
		foreach ($tables as $table)
6476
		{
6477
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_soc = '.$dest_id.' WHERE fk_soc = '.$origin_id;
6478
6479
			if (! $db->query($sql))
6480
			{
6481
				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.
6482
				//$this->errors = $db->lasterror();
6483
				return false;
6484
			}
6485
		}
6486
6487
		return true;
6488
	}
6489
6490
	/**
6491
	 * Get buy price to use for margin calculation. This function is called when buy price is unknown.
6492
	 *	 Set buy price = sell price if ForceBuyingPriceIfNull configured,
6493
	 *   else if calculation MARGIN_TYPE = 'costprice' and costprice is defined, use costprice as buyprice
6494
	 *	 else if calculation MARGIN_TYPE = 'pmp' and pmp is calculated, use pmp as buyprice
6495
	 *	 else set min buy price as buy price
6496
	 *
6497
	 * @param float		$unitPrice		 Product unit price
6498
	 * @param float		$discountPercent Line discount percent
6499
	 * @param int		$fk_product		 Product id
6500
	 * @return	float                    <0 if KO, buyprice if OK
6501
	 */
6502
	public function defineBuyPrice($unitPrice = 0.0, $discountPercent = 0.0, $fk_product = 0)
6503
	{
6504
		global $conf;
6505
6506
		$buyPrice = 0;
6507
6508
		if (($unitPrice > 0) && (isset(Globals::$conf->global->ForceBuyingPriceIfNull) && Globals::$conf->global->ForceBuyingPriceIfNull == 1)) { // In most cases, test here is false{
6509
			$buyPrice = $unitPrice * (1 - $discountPercent / 100);
6510
		}
6511
		else
6512
		{
6513
			// Get cost price for margin calculation
6514
			if (! empty($fk_product))
6515
			{
6516
				if (isset(Globals::$conf->global->MARGIN_TYPE) && Globals::$conf->global->MARGIN_TYPE == 'costprice') {
6517
					require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6518
					$product = new Product($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
6519
					$result = $product->fetch($fk_product);
6520
					if ($result <= 0)
6521
					{
6522
						$this->errors[] = 'ErrorProductIdDoesNotExists';
6523
						return -1;
6524
					}
6525
					if ($product->cost_price > 0)
6526
					{
6527
						$buyPrice = $product->cost_price;
6528
					}
6529
					else if ($product->pmp > 0)
6530
					{
6531
						$buyPrice = $product->pmp;
6532
					}
6533
				}
6534
				else if (isset(Globals::$conf->global->MARGIN_TYPE) && Globals::$conf->global->MARGIN_TYPE == 'pmp') {
6535
					require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6536
					$product = new Product($this->db);
6537
					$result = $product->fetch($fk_product);
6538
					if ($result <= 0)
6539
					{
6540
						$this->errors[] = 'ErrorProductIdDoesNotExists';
6541
						return -1;
6542
					}
6543
					if ($product->pmp > 0)
6544
					{
6545
						$buyPrice = $product->pmp;
6546
					}
6547
				}
6548
6549
				if (empty($buyPrice) && isset(Globals::$conf->global->MARGIN_TYPE) && in_array(Globals::$conf->global->MARGIN_TYPE, array('1', 'pmp', 'costprice'))) {
6550
					require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
6551
					$productFournisseur = new ProductFournisseur($this->db);
6552
					if (($result = $productFournisseur->find_min_price_product_fournisseur($fk_product)) > 0)
6553
					{
6554
						$buyPrice = $productFournisseur->fourn_unitprice;
6555
					}
6556
					else if ($result < 0)
6557
					{
6558
						$this->errors[] = $productFournisseur->error;
6559
						return -2;
6560
					}
6561
				}
6562
			}
6563
		}
6564
		return $buyPrice;
6565
	}
6566
6567
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
6568
	/**
6569
	 *  Show photos of an object (nbmax maximum), into several columns
6570
	 *
6571
	 *  @param		string	$modulepart		'product', 'ticket', ...
6572
	 *  @param      string	$sdir        	Directory to scan (full absolute path)
6573
	 *  @param      int		$size        	0=original size, 1='small' use thumbnail if possible
6574
	 *  @param      int		$nbmax       	Nombre maximum de photos (0=pas de max)
6575
	 *  @param      int		$nbbyrow     	Number of image per line or -1 to use div. Used only if size=1.
6576
	 * 	@param		int		$showfilename	1=Show filename
6577
	 * 	@param		int		$showaction		1=Show icon with action links (resize, delete)
6578
	 * 	@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.
6579
	 * 	@param		int		$maxWidth		Max width of original image when size='small'
6580
	 *  @param      int     $nolink         Do not add a href link to view enlarged imaged into a new tab
6581
	 *  @param      int     $notitle        Do not add title tag on image
6582
	 *  @param		int		$usesharelink	Use the public shared link of image (if not available, the 'nophoto' image will be shown instead)
6583
	 *  @return     string					Html code to show photo. Number of photos shown is saved in this->nbphoto
6584
	 */
6585
	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)
6586
	{
6587
        // phpcs:enable
6588
		global $conf,$user,$langs;
6589
6590
		include_once DOL_DOCUMENT_ROOT .'/core/lib/files.lib.php';
6591
		include_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php';
6592
6593
		$sortfield='position_name';
6594
		$sortorder='asc';
6595
6596
		$dir = $sdir . '/';
6597
		$pdir = '/';
6598
		if ($modulepart == 'ticket')
6599
		{
6600
			$dir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->track_id.'/';
0 ignored issues
show
Bug Best Practice introduced by
The property track_id does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
6601
			$pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->track_id.'/';
6602
		}
6603
		else
6604
		{
6605
			$dir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->ref.'/';
6606
			$pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart).$this->ref.'/';
6607
		}
6608
6609
		// For backward compatibility
6610
		if ($modulepart == 'product' && !empty(Globals::$conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) {
6611
			$dir = $sdir . '/'. get_exdir($this->id,2,0,0,$this,$modulepart) . $this->id ."/photos/";
6612
			$pdir = '/' . get_exdir($this->id,2,0,0,$this,$modulepart) . $this->id ."/photos/";
6613
		}
6614
6615
		// Defined relative dir to DOL_DATA_ROOT
6616
		$relativedir = '';
6617
		if ($dir)
6618
		{
6619
			$relativedir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $dir);
6620
			$relativedir = preg_replace('/^[\\/]/','',$relativedir);
6621
			$relativedir = preg_replace('/[\\/]$/','',$relativedir);
6622
		}
6623
6624
		$dirthumb = $dir.'thumbs/';
6625
		$pdirthumb = $pdir.'thumbs/';
6626
6627
		$return ='<!-- Photo -->'."\n";
6628
		$nbphoto=0;
6629
6630
		$filearray=dol_dir_list($dir,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
6631
6632
		/* if (! empty(Globals::$conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))    // For backward compatiblity, we scan also old dirs
6633
          {
6634
          $filearrayold=dol_dir_list($dirold,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
6635
          $filearray=array_merge($filearray, $filearrayold);
6636
          } */
6637
6638
		completeFileArrayWithDatabaseInfo($filearray, $relativedir);
6639
6640
		if (count($filearray))
6641
		{
6642
			if ($sortfield && $sortorder)
6643
			{
6644
				$filearray=dol_sort_array($filearray, $sortfield, $sortorder);
6645
			}
6646
6647
			foreach($filearray as $key => $val)
6648
			{
6649
				$photo='';
6650
				$file = $val['name'];
6651
6652
				//if (! utf8_check($file)) $file=utf8_encode($file);	// To be sure file is stored in UTF8 in memory
6653
6654
				//if (dol_is_file($dir.$file) && image_format_supported($file) >= 0)
6655
				if (image_format_supported($file) >= 0)
6656
				{
6657
					$nbphoto++;
6658
					$photo = $file;
6659
					$viewfilename = $file;
6660
6661
					if ($size == 1 || $size == 'small') {   // Format vignette
6662
6663
						// Find name of thumb file
6664
						$photo_vignette=basename(getImageFileNameForSize($dir.$file, '_small'));
6665
						if (! dol_is_file($dirthumb.$photo_vignette)) $photo_vignette='';
6666
6667
						// Get filesize of original file
6668
						$imgarray=dol_getImageSize($dir.$photo);
6669
6670
						if ($nbbyrow > 0)
6671
						{
6672
							if ($nbphoto == 1) $return.= '<table width="100%" valign="top" align="center" border="0" cellpadding="2" cellspacing="2">';
6673
6674
							if ($nbphoto % $nbbyrow == 1) $return.= '<tr align=center valign=middle border=1>';
6675
							$return.= '<td width="'.ceil(100/$nbbyrow).'%" class="photo">';
6676
						}
6677
						else if ($nbbyrow < 0) $return .= '<div class="inline-block">';
6678
6679
						$return.= "\n";
6680
6681
						$relativefile=preg_replace('/^\//', '', $pdir.$photo);
6682
						if (empty($nolink))
6683
						{
6684
							$urladvanced=getAdvancedPreviewUrl($modulepart, $relativefile, 0, 'entity='.$this->entity);
6685
							if ($urladvanced) $return.='<a href="'.$urladvanced.'">';
6686
							else $return.= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'" class="aphoto" target="_blank">';
6687
						}
6688
6689
						// Show image (width height=$maxHeight)
6690
						// Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine
6691
						$alt=$langs->transnoentitiesnoconv('File').': '.$relativefile;
6692
						$alt.=' - '.$langs->transnoentitiesnoconv('Size').': '.$imgarray['width'].'x'.$imgarray['height'];
6693
						if ($notitle) $alt='';
6694
6695
						if ($usesharelink)
6696
						{
6697
							if ($val['share'])
6698
							{
6699
								if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight)
6700
								{
6701
									$return.= '<!-- Show original file (thumb not yet available with shared links) -->';
6702
									$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).'" title="'.dol_escape_htmltag($alt).'">';
6703
								}
6704
								else {
6705
									$return.= '<!-- Show original file -->';
6706
									$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($val['share']).'" title="'.dol_escape_htmltag($alt).'">';
6707
								}
6708
							}
6709
							else
6710
							{
6711
								$return.= '<!-- Show nophoto file (because file is not shared) -->';
6712
								$return.= '<img class="photo photowithmargin" border="0" height="'.$maxHeight.'" src="'.DOL_URL_ROOT.'/public/theme/common/nophoto.png" title="'.dol_escape_htmltag($alt).'">';
6713
							}
6714
						}
6715
						else
6716
						{
6717
							if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight)
6718
							{
6719
								$return.= '<!-- Show thumb -->';
6720
								$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).'">';
6721
							}
6722
							else {
6723
								$return.= '<!-- Show original file -->';
6724
								$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).'">';
6725
							}
6726
						}
6727
6728
						if (empty($nolink)) $return.= '</a>';
6729
						$return.="\n";
6730
6731
						if ($showfilename) $return.= '<br>'.$viewfilename;
6732
						if ($showaction)
6733
						{
6734
							$return.= '<br>';
6735
							// On propose la generation de la vignette si elle n'existe pas et si la taille est superieure aux limites
6736
							if ($photo_vignette && (image_format_supported($photo) > 0) && ($this->imgWidth > $maxWidth || $this->imgHeight > $maxHeight))
6737
							{
6738
								$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>';
6739
							}
6740
							// Special cas for product
6741
							if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer))
6742
							{
6743
								// Link to resize
6744
								$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; ';
6745
6746
								// Link to delete
6747
								$return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=delete&amp;file='.urlencode($pdir.$viewfilename).'">';
6748
								$return.= img_delete().'</a>';
6749
							}
6750
						}
6751
						$return.= "\n";
6752
6753
						if ($nbbyrow > 0)
6754
						{
6755
							$return.= '</td>';
6756
							if (($nbphoto % $nbbyrow) == 0) $return.= '</tr>';
6757
						}
6758
						else if ($nbbyrow < 0) $return.='</div>';
6759
					}
6760
6761
					if (empty($size)) {     // Format origine
6762
						$return.= '<img class="photo photowithmargin" border="0" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$this->entity.'&file='.urlencode($pdir.$photo).'">';
6763
6764
						if ($showfilename) $return.= '<br>'.$viewfilename;
6765
						if ($showaction)
6766
						{
6767
							// Special case for product
6768
							if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer))
6769
							{
6770
								// Link to resize
6771
								$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; ';
6772
6773
								// Link to delete
6774
								$return.= '<a href="'.$_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=delete&amp;file='.urlencode($pdir.$viewfilename).'">';
6775
								$return.= img_delete().'</a>';
6776
							}
6777
						}
6778
					}
6779
6780
					// On continue ou on arrete de boucler ?
6781
					if ($nbmax && $nbphoto >= $nbmax) break;
6782
				}
6783
			}
6784
6785
			if ($size==1 || $size=='small')
6786
			{
6787
				if ($nbbyrow > 0)
6788
				{
6789
					// Ferme tableau
6790
					while ($nbphoto % $nbbyrow)
6791
					{
6792
						$return.= '<td width="'.ceil(100/$nbbyrow).'%">&nbsp;</td>';
6793
						$nbphoto++;
6794
					}
6795
6796
					if ($nbphoto) $return.= '</table>';
6797
				}
6798
			}
6799
		}
6800
6801
		$this->nbphoto = $nbphoto;
6802
6803
		return $return;
6804
	}
6805
6806
6807
	/**
6808
	 * Function test if type is array
6809
	 *
6810
	 * @param   array   $info   content informations of field
6811
	 * @return                  bool
6812
	 */
6813
	protected function isArray($info)
6814
	{
6815
		if(is_array($info))
6816
		{
6817
			if(isset($info['type']) && $info['type']=='array') return true;
6818
			else return false;
6819
		}
6820
		else return false;
6821
	}
6822
6823
	/**
6824
	 * Function test if type is null
6825
	 *
6826
	 * @param   array   $info   content informations of field
6827
	 * @return                  bool
6828
	 */
6829
	protected function isNull($info)
6830
	{
6831
		if(is_array($info))
6832
		{
6833
			if(isset($info['type']) && $info['type']=='null') return true;
6834
			else return false;
6835
		}
6836
		else return false;
6837
	}
6838
6839
	/**
6840
	 * Function test if type is date
6841
	 *
6842
	 * @param   array   $info   content informations of field
6843
	 * @return                  bool
6844
	 */
6845
	public function isDate($info)
6846
	{
6847
		if(isset($info['type']) && ($info['type']=='date' || $info['type']=='datetime' || $info['type']=='timestamp')) return true;
6848
		else return false;
6849
	}
6850
6851
	/**
6852
	 * Function test if type is integer
6853
	 *
6854
	 * @param   array   $info   content informations of field
6855
	 * @return                  bool
6856
	 */
6857
	public function isInt($info)
6858
	{
6859
		if(is_array($info))
6860
		{
6861
			if(isset($info['type']) && ($info['type']=='int' || preg_match('/^integer/i',$info['type']) ) ) return true;
6862
			else return false;
6863
		}
6864
		else return false;
6865
	}
6866
6867
	/**
6868
	 * Function test if type is float
6869
	 *
6870
	 * @param   array   $info   content informations of field
6871
	 * @return                  bool
6872
	 */
6873
	public function isFloat($info)
6874
	{
6875
		if(is_array($info))
6876
		{
6877
			if (isset($info['type']) && (preg_match('/^(double|real)/i', $info['type']))) return true;
6878
			else return false;
6879
		}
6880
		else return false;
6881
	}
6882
6883
	/**
6884
	 * Function test if type is text
6885
	 *
6886
	 * @param   array   $info   content informations of field
6887
	 * @return                  bool
6888
	 */
6889
	public function isText($info)
6890
	{
6891
		if(is_array($info))
6892
		{
6893
			if(isset($info['type']) && $info['type']=='text') return true;
6894
			else return false;
6895
		}
6896
		else return false;
6897
	}
6898
6899
	/**
6900
	 * Function test if is indexed
6901
	 *
6902
	 * @param   array   $info   content informations of field
6903
	 * @return                  bool
6904
	 */
6905
	protected function isIndex($info)
6906
	{
6907
		if(is_array($info))
6908
		{
6909
			if(isset($info['index']) && $info['index']==true) return true;
6910
			else return false;
6911
		}
6912
		else return false;
6913
	}
6914
6915
	/**
6916
	 * Function to prepare the values to insert.
6917
	 * Note $this->${field} are set by the page that make the createCommon or the updateCommon.
6918
	 *
6919
	 * @return array
6920
	 */
6921
	protected function setSaveQuery()
6922
	{
6923
		global $conf;
6924
6925
		$queryarray=array();
6926
		foreach ($this->fields as $field=>$info)	// Loop on definition of fields
6927
		{
6928
			// Depending on field type ('datetime', ...)
6929
			if($this->isDate($info))
6930
			{
6931
				if(empty($this->{$field}))
6932
				{
6933
					$queryarray[$field] = null;
6934
				}
6935
				else
6936
				{
6937
					$queryarray[$field] = $this->db->idate($this->{$field});
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
6938
				}
6939
			}
6940
			else if($this->isArray($info))
6941
			{
6942
				if(! empty($this->{$field})) {
6943
					if(! is_array($this->{$field})) {
6944
						$this->{$field} = array($this->{$field});
6945
					}
6946
					$queryarray[$field] = serialize($this->{$field});
6947
				} else {
6948
					$queryarray[$field] = null;
6949
				}
6950
			}
6951
			else if($this->isInt($info))
6952
			{
6953
				if ($field == 'entity' && is_null($this->{$field}))
6954
                    $queryarray[$field] = Globals::$conf->entity;
6955
                else
6956
				{
6957
					$queryarray[$field] = (int) price2num($this->{$field});
6958
					if (empty($queryarray[$field])) $queryarray[$field]=0;		// May be reset to null later if property 'notnull' is -1 for this field.
6959
				}
6960
			}
6961
			else if($this->isFloat($info))
6962
			{
6963
				$queryarray[$field] = (double) price2num($this->{$field});
6964
				if (empty($queryarray[$field])) $queryarray[$field]=0;
6965
			}
6966
			else
6967
			{
6968
				$queryarray[$field] = $this->{$field};
6969
			}
6970
6971
			if ($info['type'] == 'timestamp' && empty($queryarray[$field])) unset($queryarray[$field]);
6972
			if (! empty($info['notnull']) && $info['notnull'] == -1 && empty($queryarray[$field])) $queryarray[$field] = null;
6973
		}
6974
6975
		return $queryarray;
6976
	}
6977
6978
	/**
6979
	 * Function to load data from a SQL pointer into properties of current object $this
6980
	 *
6981
	 * @param   stdClass    $obj    Contain data of object from database
6982
     * @return void
6983
	 */
6984
	protected function setVarsFromFetchObj(&$obj)
6985
	{
6986
		foreach ($this->fields as $field => $info)
6987
		{
6988
			if($this->isDate($info))
6989
			{
6990
				if(empty($obj->{$field}) || $obj->{$field} === '0000-00-00 00:00:00' || $obj->{$field} === '1000-01-01 00:00:00') $this->{$field} = 0;
6991
				else $this->{$field} = strtotime($obj->{$field});
6992
			}
6993
			elseif($this->isArray($info))
6994
			{
6995
				if(! empty($obj->{$field})) {
6996
					$this->{$field} = @unserialize($obj->{$field});
6997
					// Hack for data not in UTF8
6998
					if($this->{$field } === false) @unserialize(utf8_decode($obj->{$field}));
6999
				} else {
7000
					$this->{$field} = array();
7001
				}
7002
			}
7003
			elseif($this->isInt($info))
7004
			{
7005
				if ($field == 'rowid') $this->id = (int) $obj->{$field};
7006
				else $this->{$field} = (int) $obj->{$field};
7007
			}
7008
			elseif($this->isFloat($info))
7009
			{
7010
				$this->{$field} = (double) $obj->{$field};
7011
			}
7012
			elseif($this->isNull($info))
7013
			{
7014
				$val = $obj->{$field};
7015
				// zero is not null
7016
				$this->{$field} = (is_null($val) || (empty($val) && $val!==0 && $val!=='0') ? null : $val);
7017
			}
7018
			else
7019
			{
7020
				$this->{$field} = $obj->{$field};
7021
			}
7022
		}
7023
7024
		// If there is no 'ref' field, we force property ->ref to ->id for a better compatibility with common functions.
7025
		if (! isset($this->fields['ref']) && isset($this->id)) $this->ref = $this->id;
7026
	}
7027
7028
	/**
7029
	 * Function to concat keys of fields
7030
	 *
7031
	 * @return string
7032
	 */
7033
	protected function getFieldList()
7034
	{
7035
		$keys = array_keys($this->fields);
7036
		return implode(',', $keys);
7037
	}
7038
7039
	/**
7040
	 * Add quote to field value if necessary
7041
	 *
7042
	 * @param 	string|int	$value			Value to protect
7043
	 * @param	array		$fieldsentry	Properties of field
7044
	 * @return 	string
7045
	 */
7046
    protected function quote($value, $fieldsentry)
7047
    {
7048
		if (is_null($value)) return 'NULL';
7049
		else if (preg_match('/^(int|double|real)/i', $fieldsentry['type'])) return $this->db->escape("$value");
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
7050
		else return "'".$this->db->escape($value)."'";
7051
	}
7052
7053
7054
	/**
7055
	 * Create object into database
7056
	 *
7057
	 * @param  User $user      User that creates
7058
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
7059
	 * @return int             <0 if KO, Id of created object if OK
7060
	 */
7061
	public function createCommon(User $user, $notrigger = false)
7062
	{
7063
		global $langs;
7064
7065
		$error = 0;
7066
7067
		$now=dol_now();
7068
7069
		$fieldvalues = $this->setSaveQuery();
7070
		if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) $fieldvalues['date_creation']=$this->db->idate($now);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
7071
		if (array_key_exists('fk_user_creat', $fieldvalues) && ! ($fieldvalues['fk_user_creat'] > 0)) $fieldvalues['fk_user_creat']=$user->id;
7072
		unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into insert.
7073
7074
		$keys=array();
7075
		$values = array();
7076
		foreach ($fieldvalues as $k => $v) {
7077
			$keys[$k] = $k;
7078
			$value = $this->fields[$k];
7079
			$values[$k] = $this->quote($v, $value);
7080
		}
7081
7082
		// Clean and check mandatory
7083
		foreach($keys as $key)
7084
		{
7085
			// If field is an implicit foreign key field
7086
			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';
7087
			if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';
7088
7089
			//var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7090
			if (isset($this->fields[$key]['notnull']) && $this->fields[$key]['notnull'] == 1 && ! isset($values[$key]) && is_null($val['default']))
7091
			{
7092
				$error++;
7093
				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7094
			}
7095
7096
			// If field is an implicit foreign key field
7097
			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && empty($values[$key])) $values[$key]='null';
7098
			if (! empty($this->fields[$key]['foreignkey']) && empty($values[$key])) $values[$key]='null';
7099
		}
7100
7101
		if ($error) return -1;
7102
7103
		$this->db->begin();
7104
7105
		if (! $error)
7106
		{
7107
			$sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
7108
			$sql.= ' ('.implode( ", ", $keys ).')';
7109
			$sql.= ' VALUES ('.implode( ", ", $values ).')';
7110
7111
			$res = $this->db->query($sql);
7112
			if ($res===false) {
7113
				$error++;
7114
				$this->errors[] = $this->db->lasterror();
7115
			}
7116
		}
7117
7118
		if (! $error)
7119
		{
7120
			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
7121
		}
7122
7123
		// Create extrafields
7124
		if (! $error)
7125
		{
7126
			$result=$this->insertExtraFields();
7127
			if ($result < 0) $error++;
7128
		}
7129
7130
		// Triggers
7131
		if (! $error && ! $notrigger)
7132
		{
7133
			// Call triggers
7134
			$result=$this->call_trigger(strtoupper(get_class($this)).'_CREATE',$user);
7135
			if ($result < 0) { $error++; }
7136
			// End call triggers
7137
		}
7138
7139
		// Commit or rollback
7140
		if ($error) {
7141
			$this->db->rollback();
7142
			return -1;
7143
		} else {
7144
			$this->db->commit();
7145
			return $this->id;
7146
		}
7147
	}
7148
7149
7150
	/**
7151
	 * Load object in memory from the database
7152
	 *
7153
	 * @param	int    $id				Id object
7154
	 * @param	string $ref				Ref
7155
	 * @param	string	$morewhere		More SQL filters (' AND ...')
7156
	 * @return 	int         			<0 if KO, 0 if not found, >0 if OK
7157
	 */
7158
	public function fetchCommon($id, $ref = null, $morewhere = '')
7159
	{
7160
		if (empty($id) && empty($ref) && empty($morewhere)) return -1;
7161
7162
		$sql = 'SELECT '.$this->getFieldList();
7163
		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
7164
7165
		if (!empty($id))  $sql.= ' WHERE rowid = '.$id;
7166
		elseif (!empty($ref)) $sql.= " WHERE ref = ".$this->quote($ref, $this->fields['ref']);
7167
		else $sql.=' WHERE 1 = 1';	// usage with empty id and empty ref is very rare
7168
		if ($morewhere)   $sql.= $morewhere;
7169
		$sql.=' LIMIT 1';	// This is a fetch, to be sure to get only one record
7170
7171
		$res = $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
7172
		if ($res)
7173
		{
7174
			$obj = $this->db->fetch_object($res);
7175
			if ($obj)
7176
			{
7177
				$this->setVarsFromFetchObj($obj);
7178
				return $this->id;
7179
			}
7180
			else
7181
			{
7182
				return 0;
7183
			}
7184
		}
7185
		else
7186
		{
7187
			$this->error = $this->db->lasterror();
7188
			$this->errors[] = $this->error;
7189
			return -1;
7190
		}
7191
	}
7192
7193
	/**
7194
	 * Update object into database
7195
	 *
7196
	 * @param  User $user      	User that modifies
7197
	 * @param  bool $notrigger 	false=launch triggers after, true=disable triggers
7198
	 * @return int             	<0 if KO, >0 if OK
7199
	 */
7200
	public function updateCommon(User $user, $notrigger = false)
7201
	{
7202
		global $conf, $langs;
7203
7204
		$error = 0;
7205
7206
		$now=dol_now();
7207
7208
		$fieldvalues = $this->setSaveQuery();
7209
		if (array_key_exists('date_modification', $fieldvalues) && empty($fieldvalues['date_modification'])) $fieldvalues['date_modification']=$this->db->idate($now);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
7210
		if (array_key_exists('fk_user_modif', $fieldvalues) && ! ($fieldvalues['fk_user_modif'] > 0)) $fieldvalues['fk_user_modif']=$user->id;
7211
		unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into update.
7212
7213
		$keys=array();
7214
		$values = array();
7215
		foreach ($fieldvalues as $k => $v) {
7216
			$keys[$k] = $k;
7217
			$value = $this->fields[$k];
7218
			$values[$k] = $this->quote($v, $value);
7219
			$tmp[] = $k.'='.$this->quote($v, $this->fields[$k]);
7220
		}
7221
7222
		// Clean and check mandatory
7223
		foreach($keys as $key)
7224
		{
7225
			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';		// This is an implicit foreign key field
7226
			if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';					// This is an explicit foreign key field
7227
7228
			//var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7229
			/*
7230
			if ($this->fields[$key]['notnull'] == 1 && empty($values[$key]))
7231
			{
7232
				$error++;
7233
				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7234
			}*/
7235
		}
7236
7237
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET '.implode( ',', $tmp ).' WHERE rowid='.$this->id ;
7238
7239
		$this->db->begin();
7240
		if (! $error)
7241
		{
7242
			$res = $this->db->query($sql);
7243
			if ($res===false)
7244
			{
7245
				$error++;
7246
				$this->errors[] = $this->db->lasterror();
7247
			}
7248
		}
7249
7250
		// Update extrafield
7251
		if (!$error && empty(Globals::$conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options) > 0) {
7252
			$result=$this->insertExtraFields();
7253
			if ($result < 0)
7254
			{
7255
				$error++;
7256
			}
7257
		}
7258
7259
		// Triggers
7260
		if (! $error && ! $notrigger)
7261
		{
7262
			// Call triggers
7263
			$result=$this->call_trigger(strtoupper(get_class($this)).'_MODIFY',$user);
7264
			if ($result < 0) { $error++; } //Do also here what you must do to rollback action if trigger fail
7265
			// End call triggers
7266
		}
7267
7268
		// Commit or rollback
7269
		if ($error) {
7270
			$this->db->rollback();
7271
			return -1;
7272
		} else {
7273
			$this->db->commit();
7274
			return $this->id;
7275
		}
7276
	}
7277
7278
	/**
7279
	 * Delete object in database
7280
	 *
7281
	 * @param 	User 	$user       			User that deletes
7282
	 * @param 	bool 	$notrigger  			false=launch triggers after, true=disable triggers
7283
	 * @param	int		$forcechilddeletion		0=no, 1=Force deletion of children
7284
	 * @return 	int             				<=0 if KO, >0 if OK
7285
	 */
7286
	public function deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
7287
	{
7288
		$error=0;
7289
7290
		$this->db->begin();
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
7291
7292
		if ($forcechilddeletion)
7293
		{
7294
			foreach($this->childtables as $table)
0 ignored issues
show
Bug Best Practice introduced by
The property childtables does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
7295
			{
7296
				$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$table.' WHERE '.$this->fk_element.' = '.$this->id;
7297
				$resql = $this->db->query($sql);
7298
				if (! $resql)
7299
				{
7300
					$this->error=$this->db->lasterror();
7301
					$this->errors[]=$this->error;
7302
					$this->db->rollback();
7303
					return -1;
7304
				}
7305
			}
7306
		}
7307
		elseif (! empty($this->fk_element) && ! empty($this->childtables))	// If object has childs linked with a foreign key field, we check all child tables.
7308
		{
7309
			$objectisused = $this->isObjectUsed($this->id);
7310
			if (! empty($objectisused))
7311
			{
7312
				dol_syslog(get_class($this)."::deleteCommon Can't delete record as it has some child", LOG_WARNING);
7313
				$this->error='ErrorRecordHasChildren';
7314
				$this->errors[]=$this->error;
7315
				$this->db->rollback();
7316
				return 0;
7317
			}
7318
		}
7319
7320
		if (! $error) {
7321
			if (! $notrigger) {
7322
				// Call triggers
7323
				$result=$this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user);
7324
				if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
7325
				// End call triggers
7326
			}
7327
		}
7328
7329
		if (! $error && ! empty($this->isextrafieldmanaged))
7330
		{
7331
			$sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element."_extrafields";
7332
			$sql.= " WHERE fk_object=" . $this->id;
7333
7334
			$resql = $this->db->query($sql);
7335
			if (! $resql)
7336
			{
7337
				$this->errors[] = $this->db->lasterror();
7338
				$error++;
7339
			}
7340
		}
7341
7342
		if (! $error)
7343
		{
7344
			$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
7345
7346
			$res = $this->db->query($sql);
7347
			if($res===false) {
7348
				$error++;
7349
				$this->errors[] = $this->db->lasterror();
7350
			}
7351
		}
7352
7353
		// Commit or rollback
7354
		if ($error) {
7355
			$this->db->rollback();
7356
			return -1;
7357
		} else {
7358
			$this->db->commit();
7359
			return 1;
7360
		}
7361
	}
7362
7363
	/**
7364
	 * Initialise object with example values
7365
	 * Id must be 0 if object instance is a specimen
7366
	 *
7367
	 * @return void
7368
	 */
7369
	public function initAsSpecimenCommon()
7370
	{
7371
		$this->id = 0;
7372
7373
		// TODO...
7374
	}
7375
7376
7377
	/* Part for comments */
7378
7379
	/**
7380
	 * Load comments linked with current task
7381
	 *	@return boolean	1 if ok
7382
	 */
7383
	public function fetchComments()
7384
	{
7385
		require_once DOL_DOCUMENT_ROOT.'/core/class/comment.class.php';
7386
7387
		$comment = new Comment($this->db);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Alixar\Base\AlCommonObject. Did you maybe forget to declare it?
Loading history...
7388
		$result=$comment->fetchAllFor($this->element, $this->id);
7389
		if ($result<0) {
7390
			$this->errors=array_merge($this->errors, $comment->errors);
7391
			return -1;
7392
		} else {
7393
			$this->comments = $comment->comments;
7394
		}
7395
		return count($this->comments);
7396
	}
7397
7398
	/**
7399
	 * Return nb comments already posted
7400
	 *
7401
	 * @return int
7402
	 */
7403
	public function getNbComments()
7404
	{
7405
		return count($this->comments);
7406
	}
7407
7408
    /**
7409
     * Trim object parameters
7410
     * @param string[] $parameters array of parameters to trim
7411
     *
7412
     * @return void
7413
     */
7414
    public function trimParameters($parameters)
7415
    {
7416
        if (!is_array($parameters)) return;
7417
        foreach ($parameters as $parameter) {
7418
            if (isset($this->$parameter)) {
7419
                $this->$parameter = trim($this->$parameter);
7420
            }
7421
        }
7422
    }
7423
}
7424