Passed
Branch develop (a7390e)
by
unknown
25:38
created

CommonObject::updateLineUp()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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

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

1358
		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...
1359
	}
1360
1361
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1362
	/**
1363
	 *	Load data for barcode into properties ->barcode_type*
1364
	 *	Properties ->barcode_type that is id of barcode. Type is used to find other properties, but
1365
	 *  if it is not defined, ->element must be defined to know default barcode type.
1366
	 *
1367
	 *	@return		int			<0 if KO, 0 if can't guess type of barcode (ISBN, EAN13...), >0 if OK (all barcode properties loaded)
1368
	 */
1369
	public function fetch_barcode()
1370
	{
1371
        // phpcs:enable
1372
		global $conf;
1373
1374
		dol_syslog(get_class($this).'::fetch_barcode this->element='.$this->element.' this->barcode_type='.$this->barcode_type);
1375
1376
		$idtype=$this->barcode_type;
1377
		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
1378
		{
1379
			if ($this->element == 'product')      $idtype = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
1380
			elseif ($this->element == 'societe') $idtype = $conf->global->GENBARCODE_BARCODETYPE_THIRDPARTY;
1381
			else dol_syslog('Call fetch_barcode with barcode_type not defined and cant be guessed', LOG_WARNING);
1382
		}
1383
1384
		if ($idtype > 0)
1385
		{
1386
			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
1387
			{
1388
				$sql = "SELECT rowid, code, libelle as label, coder";
1389
				$sql.= " FROM ".MAIN_DB_PREFIX."c_barcode_type";
1390
				$sql.= " WHERE rowid = ".$idtype;
1391
				dol_syslog(get_class($this).'::fetch_barcode', LOG_DEBUG);
1392
				$resql = $this->db->query($sql);
1393
				if ($resql)
1394
				{
1395
					$obj = $this->db->fetch_object($resql);
1396
					$this->barcode_type       = $obj->rowid;
1397
					$this->barcode_type_code  = $obj->code;
1398
					$this->barcode_type_label = $obj->label;
1399
					$this->barcode_type_coder = $obj->coder;
1400
					return 1;
1401
				}
1402
				else
1403
				{
1404
					dol_print_error($this->db);
1405
					return -1;
1406
				}
1407
			}
1408
		}
1409
		return 0;
1410
	}
1411
1412
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1413
	/**
1414
	 *		Load the project with id $this->fk_project into this->project
1415
	 *
1416
	 *		@return		int			<0 if KO, >=0 if OK
1417
	 */
1418
	public function fetch_projet()
1419
	{
1420
        // phpcs:enable
1421
		include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
1422
1423
		if (empty($this->fk_project) && ! empty($this->fk_projet)) $this->fk_project = $this->fk_projet;	// For backward compatibility
1424
		if (empty($this->fk_project)) return 0;
1425
1426
		$project = new Project($this->db);
1427
		$result = $project->fetch($this->fk_project);
1428
1429
		$this->projet = $project;	// deprecated
1 ignored issue
show
Deprecated Code introduced by
The property CommonObject::$projet has been deprecated. ( Ignorable by Annotation )

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

1429
		/** @scrutinizer ignore-deprecated */ $this->projet = $project;	// deprecated
Loading history...
1430
		$this->project = $project;
1431
		return $result;
1432
	}
1433
1434
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1435
	/**
1436
	 *		Load the product with id $this->fk_product into this->product
1437
	 *
1438
	 *		@return		int			<0 if KO, >=0 if OK
1439
	 */
1440
	public function fetch_product()
1441
	{
1442
        // phpcs:enable
1443
		include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1444
1445
		if (empty($this->fk_product)) return 0;
1446
1447
		$product = new Product($this->db);
1448
		$result = $product->fetch($this->fk_product);
1449
1450
		$this->product = $product;
1451
		return $result;
1452
	}
1453
1454
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1455
	/**
1456
	 *		Load the user with id $userid into this->user
1457
	 *
1458
	 *		@param	int		$userid 		Id du contact
1459
	 *		@return	int						<0 if KO, >0 if OK
1460
	 */
1461
	public function fetch_user($userid)
1462
	{
1463
        // phpcs:enable
1464
		$user = new User($this->db);
1465
		$result=$user->fetch($userid);
1466
		$this->user = $user;
1467
		return $result;
1468
	}
1469
1470
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1471
	/**
1472
	 *	Read linked origin object
1473
	 *
1474
	 *	@return		void
1475
	 */
1476
	public function fetch_origin()
1477
	{
1478
        // phpcs:enable
1479
		if ($this->origin == 'shipping') $this->origin = 'expedition';
1480
		if ($this->origin == 'delivery') $this->origin = 'livraison';
1481
        if ($this->origin == 'order_supplier') $this->origin = 'commandeFournisseur';
1482
1483
		$origin = $this->origin;
1484
1485
		$classname = ucfirst($origin);
1486
		$this->$origin = new $classname($this->db);
1487
		$this->$origin->fetch($this->origin_id);
1488
	}
1489
1490
	/**
1491
     *  Load object from specific field
1492
     *
1493
     *  @param	string	$table		Table element or element line
1494
     *  @param	string	$field		Field selected
1495
     *  @param	string	$key		Import key
1496
     *  @param	string	$element	Element name
1497
     *	@return	int					<0 if KO, >0 if OK
1498
     */
1499
	public function fetchObjectFrom($table, $field, $key, $element = null)
1500
	{
1501
		global $conf;
1502
1503
		$result=false;
1504
1505
		$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$table;
1506
		$sql.= " WHERE ".$field." = '".$key."'";
1507
		if (! empty($element)) {
1508
			$sql.= " AND entity IN (".getEntity($element).")";
1509
		} else {
1510
			$sql.= " AND entity = ".$conf->entity;
1511
		}
1512
1513
		dol_syslog(get_class($this).'::fetchObjectFrom', LOG_DEBUG);
1514
		$resql = $this->db->query($sql);
1515
		if ($resql)
1516
		{
1517
			$row = $this->db->fetch_row($resql);
1518
			// Test for avoid error -1
1519
			if ($row[0] > 0) {
1520
				$result = $this->fetch($row[0]);
1521
			}
1522
		}
1523
1524
		return $result;
1525
	}
1526
1527
	/**
1528
	 *	Getter generic. Load value from a specific field
1529
	 *
1530
	 *	@param	string	$table		Table of element or element line
1531
	 *	@param	int		$id			Element id
1532
	 *	@param	string	$field		Field selected
1533
	 *	@return	int					<0 if KO, >0 if OK
1534
	 */
1535
	public function getValueFrom($table, $id, $field)
1536
	{
1537
		$result=false;
1538
		if (!empty($id) && !empty($field) && !empty($table)) {
1539
			$sql = "SELECT ".$field." FROM ".MAIN_DB_PREFIX.$table;
1540
			$sql.= " WHERE rowid = ".$id;
1541
1542
			dol_syslog(get_class($this).'::getValueFrom', LOG_DEBUG);
1543
			$resql = $this->db->query($sql);
1544
			if ($resql)
1545
			{
1546
				$row = $this->db->fetch_row($resql);
1547
				$result = $row[0];
1548
			}
1549
		}
1550
		return $result;
1551
	}
1552
1553
	/**
1554
	 *	Setter generic. Update a specific field into database.
1555
	 *  Warning: Trigger is run only if param trigkey is provided.
1556
	 *
1557
	 *	@param	string		$field			Field to update
1558
	 *	@param	mixed		$value			New value
1559
	 *	@param	string		$table			To force other table element or element line (should not be used)
1560
	 *	@param	int			$id				To force other object id (should not be used)
1561
	 *	@param	string		$format			Data format ('text', 'date'). 'text' is used if not defined
1562
	 *	@param	string		$id_field		To force rowid field name. 'rowid' is used if not defined
1563
	 *	@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'
1564
	 *  @param  string      $trigkey    	Trigger key to run (in most cases something like 'XXX_MODIFY')
1565
	 *  @param	string		$fk_user_field	Name of field to save user id making change
1566
	 *	@return	int							<0 if KO, >0 if OK
1567
	 *  @see updateExtraField()
1568
	 */
1569
	public function setValueFrom($field, $value, $table = '', $id = null, $format = '', $id_field = '', $fuser = null, $trigkey = '', $fk_user_field = 'fk_user_modif')
1570
	{
1571
		global $user,$langs,$conf;
1572
1573
		if (empty($table)) 	  $table=$this->table_element;
1574
		if (empty($id))    	  $id=$this->id;
1575
		if (empty($format))   $format='text';
1576
		if (empty($id_field)) $id_field='rowid';
1577
1578
		$error=0;
1579
1580
		$this->db->begin();
1581
1582
		// Special case
1583
		if ($table == 'product' && $field == 'note_private') $field='note';
1584
		if (in_array($table, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))) $fk_user_field = 'fk_user_mod';
1585
1586
		$sql = "UPDATE ".MAIN_DB_PREFIX.$table." SET ";
1587
1588
		if ($format == 'text') $sql.= $field." = '".$this->db->escape($value)."'";
1589
		elseif ($format == 'int') $sql.= $field." = ".$this->db->escape($value);
1590
		elseif ($format == 'date') $sql.= $field." = ".($value ? "'".$this->db->idate($value)."'" : "null");
1591
1592
		if ($fk_user_field)
1593
		{
1594
			if (! empty($fuser) && is_object($fuser)) $sql.=", ".$fk_user_field." = ".$fuser->id;
1595
			elseif (empty($fuser) || $fuser != 'none') $sql.=", ".$fk_user_field." = ".$user->id;
1596
		}
1597
1598
		$sql.= " WHERE ".$id_field." = ".$id;
1599
1600
		dol_syslog(get_class($this)."::".__FUNCTION__."", LOG_DEBUG);
1601
		$resql = $this->db->query($sql);
1602
		if ($resql)
1603
		{
1604
			if ($trigkey)
1605
			{
1606
				// call trigger with updated object values
1607
				if (empty($this->fields) && method_exists($this, 'fetch'))
1608
				{
1609
					$result = $this->fetch($id);
1610
				}
1611
				else
1612
				{
1613
					$result = $this->fetchCommon($id);
1614
				}
1615
				if ($result >= 0) $result=$this->call_trigger($trigkey, (! empty($fuser) && is_object($fuser)) ? $fuser : $user);   // This may set this->errors
1616
				if ($result < 0) $error++;
1617
			}
1618
1619
			if (! $error)
1620
			{
1621
				if (property_exists($this, $field)) $this->$field = $value;
1622
				$this->db->commit();
1623
				return 1;
1624
			}
1625
			else
1626
			{
1627
				$this->db->rollback();
1628
				return -2;
1629
			}
1630
		}
1631
		else
1632
		{
1633
			$this->error=$this->db->lasterror();
1634
			$this->db->rollback();
1635
			return -1;
1636
		}
1637
	}
1638
1639
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1640
	/**
1641
	 *      Load properties id_previous and id_next by comparing $fieldid with $this->ref
1642
	 *
1643
	 *      @param	string	$filter		Optional filter. Example: " AND (t.field1 = 'aa' OR t.field2 = 'bb')"
1644
	 *	 	@param  string	$fieldid   	Name of field to use for the select MAX and MIN
1645
	 *		@param	int		$nodbprefix	Do not include DB prefix to forge table name
1646
	 *      @return int         		<0 if KO, >0 if OK
1647
	 */
1648
	public function load_previous_next_ref($filter, $fieldid, $nodbprefix = 0)
1649
	{
1650
        // phpcs:enable
1651
		global $conf, $user;
1652
1653
		if (! $this->table_element)
1654
		{
1655
			dol_print_error('', get_class($this)."::load_previous_next_ref was called on objet with property table_element not defined");
1656
			return -1;
1657
		}
1658
		if ($fieldid == 'none') return 1;
1659
1660
		// Security on socid
1661
		$socid = 0;
1662
		if ($user->societe_id > 0) $socid = $user->societe_id;
1663
1664
		// this->ismultientitymanaged contains
1665
		// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
1666
		$alias = 's';
1667
		if ($this->element == 'societe') $alias = 'te';
1668
1669
		$sql = "SELECT MAX(te.".$fieldid.")";
1670
		$sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1671
		if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1672
			$sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
1673
		}
1674
		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
1675
		elseif ($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
1676
		elseif ($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
1677
		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";
1678
		$sql.= " WHERE te.".$fieldid." < '".$this->db->escape($this->ref)."'";  // ->ref must always be defined (set to id if field does not exists)
1679
		if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1680
		if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1681
		if (! empty($filter))
1682
		{
1683
			if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND ";   // For backward compatibility
1684
			$sql.=$filter;
1685
		}
1686
		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
1687
		elseif ($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
1688
		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1689
			if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1690
				if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1691
					$sql.= " AND te.entity IS NOT NULL"; // Show all users
1692
				} else {
1693
					$sql.= " AND ug.fk_user = te.rowid";
1694
					$sql.= " AND ug.entity IN (".getEntity($this->element).")";
1695
				}
1696
			} else {
1697
				$sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1698
			}
1699
		}
1700
		if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1701
		if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1702
		if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1703
		//print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1704
1705
		$result = $this->db->query($sql);
1706
		if (! $result)
1707
		{
1708
			$this->error=$this->db->lasterror();
1709
			return -1;
1710
		}
1711
		$row = $this->db->fetch_row($result);
1712
		$this->ref_previous = $row[0];
1713
1714
1715
		$sql = "SELECT MIN(te.".$fieldid.")";
1716
		$sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te";
1717
		if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1718
			$sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
1719
		}
1720
		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
1721
		elseif ($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
1722
		elseif ($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
1723
		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";
1724
		$sql.= " WHERE te.".$fieldid." > '".$this->db->escape($this->ref)."'";  // ->ref must always be defined (set to id if field does not exists)
1725
		if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id;
1726
		if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)';
1727
		if (! empty($filter))
1728
		{
1729
			if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND ";   // For backward compatibility
1730
			$sql.=$filter;
1731
		}
1732
		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
1733
		elseif ($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
1734
		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1735
			if ($this->element == 'user' && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1736
				if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1737
					$sql.= " AND te.entity IS NOT NULL"; // Show all users
1738
				} else {
1739
					$sql.= " AND ug.fk_user = te.rowid";
1740
					$sql.= " AND ug.entity IN (".getEntity($this->element).")";
1741
				}
1742
			} else {
1743
				$sql.= ' AND te.entity IN ('.getEntity($this->element).')';
1744
			}
1745
		}
1746
		if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid;
1747
		if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)';
1748
		if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid;
1749
		//print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1750
		// 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
1751
1752
		$result = $this->db->query($sql);
1753
		if (! $result)
1754
		{
1755
			$this->error=$this->db->lasterror();
1756
			return -2;
1757
		}
1758
		$row = $this->db->fetch_row($result);
1759
		$this->ref_next = $row[0];
1760
1761
		return 1;
1762
	}
1763
1764
1765
	/**
1766
	 *      Return list of id of contacts of object
1767
	 *
1768
	 *      @param	string	$source     Source of contact: external (llx_socpeople) or internal (llx_user) or thirdparty (llx_societe)
1769
	 *      @return array				Array of id of contacts (if source=external or internal)
1770
	 * 									Array of id of third parties with at least one contact on object (if source=thirdparty)
1771
	 */
1772
	public function getListContactId($source = 'external')
1773
	{
1774
		$contactAlreadySelected = array();
1775
		$tab = $this->liste_contact(-1, $source);
1776
		$num=count($tab);
1777
		$i = 0;
1778
		while ($i < $num)
1779
		{
1780
			if ($source == 'thirdparty') $contactAlreadySelected[$i] = $tab[$i]['socid'];
1781
			else  $contactAlreadySelected[$i] = $tab[$i]['id'];
1782
			$i++;
1783
		}
1784
		return $contactAlreadySelected;
1785
	}
1786
1787
1788
	/**
1789
	 *	Link element with a project
1790
	 *
1791
	 *	@param     	int		$projectid		Project id to link element to
1792
	 *	@return		int						<0 if KO, >0 if OK
1793
	 */
1794
	public function setProject($projectid)
1795
	{
1796
		if (! $this->table_element)
1797
		{
1798
			dol_syslog(get_class($this)."::setProject was called on objet with property table_element not defined", LOG_ERR);
1799
			return -1;
1800
		}
1801
1802
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1803
		if ($this->table_element == 'actioncomm')
1804
		{
1805
			if ($projectid) $sql.= ' SET fk_project = '.$projectid;
1806
			else $sql.= ' SET fk_project = NULL';
1807
			$sql.= ' WHERE id = '.$this->id;
1808
		}
1809
		else
1810
		{
1811
			if ($projectid) $sql.= ' SET fk_projet = '.$projectid;
1812
			else $sql.= ' SET fk_projet = NULL';
1813
			$sql.= ' WHERE rowid = '.$this->id;
1814
		}
1815
1816
		dol_syslog(get_class($this)."::setProject", LOG_DEBUG);
1817
		if ($this->db->query($sql))
1818
		{
1819
			$this->fk_project = $projectid;
1820
			return 1;
1821
		}
1822
		else
1823
		{
1824
			dol_print_error($this->db);
1825
			return -1;
1826
		}
1827
	}
1828
1829
	/**
1830
	 *  Change the payments methods
1831
	 *
1832
	 *  @param		int		$id		Id of new payment method
1833
	 *  @return		int				>0 if OK, <0 if KO
1834
	 */
1835
	public function setPaymentMethods($id)
1836
	{
1837
		dol_syslog(get_class($this).'::setPaymentMethods('.$id.')');
1838
		if ($this->statut >= 0 || $this->element == 'societe')
1839
		{
1840
			// TODO uniformize field name
1841
			$fieldname = 'fk_mode_reglement';
1842
			if ($this->element == 'societe') $fieldname = 'mode_reglement';
1843
			if (get_class($this) == 'Fournisseur') $fieldname = 'mode_reglement_supplier';
1844
1845
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1846
			$sql .= ' SET '.$fieldname.' = '.(($id > 0 || $id == '0') ? $id : 'NULL');
1847
			$sql .= ' WHERE rowid='.$this->id;
1848
1849
			if ($this->db->query($sql))
1850
			{
1851
				$this->mode_reglement_id = $id;
1852
				// for supplier
1853
				if (get_class($this) == 'Fournisseur') $this->mode_reglement_supplier_id = $id;
1854
				return 1;
1855
			}
1856
			else
1857
			{
1858
				dol_syslog(get_class($this).'::setPaymentMethods Erreur '.$sql.' - '.$this->db->error());
1859
				$this->error=$this->db->error();
1860
				return -1;
1861
			}
1862
		}
1863
		else
1864
		{
1865
			dol_syslog(get_class($this).'::setPaymentMethods, status of the object is incompatible');
1866
			$this->error='Status of the object is incompatible '.$this->statut;
1867
			return -2;
1868
		}
1869
	}
1870
1871
	/**
1872
	 *  Change the multicurrency code
1873
	 *
1874
	 *  @param		string	$code	multicurrency code
1875
	 *  @return		int				>0 if OK, <0 if KO
1876
	 */
1877
	public function setMulticurrencyCode($code)
1878
	{
1879
		dol_syslog(get_class($this).'::setMulticurrencyCode('.$id.')');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id seems to be never defined.
Loading history...
1880
		if ($this->statut >= 0 || $this->element == 'societe')
1881
		{
1882
			$fieldname = 'multicurrency_code';
1883
1884
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1885
			$sql .= ' SET '.$fieldname." = '".$this->db->escape($code)."'";
1886
			$sql .= ' WHERE rowid='.$this->id;
1887
1888
			if ($this->db->query($sql))
1889
			{
1890
				$this->multicurrency_code = $code;
1891
1892
				list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code);
1893
				if ($rate) $this->setMulticurrencyRate($rate, 2);
1894
1895
				return 1;
1896
			}
1897
			else
1898
			{
1899
				dol_syslog(get_class($this).'::setMulticurrencyCode Erreur '.$sql.' - '.$this->db->error());
1900
				$this->error=$this->db->error();
1901
				return -1;
1902
			}
1903
		}
1904
		else
1905
		{
1906
			dol_syslog(get_class($this).'::setMulticurrencyCode, status of the object is incompatible');
1907
			$this->error='Status of the object is incompatible '.$this->statut;
1908
			return -2;
1909
		}
1910
	}
1911
1912
	/**
1913
	 *  Change the multicurrency rate
1914
	 *
1915
	 *  @param		double	$rate	multicurrency rate
1916
	 *  @param		int		$mode	mode 1 : amounts in company currency will be recalculated, mode 2 : amounts in foreign currency
1917
	 *  @return		int				>0 if OK, <0 if KO
1918
	 */
1919
	public function setMulticurrencyRate($rate, $mode = 1)
1920
	{
1921
		dol_syslog(get_class($this).'::setMulticurrencyRate('.$id.')');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id seems to be never defined.
Loading history...
1922
		if ($this->statut >= 0 || $this->element == 'societe')
1923
		{
1924
			$fieldname = 'multicurrency_tx';
1925
1926
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1927
			$sql .= ' SET '.$fieldname.' = '.$rate;
1928
			$sql .= ' WHERE rowid='.$this->id;
1929
1930
			if ($this->db->query($sql))
1931
			{
1932
				$this->multicurrency_tx = $rate;
1933
1934
				// Update line price
1935
				if (!empty($this->lines))
1936
				{
1937
					foreach ($this->lines as &$line)
1938
					{
1939
						if($mode == 1) {
1940
							$line->subprice = 0;
1941
						}
1942
1943
						switch ($this->element) {
1944
							case 'propal':
1945
								$this->updateline(
1 ignored issue
show
Bug introduced by
The method updateline() does not exist on CommonObject. Did you maybe mean updateLineUp()? ( Ignorable by Annotation )

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

1945
								$this->/** @scrutinizer ignore-call */ 
1946
               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...
1946
									$line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1947
									($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1948
									$line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start,
1949
									$line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1950
								);
1951
								break;
1952
							case 'commande':
1953
								$this->updateline(
1954
									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1955
									$line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->date_start, $line->date_end,
1956
									$line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1957
									$line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1958
								);
1959
								break;
1960
							case 'facture':
1961
								$this->updateline(
1962
									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1963
									$line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits,
1964
									$line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1965
									$line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice
1966
								);
1967
								break;
1968
							case 'supplier_proposal':
1969
								$this->updateline(
1970
									$line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1971
									($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1972
									$line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->array_options,
1973
									$line->ref_fourn, $line->multicurrency_subprice
1974
								);
1975
								break;
1976
							case 'order_supplier':
1977
								$this->updateline(
1978
									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent,
1979
									$line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, false,
1980
									$line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1981
								);
1982
								break;
1983
							case 'invoice_supplier':
1984
								$this->updateline(
1985
									$line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->tva_tx, $line->localtax1_tx,
1986
									$line->localtax2_tx, $line->qty, 0, 'HT', $line->info_bits, $line->product_type, $line->remise_percent, false,
1987
									$line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1988
								);
1989
								break;
1990
							default:
1991
								dol_syslog(get_class($this).'::setMulticurrencyRate no updateline defined', LOG_DEBUG);
1992
								break;
1993
						}
1994
					}
1995
				}
1996
1997
				return 1;
1998
			}
1999
			else
2000
			{
2001
				dol_syslog(get_class($this).'::setMulticurrencyRate Erreur '.$sql.' - '.$this->db->error());
2002
				$this->error=$this->db->error();
2003
				return -1;
2004
			}
2005
		}
2006
		else
2007
		{
2008
			dol_syslog(get_class($this).'::setMulticurrencyRate, status of the object is incompatible');
2009
			$this->error='Status of the object is incompatible '.$this->statut;
2010
			return -2;
2011
		}
2012
	}
2013
2014
	/**
2015
	 *  Change the payments terms
2016
	 *
2017
	 *  @param		int		$id		Id of new payment terms
2018
	 *  @return		int				>0 if OK, <0 if KO
2019
	 */
2020
	public function setPaymentTerms($id)
2021
	{
2022
		dol_syslog(get_class($this).'::setPaymentTerms('.$id.')');
2023
		if ($this->statut >= 0 || $this->element == 'societe')
2024
		{
2025
			// TODO uniformize field name
2026
			$fieldname = 'fk_cond_reglement';
2027
			if ($this->element == 'societe') $fieldname = 'cond_reglement';
2028
			if (get_class($this) == 'Fournisseur') $fieldname = 'cond_reglement_supplier';
2029
2030
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2031
			$sql .= ' SET '.$fieldname.' = '.(($id > 0 || $id == '0') ? $id : 'NULL');
2032
			$sql .= ' WHERE rowid='.$this->id;
2033
2034
			if ($this->db->query($sql))
2035
			{
2036
				$this->cond_reglement_id = $id;
2037
				// for supplier
2038
				if (get_class($this) == 'Fournisseur') $this->cond_reglement_supplier_id = $id;
2039
				$this->cond_reglement = $id;	// for compatibility
1 ignored issue
show
Deprecated Code introduced by
The property CommonObject::$cond_reglement has been deprecated: Kept for compatibility ( Ignorable by Annotation )

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

2039
				/** @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...
2040
				return 1;
2041
			}
2042
			else
2043
			{
2044
				dol_syslog(get_class($this).'::setPaymentTerms Erreur '.$sql.' - '.$this->db->error());
2045
				$this->error=$this->db->error();
2046
				return -1;
2047
			}
2048
		}
2049
		else
2050
		{
2051
			dol_syslog(get_class($this).'::setPaymentTerms, status of the object is incompatible');
2052
			$this->error='Status of the object is incompatible '.$this->statut;
2053
			return -2;
2054
		}
2055
	}
2056
	
2057
	/**
2058
	 *  Change the retained warranty payments terms
2059
	 *
2060
	 *  @param		int		$id		Id of new payment terms
2061
	 *  @return		int				>0 if OK, <0 if KO
2062
	 */
2063
	public function setRetainedWarrantyPaymentTerms($id)
2064
	{
2065
	    dol_syslog(get_class($this).'::setRetainedWarrantyPaymentTerms('.$id.')');
2066
	    if ($this->statut >= 0 || $this->element == 'societe')
2067
	    {
2068
	        $fieldname = 'retained_warranty_fk_cond_reglement';
2069
	        
2070
	        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2071
	        $sql .= ' SET '.$fieldname.' = '.$id;
2072
	        $sql .= ' WHERE rowid='.$this->id;
2073
	        
2074
	        if ($this->db->query($sql))
2075
	        {
2076
	            $this->retained_warranty_fk_cond_reglement = $id;
2077
	            return 1;
2078
	        }
2079
	        else
2080
	        {
2081
	            dol_syslog(get_class($this).'::setRetainedWarrantyPaymentTerms Erreur '.$sql.' - '.$this->db->error());
2082
	            $this->error=$this->db->error();
2083
	            return -1;
2084
	        }
2085
	    }
2086
	    else
2087
	    {
2088
	        dol_syslog(get_class($this).'::setRetainedWarrantyPaymentTerms, status of the object is incompatible');
2089
	        $this->error='Status of the object is incompatible '.$this->statut;
2090
	        return -2;
2091
	    }
2092
	}
2093
2094
	/**
2095
	 *	Define delivery address
2096
	 *  @deprecated
2097
	 *
2098
	 *	@param      int		$id		Address id
2099
	 *	@return     int				<0 si ko, >0 si ok
2100
	 */
2101
	public function setDeliveryAddress($id)
2102
	{
2103
		$fieldname = 'fk_delivery_address';
2104
		if ($this->element == 'delivery' || $this->element == 'shipping') $fieldname = 'fk_address';
2105
2106
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET ".$fieldname." = ".$id;
2107
		$sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
2108
2109
		if ($this->db->query($sql))
2110
		{
2111
			$this->fk_delivery_address = $id;
1 ignored issue
show
Deprecated Code introduced by
The property CommonObject::$fk_delivery_address has been deprecated. ( Ignorable by Annotation )

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

2111
			/** @scrutinizer ignore-deprecated */ $this->fk_delivery_address = $id;
Loading history...
2112
			return 1;
2113
		}
2114
		else
2115
		{
2116
			$this->error=$this->db->error();
2117
			dol_syslog(get_class($this).'::setDeliveryAddress Erreur '.$sql.' - '.$this->error);
2118
			return -1;
2119
		}
2120
	}
2121
2122
2123
	/**
2124
	 *  Change the shipping method
2125
	 *
2126
	 *  @param      int     $shipping_method_id     Id of shipping method
2127
	 *  @param      bool    $notrigger              false=launch triggers after, true=disable triggers
2128
	 *  @param      User	$userused               Object user
2129
	 *
2130
	 *  @return     int              1 if OK, 0 if KO
2131
	 */
2132
	public function setShippingMethod($shipping_method_id, $notrigger = false, $userused = null)
2133
	{
2134
		global $user;
2135
2136
		if (empty($userused)) $userused=$user;
2137
2138
		$error = 0;
2139
2140
		if (! $this->table_element) {
2141
			dol_syslog(get_class($this)."::setShippingMethod was called on objet with property table_element not defined", LOG_ERR);
2142
			return -1;
2143
		}
2144
2145
		$this->db->begin();
2146
2147
		if ($shipping_method_id<0) $shipping_method_id='NULL';
2148
		dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')');
2149
2150
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2151
		$sql.= " SET fk_shipping_method = ".$shipping_method_id;
2152
		$sql.= " WHERE rowid=".$this->id;
2153
		$resql = $this->db->query($sql);
2154
		if (! $resql) {
2155
			dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG);
2156
			$this->error = $this->db->lasterror();
2157
			$error++;
2158
		} else {
2159
			if (!$notrigger)
2160
			{
2161
				// Call trigger
2162
				$this->context=array('shippingmethodupdate'=>1);
2163
				$result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2164
				if ($result < 0) $error++;
2165
				// End call trigger
2166
			}
2167
		}
2168
		if ($error)
2169
		{
2170
			$this->db->rollback();
2171
			return -1;
2172
		} else {
2173
			$this->shipping_method_id = ($shipping_method_id=='NULL')?null:$shipping_method_id;
1 ignored issue
show
Documentation Bug introduced by
It seems like $shipping_method_id == '...l : $shipping_method_id can also be of type string. However, the property $shipping_method_id is declared as type integer. Maybe add an additional type check?

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

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

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

class Id
{
    public $id;

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

}

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

$account_id = false;

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

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
2174
			$this->db->commit();
2175
			return 1;
2176
		}
2177
	}
2178
2179
2180
	/**
2181
	 *  Change the warehouse
2182
	 *
2183
	 *  @param      int     $warehouse_id     Id of warehouse
2184
	 *  @return     int              1 if OK, 0 if KO
2185
	 */
2186
	public function setWarehouse($warehouse_id)
2187
	{
2188
		if (! $this->table_element) {
2189
			dol_syslog(get_class($this)."::setWarehouse was called on objet with property table_element not defined", LOG_ERR);
2190
			return -1;
2191
		}
2192
		if ($warehouse_id<0) $warehouse_id='NULL';
2193
		dol_syslog(get_class($this).'::setWarehouse('.$warehouse_id.')');
2194
2195
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2196
		$sql.= " SET fk_warehouse = ".$warehouse_id;
2197
		$sql.= " WHERE rowid=".$this->id;
2198
2199
		if ($this->db->query($sql)) {
2200
			$this->warehouse_id = ($warehouse_id=='NULL')?null:$warehouse_id;
2201
			return 1;
2202
		} else {
2203
			dol_syslog(get_class($this).'::setWarehouse Error ', LOG_DEBUG);
2204
			$this->error=$this->db->error();
2205
			return 0;
2206
		}
2207
	}
2208
2209
2210
	/**
2211
	 *		Set last model used by doc generator
2212
	 *
2213
	 *		@param		User	$user		User object that make change
2214
	 *		@param		string	$modelpdf	Modele name
2215
	 *		@return		int					<0 if KO, >0 if OK
2216
	 */
2217
	public function setDocModel($user, $modelpdf)
2218
	{
2219
		if (! $this->table_element)
2220
		{
2221
			dol_syslog(get_class($this)."::setDocModel was called on objet with property table_element not defined", LOG_ERR);
2222
			return -1;
2223
		}
2224
2225
		$newmodelpdf=dol_trunc($modelpdf, 255);
2226
2227
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2228
		$sql.= " SET model_pdf = '".$this->db->escape($newmodelpdf)."'";
2229
		$sql.= " WHERE rowid = ".$this->id;
2230
		// if ($this->element == 'facture') $sql.= " AND fk_statut < 2";
2231
		// if ($this->element == 'propal')  $sql.= " AND fk_statut = 0";
2232
2233
		dol_syslog(get_class($this)."::setDocModel", LOG_DEBUG);
2234
		$resql=$this->db->query($sql);
2235
		if ($resql)
2236
		{
2237
			$this->modelpdf=$modelpdf;
2238
			return 1;
2239
		}
2240
		else
2241
		{
2242
			dol_print_error($this->db);
2243
			return 0;
2244
		}
2245
	}
2246
2247
2248
	/**
2249
	 *  Change the bank account
2250
	 *
2251
	 *  @param		int		$fk_account		Id of bank account
2252
	 *  @param      bool    $notrigger      false=launch triggers after, true=disable triggers
2253
	 *  @param      User	$userused		Object user
2254
	 *  @return		int				1 if OK, 0 if KO
2255
	 */
2256
	public function setBankAccount($fk_account, $notrigger = false, $userused = null)
2257
	{
2258
		global $user;
2259
2260
		if (empty($userused)) $userused=$user;
2261
2262
		$error = 0;
2263
2264
		if (! $this->table_element) {
2265
			dol_syslog(get_class($this)."::setBankAccount was called on objet with property table_element not defined", LOG_ERR);
2266
			return -1;
2267
		}
2268
		$this->db->begin();
2269
2270
		if ($fk_account<0) $fk_account='NULL';
2271
		dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')');
2272
2273
		$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2274
		$sql.= " SET fk_account = ".$fk_account;
2275
		$sql.= " WHERE rowid=".$this->id;
2276
2277
		$resql = $this->db->query($sql);
2278
		if (! $resql)
2279
		{
2280
			dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error());
2281
			$this->error = $this->db->lasterror();
2282
			$error++;
2283
		}
2284
		else
2285
		{
2286
			if (!$notrigger)
2287
			{
2288
				// Call trigger
2289
				$this->context=array('bankaccountupdate'=>1);
2290
				$result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2291
				if ($result < 0) $error++;
2292
				// End call trigger
2293
			}
2294
		}
2295
		if ($error)
2296
		{
2297
			$this->db->rollback();
2298
			return -1;
2299
		}
2300
		else
2301
		{
2302
			$this->fk_account = ($fk_account=='NULL')?null:$fk_account;
1 ignored issue
show
Documentation Bug introduced by
It seems like $fk_account == 'NULL' ? null : $fk_account can also be of type string. However, the property $fk_account is declared as type integer. Maybe add an additional type check?

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

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

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

class Id
{
    public $id;

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

}

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

$account_id = false;

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

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
2303
			$this->db->commit();
2304
			return 1;
2305
		}
2306
	}
2307
2308
2309
	// TODO: Move line related operations to CommonObjectLine?
2310
2311
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2312
	/**
2313
	 *  Save a new position (field rang) for details lines.
2314
	 *  You can choose to set position for lines with already a position or lines without any position defined.
2315
	 *
2316
	 * 	@param		boolean		$renum			   True to renum all already ordered lines, false to renum only not already ordered lines.
2317
	 * 	@param		string		$rowidorder		   ASC or DESC
2318
	 * 	@param		boolean		$fk_parent_line    Table with fk_parent_line field or not
2319
	 * 	@return		int                            <0 if KO, >0 if OK
2320
	 */
2321
	public function line_order($renum = false, $rowidorder = 'ASC', $fk_parent_line = true)
2322
	{
2323
        // phpcs:enable
2324
		if (! $this->table_element_line)
2325
		{
2326
			dol_syslog(get_class($this)."::line_order was called on objet with property table_element_line not defined", LOG_ERR);
2327
			return -1;
2328
		}
2329
		if (! $this->fk_element)
2330
		{
2331
			dol_syslog(get_class($this)."::line_order was called on objet with property fk_element not defined", LOG_ERR);
2332
			return -1;
2333
		}
2334
2335
		// Count number of lines to reorder (according to choice $renum)
2336
		$nl=0;
2337
		$sql = 'SELECT count(rowid) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2338
		$sql.= ' WHERE '.$this->fk_element.'='.$this->id;
2339
		if (! $renum) $sql.= ' AND rang = 0';
2340
		if ($renum) $sql.= ' AND rang <> 0';
2341
2342
		dol_syslog(get_class($this)."::line_order", LOG_DEBUG);
2343
		$resql = $this->db->query($sql);
2344
		if ($resql)
2345
		{
2346
			$row = $this->db->fetch_row($resql);
2347
			$nl = $row[0];
2348
		}
2349
		else dol_print_error($this->db);
2350
		if ($nl > 0)
2351
		{
2352
			// The goal of this part is to reorder all lines, with all children lines sharing the same
2353
			// counter that parents.
2354
			$rows=array();
2355
2356
			// We first search all lines that are parent lines (for multilevel details lines)
2357
			$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2358
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2359
			if ($fk_parent_line) $sql.= ' AND fk_parent_line IS NULL';
2360
			$sql.= ' ORDER BY rang ASC, rowid '.$rowidorder;
2361
2362
			dol_syslog(get_class($this)."::line_order search all parent lines", LOG_DEBUG);
2363
			$resql = $this->db->query($sql);
2364
			if ($resql)
2365
			{
2366
				$i=0;
2367
				$num = $this->db->num_rows($resql);
2368
				while ($i < $num)
2369
				{
2370
					$row = $this->db->fetch_row($resql);
2371
					$rows[] = $row[0];	// Add parent line into array rows
2372
					$childrens = $this->getChildrenOfLine($row[0]);
2373
					if (! empty($childrens))
2374
					{
2375
						foreach($childrens as $child)
2376
						{
2377
							array_push($rows, $child);
2378
						}
2379
					}
2380
					$i++;
2381
				}
2382
2383
				// Now we set a new number for each lines (parent and children with children included into parent tree)
2384
				if (! empty($rows))
2385
				{
2386
					foreach($rows as $key => $row)
2387
					{
2388
						$this->updateRangOfLine($row, ($key+1));
2389
					}
2390
				}
2391
			}
2392
			else
2393
			{
2394
				dol_print_error($this->db);
2395
			}
2396
		}
2397
		return 1;
2398
	}
2399
2400
	/**
2401
	 * 	Get children of line
2402
	 *
2403
	 * 	@param	int		$id		Id of parent line
2404
	 * 	@return	array			Array with list of children lines id
2405
	 */
2406
	public function getChildrenOfLine($id)
2407
	{
2408
		$rows=array();
2409
2410
		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2411
		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2412
		$sql.= ' AND fk_parent_line = '.$id;
2413
		$sql.= ' ORDER BY rang ASC';
2414
2415
		dol_syslog(get_class($this)."::getChildrenOfLine search children lines for line ".$id."", LOG_DEBUG);
2416
		$resql = $this->db->query($sql);
2417
		if ($resql)
2418
		{
2419
			$i=0;
2420
			$num = $this->db->num_rows($resql);
2421
			while ($i < $num)
2422
			{
2423
				$row = $this->db->fetch_row($resql);
2424
				$rows[$i] = $row[0];
2425
				$i++;
2426
			}
2427
		}
2428
2429
		return $rows;
2430
	}
2431
2432
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2433
	/**
2434
	 * 	Update a line to have a lower rank
2435
	 *
2436
	 * 	@param 	int			$rowid				Id of line
2437
	 * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2438
	 * 	@return	void
2439
	 */
2440
	public function line_up($rowid, $fk_parent_line = true)
2441
	{
2442
        // phpcs:enable
2443
		$this->line_order(false, 'ASC', $fk_parent_line);
2444
2445
		// Get rang of line
2446
		$rang = $this->getRangOfLine($rowid);
2447
2448
		// Update position of line
2449
		$this->updateLineUp($rowid, $rang);
2450
	}
2451
2452
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2453
	/**
2454
	 * 	Update a line to have a higher rank
2455
	 *
2456
	 * 	@param	int			$rowid				Id of line
2457
	 * 	@param	boolean		$fk_parent_line		Table with fk_parent_line field or not
2458
	 * 	@return	void
2459
	 */
2460
	public function line_down($rowid, $fk_parent_line = true)
2461
	{
2462
        // phpcs:enable
2463
		$this->line_order(false, 'ASC', $fk_parent_line);
2464
2465
		// Get rang of line
2466
		$rang = $this->getRangOfLine($rowid);
2467
2468
		// Get max value for rang
2469
		$max = $this->line_max();
2470
2471
		// Update position of line
2472
		$this->updateLineDown($rowid, $rang, $max);
2473
	}
2474
2475
	/**
2476
	 * 	Update position of line (rang)
2477
	 *
2478
	 * 	@param	int		$rowid		Id of line
2479
	 * 	@param	int		$rang		Position
2480
	 * 	@return	void
2481
	 */
2482
	public function updateRangOfLine($rowid, $rang)
2483
	{
2484
		$fieldposition = 'rang';	// @TODO Rename 'rang' into 'position'
2485
		if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2486
		if (in_array($this->table_element_line, array('bom_bomline'))) $fieldposition = 'position';
2487
2488
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2489
		$sql.= ' WHERE rowid = '.$rowid;
2490
2491
		dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
2492
		if (! $this->db->query($sql))
2493
		{
2494
			dol_print_error($this->db);
2495
		}
2496
	}
2497
2498
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2499
	/**
2500
	 * 	Update position of line with ajax (rang)
2501
	 *
2502
	 * 	@param	array	$rows	Array of rows
2503
	 * 	@return	void
2504
	 */
2505
	public function line_ajaxorder($rows)
2506
	{
2507
        // phpcs:enable
2508
		$num = count($rows);
2509
		for ($i = 0 ; $i < $num ; $i++)
2510
		{
2511
			$this->updateRangOfLine($rows[$i], ($i+1));
2512
		}
2513
	}
2514
2515
	/**
2516
	 * 	Update position of line up (rang)
2517
	 *
2518
	 * 	@param	int		$rowid		Id of line
2519
	 * 	@param	int		$rang		Position
2520
	 * 	@return	void
2521
	 */
2522
	public function updateLineUp($rowid, $rang)
2523
	{
2524
		if ($rang > 1)
2525
		{
2526
			$fieldposition = 'rang';
2527
			if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2528
2529
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang ;
2530
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2531
			$sql.= ' AND rang = '.($rang - 1);
2532
			if ($this->db->query($sql) )
2533
			{
2534
				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang - 1);
2535
				$sql.= ' WHERE rowid = '.$rowid;
2536
				if (! $this->db->query($sql) )
2537
				{
2538
					dol_print_error($this->db);
2539
				}
2540
			}
2541
			else
2542
			{
2543
				dol_print_error($this->db);
2544
			}
2545
		}
2546
	}
2547
2548
	/**
2549
	 * 	Update position of line down (rang)
2550
	 *
2551
	 * 	@param	int		$rowid		Id of line
2552
	 * 	@param	int		$rang		Position
2553
	 * 	@param	int		$max		Max
2554
	 * 	@return	void
2555
	 */
2556
	public function updateLineDown($rowid, $rang, $max)
2557
	{
2558
		if ($rang < $max)
2559
		{
2560
			$fieldposition = 'rang';
2561
			if (in_array($this->table_element_line, array('ecm_files', 'emailcollector_emailcollectoraction'))) $fieldposition = 'position';
2562
2563
			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang;
2564
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2565
			$sql.= ' AND rang = '.($rang+1);
2566
			if ($this->db->query($sql) )
2567
			{
2568
				$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.($rang+1);
2569
				$sql.= ' WHERE rowid = '.$rowid;
2570
				if (! $this->db->query($sql) )
2571
				{
2572
					dol_print_error($this->db);
2573
				}
2574
			}
2575
			else
2576
			{
2577
				dol_print_error($this->db);
2578
			}
2579
		}
2580
	}
2581
2582
	/**
2583
	 * 	Get position of line (rang)
2584
	 *
2585
	 * 	@param		int		$rowid		Id of line
2586
	 *  @return		int     			Value of rang in table of lines
2587
	 */
2588
	public function getRangOfLine($rowid)
2589
	{
2590
		$sql = 'SELECT rang FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2591
		$sql.= ' WHERE rowid ='.$rowid;
2592
2593
		dol_syslog(get_class($this)."::getRangOfLine", LOG_DEBUG);
2594
		$resql = $this->db->query($sql);
2595
		if ($resql)
2596
		{
2597
			$row = $this->db->fetch_row($resql);
2598
			return $row[0];
2599
		}
2600
	}
2601
2602
	/**
2603
	 * 	Get rowid of the line relative to its position
2604
	 *
2605
	 * 	@param		int		$rang		Rang value
2606
	 *  @return     int     			Rowid of the line
2607
	 */
2608
	public function getIdOfLine($rang)
2609
	{
2610
		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2611
		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2612
		$sql.= ' AND rang = '.$rang;
2613
		$resql = $this->db->query($sql);
2614
		if ($resql)
2615
		{
2616
			$row = $this->db->fetch_row($resql);
2617
			return $row[0];
2618
		}
2619
	}
2620
2621
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2622
	/**
2623
	 * 	Get max value used for position of line (rang)
2624
	 *
2625
	 * 	@param		int		$fk_parent_line		Parent line id
2626
	 *  @return     int  			   			Max value of rang in table of lines
2627
	 */
2628
	public function line_max($fk_parent_line = 0)
2629
	{
2630
        // phpcs:enable
2631
		// Search the last rang with fk_parent_line
2632
		if ($fk_parent_line)
2633
		{
2634
			$sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2635
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2636
			$sql.= ' AND fk_parent_line = '.$fk_parent_line;
2637
2638
			dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2639
			$resql = $this->db->query($sql);
2640
			if ($resql)
2641
			{
2642
				$row = $this->db->fetch_row($resql);
2643
				if (! empty($row[0]))
2644
				{
2645
					return $row[0];
2646
				}
2647
				else
2648
				{
2649
					return $this->getRangOfLine($fk_parent_line);
2650
				}
2651
			}
2652
		}
2653
		// If not, search the last rang of element
2654
		else
2655
		{
2656
			$sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2657
			$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2658
2659
			dol_syslog(get_class($this)."::line_max", LOG_DEBUG);
2660
			$resql = $this->db->query($sql);
2661
			if ($resql)
2662
			{
2663
				$row = $this->db->fetch_row($resql);
2664
				return $row[0];
2665
			}
2666
		}
2667
	}
2668
2669
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2670
	/**
2671
	 *  Update external ref of element
2672
	 *
2673
	 *  @param      string		$ref_ext	Update field ref_ext
2674
	 *  @return     int      		   		<0 if KO, >0 if OK
2675
	 */
2676
	public function update_ref_ext($ref_ext)
2677
	{
2678
        // phpcs:enable
2679
		if (! $this->table_element)
2680
		{
2681
			dol_syslog(get_class($this)."::update_ref_ext was called on objet with property table_element not defined", LOG_ERR);
2682
			return -1;
2683
		}
2684
2685
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2686
		$sql.= " SET ref_ext = '".$this->db->escape($ref_ext)."'";
2687
		$sql.= " WHERE ".(isset($this->table_rowid)?$this->table_rowid:'rowid')." = ". $this->id;
2688
2689
		dol_syslog(get_class($this)."::update_ref_ext", LOG_DEBUG);
2690
		if ($this->db->query($sql))
2691
		{
2692
			$this->ref_ext = $ref_ext;
2693
			return 1;
2694
		}
2695
		else
2696
		{
2697
			$this->error=$this->db->error();
2698
			return -1;
2699
		}
2700
	}
2701
2702
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2703
	/**
2704
	 *  Update note of element
2705
	 *
2706
	 *  @param      string		$note		New value for note
2707
	 *  @param		string		$suffix		'', '_public' or '_private'
2708
	 *  @return     int      		   		<0 if KO, >0 if OK
2709
	 */
2710
	public function update_note($note, $suffix = '')
2711
	{
2712
        // phpcs:enable
2713
		global $user;
2714
2715
		if (! $this->table_element)
2716
		{
2717
			$this->error='update_note was called on objet with property table_element not defined';
2718
			dol_syslog(get_class($this)."::update_note was called on objet with property table_element not defined", LOG_ERR);
2719
			return -1;
2720
		}
2721
		if (! in_array($suffix, array('','_public','_private')))
2722
		{
2723
			$this->error='update_note Parameter suffix must be empty, \'_private\' or \'_public\'';
2724
			dol_syslog(get_class($this)."::update_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR);
2725
			return -2;
2726
		}
2727
		// Special cas
2728
		//var_dump($this->table_element);exit;
2729
		if ($this->table_element == 'product') $suffix='';
2730
2731
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2732
		$sql.= " SET note".$suffix." = ".(!empty($note)?("'".$this->db->escape($note)."'"):"NULL");
2733
		$sql.= " ,".(in_array($this->table_element, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))?"fk_user_mod":"fk_user_modif")." = ".$user->id;
2734
		$sql.= " WHERE rowid =". $this->id;
2735
2736
		dol_syslog(get_class($this)."::update_note", LOG_DEBUG);
2737
		if ($this->db->query($sql))
2738
		{
2739
			if ($suffix == '_public') $this->note_public = $note;
2740
			elseif ($suffix == '_private') $this->note_private = $note;
2741
			else
2742
			{
2743
				$this->note = $note;      // deprecated
1 ignored issue
show
Deprecated Code introduced by
The property CommonObject::$note has been deprecated. ( Ignorable by Annotation )

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

2743
				/** @scrutinizer ignore-deprecated */ $this->note = $note;      // deprecated
Loading history...
2744
				$this->note_private = $note;
2745
			}
2746
			return 1;
2747
		}
2748
		else
2749
		{
2750
			$this->error=$this->db->lasterror();
2751
			return -1;
2752
		}
2753
	}
2754
2755
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2756
	/**
2757
	 * 	Update public note (kept for backward compatibility)
2758
	 *
2759
	 * @param      string		$note		New value for note
2760
	 * @return     int      		   		<0 if KO, >0 if OK
2761
	 * @deprecated
2762
	 * @see update_note()
2763
	 */
2764
	public function update_note_public($note)
2765
	{
2766
        // phpcs:enable
2767
		return $this->update_note($note, '_public');
2768
	}
2769
2770
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2771
	/**
2772
	 *	Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
2773
	 *  Must be called at end of methods addline or updateline.
2774
	 *
2775
	 *	@param	int		$exclspec          	>0 = Exclude special product (product_type=9)
2776
	 *  @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
2777
	 *  @param	int		$nodatabaseupdate	1=Do not update database. Update only properties of object.
2778
	 *  @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.
2779
	 *	@return	int    			           	<0 if KO, >0 if OK
2780
	 */
2781
	public function update_price($exclspec = 0, $roundingadjust = 'none', $nodatabaseupdate = 0, $seller = null)
2782
	{
2783
        // phpcs:enable
2784
		global $conf, $hookmanager, $action;
2785
2786
		// Some external module want no update price after a trigger because they have another method to calculate the total (ex: with an extrafield)
2787
		$MODULE = "";
2788
		if ($this->element == 'propal')
2789
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_PROPOSAL";
2790
		elseif ($this->element == 'commande' || $this->element == 'order')
2791
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER";
2792
		elseif ($this->element == 'facture')
2793
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE";
2794
		elseif ($this->element == 'facture_fourn')
2795
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE";
2796
		elseif ($this->element == 'order_supplier')
2797
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER";
2798
		elseif ($this->element == 'supplier_proposal')
2799
			$MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_PROPOSAL";
2800
2801
		if (! empty($MODULE)) {
2802
			if (! empty($conf->global->$MODULE)) {
2803
				$modsactivated = explode(',', $conf->global->$MODULE);
2804
				foreach ($modsactivated as $mod) {
2805
					if ($conf->$mod->enabled)
2806
						return 1; // update was disabled by specific setup
2807
				}
2808
			}
2809
		}
2810
2811
		include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2812
2813
		if ($roundingadjust == '-1') $roundingadjust='auto';	// For backward compatibility
2814
2815
		$forcedroundingmode=$roundingadjust;
2816
		if ($forcedroundingmode == 'auto' && isset($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)) $forcedroundingmode=$conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND;
2817
		elseif ($forcedroundingmode == 'auto') $forcedroundingmode='0';
2818
2819
		$error=0;
2820
2821
		$multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1;
2822
2823
		// Define constants to find lines to sum
2824
		$fieldtva='total_tva';
2825
		$fieldlocaltax1='total_localtax1';
2826
		$fieldlocaltax2='total_localtax2';
2827
		$fieldup='subprice';
2828
		if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier')
2829
		{
2830
			$fieldtva='tva';
2831
			$fieldup='pu_ht';
2832
		}
2833
		if ($this->element == 'expensereport')
2834
		{
2835
			$fieldup='value_unit';
2836
		}
2837
2838
		$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,';
2839
		$sql.= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type';
2840
			if ($this->table_element_line == 'facturedet') $sql.= ', situation_percent';
2841
			$sql.= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
2842
		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line;
2843
		$sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
2844
		if ($exclspec)
2845
		{
2846
			$product_field='product_type';
2847
			if ($this->table_element_line == 'contratdet') $product_field='';    // contratdet table has no product_type field
2848
			if ($product_field) $sql.= ' AND '.$product_field.' <> 9';
2849
		}
2850
		$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
2851
2852
		dol_syslog(get_class($this)."::update_price", LOG_DEBUG);
2853
		$resql = $this->db->query($sql);
2854
		if ($resql)
2855
		{
2856
			$this->total_ht  = 0;
2857
			$this->total_tva = 0;
2858
			$this->total_localtax1 = 0;
2859
			$this->total_localtax2 = 0;
2860
			$this->total_ttc = 0;
2861
			$total_ht_by_vats  = array();
2862
			$total_tva_by_vats = array();
2863
			$total_ttc_by_vats = array();
2864
			$this->multicurrency_total_ht	= 0;
2865
			$this->multicurrency_total_tva	= 0;
2866
			$this->multicurrency_total_ttc	= 0;
2867
2868
			$num = $this->db->num_rows($resql);
2869
			$i = 0;
2870
			while ($i < $num)
2871
			{
2872
				$obj = $this->db->fetch_object($resql);
2873
2874
				// Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none'
2875
				$parameters=array('fk_element' => $obj->rowid);
2876
				$reshook = $hookmanager->executeHooks('changeRoundingMode', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2877
2878
				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'
2879
				{
2880
					$localtax_array=array($obj->localtax1_type,$obj->localtax1_tx,$obj->localtax2_type,$obj->localtax2_tx);
2881
					$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);
2882
					$diff=price2num($tmpcal[1] - $obj->total_tva, 'MT', 1);
2883
					if ($diff)
2884
					{
2885
						$sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".$tmpcal[1].", total_ttc = ".$tmpcal[2]." WHERE rowid = ".$obj->rowid;
2886
						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);
2887
								$resqlfix=$this->db->query($sqlfix);
2888
								if (! $resqlfix) dol_print_error($this->db, 'Failed to update line');
2889
								$obj->total_tva = $tmpcal[1];
2890
								$obj->total_ttc = $tmpcal[2];
2891
						//
2892
					}
2893
				}
2894
2895
				$this->total_ht        += $obj->total_ht;		// The field visible at end of line detail
2896
				$this->total_tva       += $obj->total_tva;
2897
				$this->total_localtax1 += $obj->total_localtax1;
2898
				$this->total_localtax2 += $obj->total_localtax2;
2899
				$this->total_ttc       += $obj->total_ttc;
2900
				$this->multicurrency_total_ht        += $obj->multicurrency_total_ht;		// The field visible at end of line detail
2901
				$this->multicurrency_total_tva       += $obj->multicurrency_total_tva;
2902
				$this->multicurrency_total_ttc       += $obj->multicurrency_total_ttc;
2903
2904
				if (! isset($total_ht_by_vats[$obj->vatrate]))  $total_ht_by_vats[$obj->vatrate]=0;
2905
				if (! isset($total_tva_by_vats[$obj->vatrate])) $total_tva_by_vats[$obj->vatrate]=0;
2906
				if (! isset($total_ttc_by_vats[$obj->vatrate])) $total_ttc_by_vats[$obj->vatrate]=0;
2907
				$total_ht_by_vats[$obj->vatrate]  += $obj->total_ht;
2908
				$total_tva_by_vats[$obj->vatrate] += $obj->total_tva;
2909
				$total_ttc_by_vats[$obj->vatrate] += $obj->total_ttc;
2910
2911
				if ($forcedroundingmode == '1')	// Check if we need adjustement onto line for vat. TODO This works on the company currency but not on multicurrency
2912
				{
2913
					$tmpvat=price2num($total_ht_by_vats[$obj->vatrate] * $obj->vatrate / 100, 'MT', 1);
2914
					$diff=price2num($total_tva_by_vats[$obj->vatrate]-$tmpvat, 'MT', 1);
2915
					//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";
2916
					if ($diff)
2917
					{
2918
						if (abs($diff) > 0.1) { dol_syslog('A rounding difference was detected into TOTAL but is too high to be corrected', LOG_WARNING); exit; }
1 ignored issue
show
Best Practice introduced by
Using exit here is not recommended.

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

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

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

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

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

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

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

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

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

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
7178
				} else {
7179
					$this->{$field} = array();
7180
				}
7181
			}
7182
			elseif($this->isInt($info))
7183
			{
7184
				if ($field == 'rowid') $this->id = (int) $obj->{$field};
7185
				else $this->{$field} = (int) $obj->{$field};
7186
			}
7187
			elseif($this->isFloat($info))
7188
			{
7189
				$this->{$field} = (double) $obj->{$field};
7190
			}
7191
			elseif($this->isNull($info))
7192
			{
7193
				$val = $obj->{$field};
7194
				// zero is not null
7195
				$this->{$field} = (is_null($val) || (empty($val) && $val!==0 && $val!=='0') ? null : $val);
7196
			}
7197
			else
7198
			{
7199
				$this->{$field} = $obj->{$field};
7200
			}
7201
		}
7202
7203
		// If there is no 'ref' field, we force property ->ref to ->id for a better compatibility with common functions.
7204
		if (! isset($this->fields['ref']) && isset($this->id)) $this->ref = $this->id;
7205
	}
7206
7207
	/**
7208
	 * Function to concat keys of fields
7209
	 *
7210
	 * @return string
7211
	 */
7212
	protected function getFieldList()
7213
	{
7214
		$keys = array_keys($this->fields);
7215
		return implode(',', $keys);
7216
	}
7217
7218
	/**
7219
	 * Add quote to field value if necessary
7220
	 *
7221
	 * @param 	string|int	$value			Value to protect
7222
	 * @param	array		$fieldsentry	Properties of field
7223
	 * @return 	string
7224
	 */
7225
	protected function quote($value, $fieldsentry)
7226
	{
7227
		if (is_null($value)) return 'NULL';
1 ignored issue
show
introduced by
The condition is_null($value) is always false.
Loading history...
7228
		elseif (preg_match('/^(int|double|real)/i', $fieldsentry['type'])) return $this->db->escape("$value");
7229
		else return "'".$this->db->escape($value)."'";
7230
	}
7231
7232
7233
	/**
7234
	 * Create object into database
7235
	 *
7236
	 * @param  User $user      User that creates
7237
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
7238
	 * @return int             <0 if KO, Id of created object if OK
7239
	 */
7240
	public function createCommon(User $user, $notrigger = false)
7241
	{
7242
		global $langs;
7243
7244
		$error = 0;
7245
7246
		$now=dol_now();
7247
7248
		$fieldvalues = $this->setSaveQuery();
7249
		if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) $fieldvalues['date_creation']=$this->db->idate($now);
7250
		if (array_key_exists('fk_user_creat', $fieldvalues) && ! ($fieldvalues['fk_user_creat'] > 0)) $fieldvalues['fk_user_creat']=$user->id;
7251
		unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into insert.
7252
7253
		$keys=array();
7254
		$values = array();
7255
		foreach ($fieldvalues as $k => $v) {
7256
			$keys[$k] = $k;
7257
			$value = $this->fields[$k];
7258
			$values[$k] = $this->quote($v, $value);
7259
		}
7260
7261
		// Clean and check mandatory
7262
		foreach($keys as $key)
7263
		{
7264
			// If field is an implicit foreign key field
7265
			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';
7266
			if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';
7267
7268
			//var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7269
			if (isset($this->fields[$key]['notnull']) && $this->fields[$key]['notnull'] == 1 && ! isset($values[$key]) && is_null($val['default']))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $val does not exist. Did you maybe mean $value?
Loading history...
7270
			{
7271
				$error++;
7272
				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7273
			}
7274
7275
			// If field is an implicit foreign key field
7276
			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && empty($values[$key])) $values[$key]='null';
7277
			if (! empty($this->fields[$key]['foreignkey']) && empty($values[$key])) $values[$key]='null';
7278
		}
7279
7280
		if ($error) return -1;
7281
7282
		$this->db->begin();
7283
7284
		if (! $error)
7285
		{
7286
			$sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
7287
			$sql.= ' ('.implode(", ", $keys).')';
7288
			$sql.= ' VALUES ('.implode(", ", $values).')';
7289
7290
			$res = $this->db->query($sql);
7291
			if ($res===false) {
0 ignored issues
show
introduced by
The condition $res === false is always false.
Loading history...
7292
				$error++;
7293
				$this->errors[] = $this->db->lasterror();
7294
			}
7295
		}
7296
7297
		if (! $error)
7298
		{
7299
			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
7300
		}
7301
7302
		// If we have a field ref with a default value of (PROV)
7303
		if (! $error)
7304
		{
7305
		    if (key_exists('ref', $this->fields) && $this->fields['ref']['notnull'] > 0 && ! is_null($this->fields['ref']['default']) && $this->fields['ref']['default'] == '(PROV)')
7306
		    {
7307
		        $sql="UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET ref = '(PROV".$this->id.")' WHERE ref = '(PROV)' AND rowid = ".$this->id;
7308
		        $resqlupdate = $this->db->query($sql);
7309
		        if ($resqlupdate===false)
0 ignored issues
show
introduced by
The condition $resqlupdate === false is always false.
Loading history...
7310
		        {
7311
		            $error++;
7312
		            $this->errors[] = $this->db->lasterror();
7313
		        }
7314
		    }
7315
		}
7316
7317
		// Create extrafields
7318
		if (! $error)
7319
		{
7320
			$result=$this->insertExtraFields();
7321
			if ($result < 0) $error++;
7322
		}
7323
7324
		// Create lines
7325
		if (! empty($this->table_element_line) && ! empty($this->fk_element))
7326
		{
7327
			$num=(is_array($this->lines) ? count($this->lines) : 0);
1 ignored issue
show
introduced by
The condition is_array($this->lines) is always true.
Loading history...
7328
			for ($i = 0; $i < $num; $i++)
7329
			{
7330
				$line = $this->lines[$i];
7331
7332
				$keyforparent = $this->fk_element;
7333
				$line->$keyforparent = $this->id;
7334
7335
				// Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
7336
				//if (! is_object($line)) $line=json_decode(json_encode($line), false);  // convert recursively array into object.
7337
				if (! is_object($line)) $line = (object) $line;
7338
7339
				$result = $line->create($user, 1);
7340
				if ($result < 0)
7341
				{
7342
					$this->error=$this->db->lasterror();
7343
					$this->db->rollback();
7344
					return -1;
7345
				}
7346
			}
7347
		}
7348
7349
		// Triggers
7350
		if (! $error && ! $notrigger)
7351
		{
7352
			// Call triggers
7353
			$result=$this->call_trigger(strtoupper(get_class($this)).'_CREATE', $user);
7354
			if ($result < 0) { $error++; }
7355
			// End call triggers
7356
		}
7357
7358
		// Commit or rollback
7359
		if ($error) {
7360
			$this->db->rollback();
7361
			return -1;
7362
		} else {
7363
			$this->db->commit();
7364
			return $this->id;
7365
		}
7366
	}
7367
7368
7369
	/**
7370
	 * Load object in memory from the database
7371
	 *
7372
	 * @param	int    $id				Id object
7373
	 * @param	string $ref				Ref
7374
	 * @param	string	$morewhere		More SQL filters (' AND ...')
7375
	 * @return 	int         			<0 if KO, 0 if not found, >0 if OK
7376
	 */
7377
	public function fetchCommon($id, $ref = null, $morewhere = '')
7378
	{
7379
		if (empty($id) && empty($ref) && empty($morewhere)) return -1;
7380
7381
		$sql = 'SELECT '.$this->getFieldList();
7382
		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
7383
7384
		if (!empty($id))  $sql.= ' WHERE rowid = '.$id;
7385
		elseif (!empty($ref)) $sql.= " WHERE ref = ".$this->quote($ref, $this->fields['ref']);
7386
		else $sql.=' WHERE 1 = 1';	// usage with empty id and empty ref is very rare
7387
		if ($morewhere)   $sql.= $morewhere;
7388
		$sql.=' LIMIT 1';	// This is a fetch, to be sure to get only one record
7389
7390
		$res = $this->db->query($sql);
7391
		if ($res)
7392
		{
7393
			$obj = $this->db->fetch_object($res);
7394
			if ($obj)
7395
			{
7396
				$this->setVarsFromFetchObj($obj);
7397
				return $this->id;
7398
			}
7399
			else
7400
			{
7401
				return 0;
7402
			}
7403
		}
7404
		else
7405
		{
7406
			$this->error = $this->db->lasterror();
7407
			$this->errors[] = $this->error;
7408
			return -1;
7409
		}
7410
	}
7411
7412
	/**
7413
	 * Load object in memory from the database
7414
	 *
7415
	 * @param	string	$morewhere		More SQL filters (' AND ...')
7416
	 * @return 	int         			<0 if KO, 0 if not found, >0 if OK
7417
	 */
7418
	public function fetchLinesCommon($morewhere = '')
7419
	{
7420
		$objectlineclassname = get_class($this).'Line';
7421
		if (! class_exists($objectlineclassname))
7422
		{
7423
			$this->error = 'Error, class '.$objectlineclassname.' not found during call of fetchLinesCommon';
7424
			return -1;
7425
		}
7426
7427
		$objectline = new $objectlineclassname($this->db);
7428
7429
		$sql = 'SELECT '.$objectline->getFieldList();
7430
		$sql.= ' FROM '.MAIN_DB_PREFIX.$objectline->table_element;
7431
		$sql.=' WHERE fk_'.$this->element.' = '.$this->id;
7432
		if ($morewhere)   $sql.= $morewhere;
7433
7434
		$resql = $this->db->query($sql);
7435
		if ($resql)
7436
		{
7437
			$num_rows = $this->db->num_rows($resql);
7438
			$i = 0;
7439
			while ($i < $num_rows)
7440
			{
7441
				$obj = $this->db->fetch_object($resql);
7442
				if ($obj)
7443
				{
7444
					$newline = new $objectlineclassname($this->db);
7445
					$newline->setVarsFromFetchObj($obj);
7446
7447
					$this->lines[] = $newline;
7448
				}
7449
				$i++;
7450
			}
7451
7452
			return 1;
7453
		}
7454
		else
7455
		{
7456
			$this->error = $this->db->lasterror();
7457
			$this->errors[] = $this->error;
7458
			return -1;
7459
		}
7460
	}
7461
7462
	/**
7463
	 * Update object into database
7464
	 *
7465
	 * @param  User $user      	User that modifies
7466
	 * @param  bool $notrigger 	false=launch triggers after, true=disable triggers
7467
	 * @return int             	<0 if KO, >0 if OK
7468
	 */
7469
	public function updateCommon(User $user, $notrigger = false)
7470
	{
7471
		global $conf, $langs;
7472
7473
		$error = 0;
7474
7475
		$now=dol_now();
7476
7477
		$fieldvalues = $this->setSaveQuery();
7478
		if (array_key_exists('date_modification', $fieldvalues) && empty($fieldvalues['date_modification'])) $fieldvalues['date_modification']=$this->db->idate($now);
7479
		if (array_key_exists('fk_user_modif', $fieldvalues) && ! ($fieldvalues['fk_user_modif'] > 0)) $fieldvalues['fk_user_modif']=$user->id;
7480
		unset($fieldvalues['rowid']);	// The field 'rowid' is reserved field name for autoincrement field so we don't need it into update.
7481
7482
		$keys=array();
7483
		$values = array();
7484
		foreach ($fieldvalues as $k => $v) {
7485
			$keys[$k] = $k;
7486
			$value = $this->fields[$k];
7487
			$values[$k] = $this->quote($v, $value);
7488
			$tmp[] = $k.'='.$this->quote($v, $this->fields[$k]);
7489
		}
7490
7491
		// Clean and check mandatory
7492
		foreach($keys as $key)
7493
		{
7494
			if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]='';		// This is an implicit foreign key field
7495
			if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]='';					// This is an explicit foreign key field
7496
7497
			//var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
7498
			/*
7499
			if ($this->fields[$key]['notnull'] == 1 && empty($values[$key]))
7500
			{
7501
				$error++;
7502
				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
7503
			}*/
7504
		}
7505
7506
		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET '.implode(',', $tmp).' WHERE rowid='.$this->id ;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tmp seems to be defined by a foreach iteration on line 7484. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
7507
7508
		$this->db->begin();
7509
		if (! $error)
7510
		{
7511
			$res = $this->db->query($sql);
7512
			if ($res===false)
0 ignored issues
show
introduced by
The condition $res === false is always false.
Loading history...
7513
			{
7514
				$error++;
7515
				$this->errors[] = $this->db->lasterror();
7516
			}
7517
		}
7518
7519
		// Update extrafield
7520
		if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options)>0)
7521
		{
7522
			$result=$this->insertExtraFields();
7523
			if ($result < 0)
7524
			{
7525
				$error++;
7526
			}
7527
		}
7528
7529
		// Triggers
7530
		if (! $error && ! $notrigger)
7531
		{
7532
			// Call triggers
7533
			$result=$this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $user);
7534
			if ($result < 0) { $error++; } //Do also here what you must do to rollback action if trigger fail
7535
			// End call triggers
7536
		}
7537
7538
		// Commit or rollback
7539
		if ($error) {
7540
			$this->db->rollback();
7541
			return -1;
7542
		} else {
7543
			$this->db->commit();
7544
			return $this->id;
7545
		}
7546
	}
7547
7548
	/**
7549
	 * Delete object in database
7550
	 *
7551
	 * @param 	User 	$user       			User that deletes
7552
	 * @param 	bool 	$notrigger  			false=launch triggers after, true=disable triggers
7553
	 * @param	int		$forcechilddeletion		0=no, 1=Force deletion of children
7554
	 * @return 	int             				<=0 if KO, >0 if OK
7555
	 */
7556
	public function deleteCommon(User $user, $notrigger = false, $forcechilddeletion = 0)
7557
	{
7558
		$error=0;
7559
7560
		$this->db->begin();
7561
7562
		if ($forcechilddeletion)	// Force also delete of childtables that should lock deletion in standard case when option force is off
7563
		{
7564
			foreach($this->childtables as $table)
7565
			{
7566
				$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$table.' WHERE '.$this->fk_element.' = '.$this->id;
7567
				$resql = $this->db->query($sql);
7568
				if (! $resql)
7569
				{
7570
					$this->error=$this->db->lasterror();
7571
					$this->errors[]=$this->error;
7572
					$this->db->rollback();
7573
					return -1;
7574
				}
7575
			}
7576
		}
7577
		elseif (! empty($this->fk_element) && ! empty($this->childtables))	// If object has childs linked with a foreign key field, we check all child tables.
7578
		{
7579
			$objectisused = $this->isObjectUsed($this->id);
7580
			if (! empty($objectisused))
7581
			{
7582
				dol_syslog(get_class($this)."::deleteCommon Can't delete record as it has some child", LOG_WARNING);
7583
				$this->error='ErrorRecordHasChildren';
7584
				$this->errors[]=$this->error;
7585
				$this->db->rollback();
7586
				return 0;
7587
			}
7588
		}
7589
7590
		// Delete cascade first
7591
		foreach($this->childtablesoncascade as $table)
7592
		{
7593
			$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$table.' WHERE '.$this->fk_element.' = '.$this->id;
7594
			$resql = $this->db->query($sql);
7595
			if (! $resql)
7596
			{
7597
				$this->error=$this->db->lasterror();
7598
				$this->errors[]=$this->error;
7599
				$this->db->rollback();
7600
				return -1;
7601
			}
7602
		}
7603
7604
		if (! $error) {
7605
			if (! $notrigger) {
7606
				// Call triggers
7607
				$result=$this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user);
7608
				if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
7609
				// End call triggers
7610
			}
7611
		}
7612
7613
		if (! $error && ! empty($this->isextrafieldmanaged))
7614
		{
7615
			$sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element."_extrafields";
7616
			$sql.= " WHERE fk_object=" . $this->id;
7617
7618
			$resql = $this->db->query($sql);
7619
			if (! $resql)
7620
			{
7621
				$this->errors[] = $this->db->lasterror();
7622
				$error++;
7623
			}
7624
		}
7625
7626
		if (! $error)
7627
		{
7628
			$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
7629
7630
			$res = $this->db->query($sql);
7631
			if($res===false) {
0 ignored issues
show
introduced by
The condition $res === false is always false.
Loading history...
7632
				$error++;
7633
				$this->errors[] = $this->db->lasterror();
7634
			}
7635
		}
7636
7637
		// Commit or rollback
7638
		if ($error) {
7639
			$this->db->rollback();
7640
			return -1;
7641
		} else {
7642
			$this->db->commit();
7643
			return 1;
7644
		}
7645
	}
7646
7647
	/**
7648
	 *  Delete a line of object in database
7649
	 *
7650
	 *	@param  User	$user       User that delete
7651
	 *  @param	int		$idline		Id of line to delete
7652
	 *  @param 	bool 	$notrigger  false=launch triggers after, true=disable triggers
7653
	 *  @return int         		>0 if OK, <0 if KO
7654
	 */
7655
	public function deleteLineCommon(User $user, $idline, $notrigger = false)
7656
	{
7657
		global $conf;
7658
7659
		$error=0;
7660
7661
		$tmpforobjectclass = get_class($this);
7662
		$tmpforobjectlineclass = ucfirst($tmpforobjectclass).'Line';
7663
7664
		// Call trigger
7665
		$result=$this->call_trigger('LINE'.strtoupper($tmpforobjectclass).'_DELETE', $user);
7666
		if ($result < 0) return -1;
7667
		// End call triggers
7668
7669
		$this->db->begin();
7670
7671
		$sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element_line;
7672
		$sql.= " WHERE rowid=".$idline;
7673
7674
		dol_syslog(get_class($this)."::deleteLineCommon", LOG_DEBUG);
7675
		$resql = $this->db->query($sql);
7676
		if (! $resql)
7677
		{
7678
			$this->error="Error ".$this->db->lasterror();
7679
			$error++;
7680
		}
7681
7682
		if (empty($error)) {
7683
			// Remove extrafields
7684
			if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
7685
			{
7686
				$tmpobjectline = new $tmpforobjectlineclass($this->db);
7687
				$tmpobjectline->id= $idline;
7688
				$result=$tmpobjectline->deleteExtraFields();
7689
				if ($result < 0)
7690
				{
7691
					$error++;
7692
					$this->error="Error ".get_class($this)."::deleteLineCommon deleteExtraFields error -4 ".$tmpobjectline->error;
7693
				}
7694
			}
7695
		}
7696
7697
		if (empty($error)) {
7698
			$this->db->commit();
7699
			return 1;
7700
		} else {
7701
			dol_syslog(get_class($this)."::deleteLineCommon ERROR:".$this->error, LOG_ERR);
7702
			$this->db->rollback();
7703
			return -1;
7704
		}
7705
	}
7706
7707
	/**
7708
	 * Initialise object with example values
7709
	 * Id must be 0 if object instance is a specimen
7710
	 *
7711
	 * @return void
7712
	 */
7713
	public function initAsSpecimenCommon()
7714
	{
7715
	    global $user;
7716
7717
		$this->id = 0;
7718
		if (array_key_exists('label', $this->fields)) $this->label='This is label';
7719
		if (array_key_exists('note_public', $this->fields)) $this->note_public='Public note';
7720
		if (array_key_exists('note_private', $this->fields)) $this->note_private='Private note';
7721
		if (array_key_exists('date_creation', $this->fields)) $this->date_creation=(dol_now()-3600*24);
7722
		if (array_key_exists('date_modification', $this->fields)) $this->date_modification=(dol_now()-3600*24);
7723
		if (array_key_exists('fk_user_creat', $this->fields)) $this->fk_user_creat=$user->id;
7724
		if (array_key_exists('fk_user_modif', $this->fields)) $this->fk_user_modif=$user->id;
7725
		if (array_key_exists('date', $this->fields)) $this->date=dol_now();
7726
		// ...
7727
	}
7728
7729
7730
	/* Part for comments */
7731
7732
	/**
7733
	 * Load comments linked with current task
7734
	 *	@return boolean	1 if ok
7735
	 */
7736
	public function fetchComments()
7737
	{
7738
		require_once DOL_DOCUMENT_ROOT.'/core/class/comment.class.php';
7739
7740
		$comment = new Comment($this->db);
7741
		$result=$comment->fetchAllFor($this->element, $this->id);
7742
		if ($result<0) {
7743
			$this->errors=array_merge($this->errors, $comment->errors);
7744
			return -1;
7745
		} else {
7746
			$this->comments = $comment->comments;
7747
		}
7748
		return count($this->comments);
7749
	}
7750
7751
    /**
7752
     * Return nb comments already posted
7753
     *
7754
     * @return int
7755
     */
7756
    public function getNbComments()
7757
    {
7758
        return count($this->comments);
7759
    }
7760
7761
    /**
7762
     * Trim object parameters
7763
     * @param string[] $parameters array of parameters to trim
7764
     *
7765
     * @return void
7766
     */
7767
    public function trimParameters($parameters)
7768
    {
7769
        if (!is_array($parameters)) return;
1 ignored issue
show
introduced by
The condition is_array($parameters) is always true.
Loading history...
7770
        foreach ($parameters as $parameter) {
7771
            if (isset($this->$parameter)) {
7772
                $this->$parameter = trim($this->$parameter);
7773
            }
7774
        }
7775
    }
7776
}
7777