Passed
Push — master ( 284492...2c3033 )
by Alxarafe
27:10
created

AlixarModel::update_price()   F

Complexity

Conditions 54
Paths > 20000

Size

Total Lines 213
Code Lines 156

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 54
eloc 156
nc 1997624167
nop 4
dl 0
loc 213
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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

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

1559
                    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...
1560
                } else {
1561
                    $this->{$field} = array();
1562
                }
1563
            } elseif ($this->isInt($info)) {
1564
                if ($field == 'rowid') $this->id = (int)$obj->{$field};
1565
                else $this->{$field} = (int)$obj->{$field};
1566
            } elseif ($this->isFloat($info)) {
1567
                $this->{$field} = (double)$obj->{$field};
1568
            } elseif ($this->isNull($info)) {
1569
                $val = $obj->{$field};
1570
                // zero is not null
1571
                $this->{$field} = (is_null($val) || (empty($val) && $val !== 0 && $val !== '0') ? null : $val);
1572
            } else {
1573
                $this->{$field} = $obj->{$field};
1574
            }
1575
        }
1576
1577
        // If there is no 'ref' field, we force property ->ref to ->id for a better compatibility with common functions.
1578
        if (!isset($this->fields['ref']) && isset($this->id)) $this->ref = $this->id;
1579
    }
1580
1581
    /**
1582
     * Function test if type is date
1583
     *
1584
     * @param array $info content informations of field
1585
     * @return                  bool
1586
     */
1587
    public function isDate($info)
1588
    {
1589
        if (isset($info['type']) && ($info['type'] == 'date' || $info['type'] == 'datetime' || $info['type'] == 'timestamp')) return true;
1590
        else return false;
1591
    }
1592
1593
    /**
1594
     * Function test if type is array
1595
     *
1596
     * @param array $info content informations of field
1597
     * @return                  bool
1598
     */
1599
    protected function isArray($info)
1600
    {
1601
        if (is_array($info)) {
1602
            if (isset($info['type']) && $info['type'] == 'array') return true;
1603
            else return false;
1604
        } else return false;
1605
    }
1606
1607
    /**
1608
     * Function test if type is integer
1609
     *
1610
     * @param array $info content informations of field
1611
     * @return                  bool
1612
     */
1613
    public function isInt($info)
1614
    {
1615
        if (is_array($info)) {
1616
            if (isset($info['type']) && ($info['type'] == 'int' || preg_match('/^integer/i', $info['type']))) return true;
1617
            else return false;
1618
        } else return false;
1619
    }
1620
1621
    /**
1622
     * Function test if type is float
1623
     *
1624
     * @param array $info content informations of field
1625
     * @return                  bool
1626
     */
1627
    public function isFloat($info)
1628
    {
1629
        if (is_array($info)) {
1630
            if (isset($info['type']) && (preg_match('/^(double|real)/i', $info['type']))) return true;
1631
            else return false;
1632
        } else return false;
1633
    }
1634
1635
    /**
1636
     * Function test if type is null
1637
     *
1638
     * @param array $info content informations of field
1639
     * @return                  bool
1640
     */
1641
    protected function isNull($info)
1642
    {
1643
        if (is_array($info)) {
1644
            if (isset($info['type']) && $info['type'] == 'null') return true;
1645
            else return false;
1646
        } else return false;
1647
    }
1648
1649
    /**
1650
     *      Load properties id_previous and id_next by comparing $fieldid with $this->ref
1651
     *
1652
     * @param string $filter Optional filter. Example: " AND (t.field1 = 'aa' OR t.field2 = 'bb')"
1653
     * @param string $fieldid Name of field to use for the select MAX and MIN
1654
     * @param int $nodbprefix Do not include DB prefix to forge table name
1655
     * @return int                <0 if KO, >0 if OK
1656
     */
1657
    function load_previous_next_ref($filter, $fieldid, $nodbprefix = 0)
1658
    {
1659
        // phpcs:enable
1660
        global $conf, $user;
1661
1662
        if (!$this->table_element) {
1663
            dol_print_error('', get_class($this) . "::load_previous_next_ref was called on objet with property table_element not defined");
1664
            return -1;
1665
        }
1666
        if ($fieldid == 'none') return 1;
1667
1668
        // Security on socid
1669
        $socid = 0;
1670
        if ($user->societe_id > 0) $socid = $user->societe_id;
1671
1672
        // this->ismultientitymanaged contains
1673
        // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
1674
        $alias = 's';
1675
        if ($this->element == 'societe') $alias = 'te';
1676
1677
        $sql = "SELECT MAX(te." . $fieldid . ")";
1678
        $sql .= " FROM " . (empty($nodbprefix) ? MAIN_DB_PREFIX : '') . $this->table_element . " as te";
1679
        if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1680
            $sql .= "," . MAIN_DB_PREFIX . "usergroup_user as ug";
1681
        }
1682
        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
1683
        else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql .= ", " . MAIN_DB_PREFIX . "societe as s";    // If we need to link to societe to limit select to socid
1684
        else if ($this->restrictiononfksoc == 2 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON te.fk_soc = s.rowid";    // If we need to link to societe to limit select to socid
1685
        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";
1686
        $sql .= " WHERE te." . $fieldid . " < '" . $this->db->escape($this->ref) . "'";  // ->ref must always be defined (set to id if field does not exists)
1687
        if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql .= " AND sc.fk_user = " . $user->id;
1688
        if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql .= " AND (sc.fk_user = " . $user->id . ' OR te.fk_soc IS NULL)';
1689
        if (!empty($filter)) {
1690
            if (!preg_match('/^\s*AND/i', $filter)) $sql .= " AND ";   // For backward compatibility
1691
            $sql .= $filter;
1692
        }
1693
        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
1694
        else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql .= ' AND te.fk_soc = s.rowid';            // If we need to link to societe to limit select to socid
1695
        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1696
            if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1697
                if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1698
                    $sql .= " AND te.entity IS NOT NULL"; // Show all users
1699
                } else {
1700
                    $sql .= " AND ug.fk_user = te.rowid";
1701
                    $sql .= " AND ug.entity IN (" . getEntity($this->element) . ")";
1702
                }
1703
            } else {
1704
                $sql .= ' AND te.entity IN (' . getEntity($this->element) . ')';
1705
            }
1706
        }
1707
        if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql .= ' AND te.fk_soc = ' . $socid;
1708
        if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql .= ' AND (te.fk_soc = ' . $socid . ' OR te.fk_soc IS NULL)';
1709
        if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql .= ' AND te.rowid = ' . $socid;
1710
        //print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1711
1712
        $result = $this->db->query($sql);
1713
        if (!$result) {
1714
            $this->error = $this->db->lasterror();
1715
            return -1;
1716
        }
1717
        $row = $this->db->fetch_row($result);
1718
        $this->ref_previous = $row[0];
1719
1720
1721
        $sql = "SELECT MIN(te." . $fieldid . ")";
1722
        $sql .= " FROM " . (empty($nodbprefix) ? MAIN_DB_PREFIX : '') . $this->table_element . " as te";
1723
        if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1724
            $sql .= "," . MAIN_DB_PREFIX . "usergroup_user as ug";
1725
        }
1726
        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
1727
        else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql .= ", " . MAIN_DB_PREFIX . "societe as s";    // If we need to link to societe to limit select to socid
1728
        else if ($this->restrictiononfksoc == 2 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON te.fk_soc = s.rowid";    // If we need to link to societe to limit select to socid
1729
        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";
1730
        $sql .= " WHERE te." . $fieldid . " > '" . $this->db->escape($this->ref) . "'";  // ->ref must always be defined (set to id if field does not exists)
1731
        if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql .= " AND sc.fk_user = " . $user->id;
1732
        if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql .= " AND (sc.fk_user = " . $user->id . ' OR te.fk_soc IS NULL)';
1733
        if (!empty($filter)) {
1734
            if (!preg_match('/^\s*AND/i', $filter)) $sql .= " AND ";   // For backward compatibility
1735
            $sql .= $filter;
1736
        }
1737
        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
1738
        else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql .= ' AND te.fk_soc = s.rowid';            // If we need to link to societe to limit select to socid
1739
        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
1740
            if ($this->element == 'user' && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1741
                if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
1742
                    $sql .= " AND te.entity IS NOT NULL"; // Show all users
1743
                } else {
1744
                    $sql .= " AND ug.fk_user = te.rowid";
1745
                    $sql .= " AND ug.entity IN (" . getEntity($this->element) . ")";
1746
                }
1747
            } else {
1748
                $sql .= ' AND te.entity IN (' . getEntity($this->element) . ')';
1749
            }
1750
        }
1751
        if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql .= ' AND te.fk_soc = ' . $socid;
1752
        if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql .= ' AND (te.fk_soc = ' . $socid . ' OR te.fk_soc IS NULL)';
1753
        if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql .= ' AND te.rowid = ' . $socid;
1754
        //print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."<br>";
1755
        // 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
1756
1757
        $result = $this->db->query($sql);
1758
        if (!$result) {
1759
            $this->error = $this->db->lasterror();
1760
            return -2;
1761
        }
1762
        $row = $this->db->fetch_row($result);
1763
        $this->ref_next = $row[0];
1764
1765
        return 1;
1766
    }
1767
1768
1769
    // TODO: Move line related operations to CommonObjectLine?
1770
1771
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1772
1773
    /**
1774
     *      Return list of id of contacts of object
1775
     *
1776
     * @param string $source Source of contact: external (llx_socpeople) or internal (llx_user) or thirdparty (llx_societe)
1777
     * @return array                Array of id of contacts (if source=external or internal)
1778
     *                                    Array of id of third parties with at least one contact on object (if source=thirdparty)
1779
     */
1780
    function getListContactId($source = 'external')
1781
    {
1782
        $contactAlreadySelected = array();
1783
        $tab = $this->liste_contact(-1, $source);
1784
        $num = count($tab);
1785
        $i = 0;
1786
        while ($i < $num) {
1787
            if ($source == 'thirdparty') $contactAlreadySelected[$i] = $tab[$i]['socid'];
1788
            else  $contactAlreadySelected[$i] = $tab[$i]['id'];
1789
            $i++;
1790
        }
1791
        return $contactAlreadySelected;
1792
    }
1793
1794
    /**
1795
     *    Link element with a project
1796
     *
1797
     * @param int $projectid Project id to link element to
1798
     * @return        int                        <0 if KO, >0 if OK
1799
     */
1800
    function setProject($projectid)
1801
    {
1802
        if (!$this->table_element) {
1803
            dol_syslog(get_class($this) . "::setProject was called on objet with property table_element not defined", LOG_ERR);
1804
            return -1;
1805
        }
1806
1807
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
1808
        if ($this->table_element == 'actioncomm') {
1809
            if ($projectid) $sql .= ' SET fk_project = ' . $projectid;
1810
            else $sql .= ' SET fk_project = NULL';
1811
            $sql .= ' WHERE id = ' . $this->id;
1812
        } else {
1813
            if ($projectid) $sql .= ' SET fk_projet = ' . $projectid;
1814
            else $sql .= ' SET fk_projet = NULL';
1815
            $sql .= ' WHERE rowid = ' . $this->id;
1816
        }
1817
1818
        dol_syslog(get_class($this) . "::setProject", LOG_DEBUG);
1819
        if ($this->db->query($sql)) {
1820
            $this->fk_project = $projectid;
1821
            return 1;
1822
        } else {
1823
            dol_print_error($this->db);
1824
            return -1;
1825
        }
1826
    }
1827
1828
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1829
1830
    /**
1831
     *  Change the payments methods
1832
     *
1833
     * @param int $id Id of new payment method
1834
     * @return        int                >0 if OK, <0 if KO
1835
     */
1836
    function setPaymentMethods($id)
1837
    {
1838
        dol_syslog(get_class($this) . '::setPaymentMethods(' . $id . ')');
1839
        if ($this->statut >= 0 || $this->element == 'societe') {
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;
1847
            $sql .= ' WHERE rowid=' . $this->id;
1848
1849
            if ($this->db->query($sql)) {
1850
                $this->mode_reglement_id = $id;
1851
                // for supplier
1852
                if (get_class($this) == 'Fournisseur') $this->mode_reglement_supplier_id = $id;
1853
                return 1;
1854
            } else {
1855
                dol_syslog(get_class($this) . '::setPaymentMethods Erreur ' . $sql . ' - ' . $this->db->error());
1856
                $this->error = $this->db->error();
1857
                return -1;
1858
            }
1859
        } else {
1860
            dol_syslog(get_class($this) . '::setPaymentMethods, status of the object is incompatible');
1861
            $this->error = 'Status of the object is incompatible ' . $this->statut;
1862
            return -2;
1863
        }
1864
    }
1865
1866
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1867
1868
    /**
1869
     *  Change the multicurrency code
1870
     *
1871
     * @param string $code multicurrency code
1872
     * @return        int                >0 if OK, <0 if KO
1873
     */
1874
    function setMulticurrencyCode($code)
1875
    {
1876
        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...
1877
        if ($this->statut >= 0 || $this->element == 'societe') {
1878
            $fieldname = 'multicurrency_code';
1879
1880
            $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
1881
            $sql .= ' SET ' . $fieldname . " = '" . $this->db->escape($code) . "'";
1882
            $sql .= ' WHERE rowid=' . $this->id;
1883
1884
            if ($this->db->query($sql)) {
1885
                $this->multicurrency_code = $code;
1886
1887
                list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code);
0 ignored issues
show
Bug introduced by
The type Alixar\Base\MultiCurrency was not found. Did you mean MultiCurrency? If so, make sure to prefix the type with \.
Loading history...
1888
                if ($rate) $this->setMulticurrencyRate($rate, 2);
1889
1890
                return 1;
1891
            } else {
1892
                dol_syslog(get_class($this) . '::setMulticurrencyCode Erreur ' . $sql . ' - ' . $this->db->error());
1893
                $this->error = $this->db->error();
1894
                return -1;
1895
            }
1896
        } else {
1897
            dol_syslog(get_class($this) . '::setMulticurrencyCode, status of the object is incompatible');
1898
            $this->error = 'Status of the object is incompatible ' . $this->statut;
1899
            return -2;
1900
        }
1901
    }
1902
1903
    /**
1904
     *  Change the multicurrency rate
1905
     *
1906
     * @param double $rate multicurrency rate
1907
     * @param int $mode mode 1 : amounts in company currency will be recalculated, mode 2 : amounts in foreign currency
1908
     * @return        int                >0 if OK, <0 if KO
1909
     */
1910
    function setMulticurrencyRate($rate, $mode = 1)
1911
    {
1912
        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...
1913
        if ($this->statut >= 0 || $this->element == 'societe') {
1914
            $fieldname = 'multicurrency_tx';
1915
1916
            $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
1917
            $sql .= ' SET ' . $fieldname . ' = ' . $rate;
1918
            $sql .= ' WHERE rowid=' . $this->id;
1919
1920
            if ($this->db->query($sql)) {
1921
                $this->multicurrency_tx = $rate;
1922
1923
                // Update line price
1924
                if (!empty($this->lines)) {
1925
                    foreach ($this->lines as &$line) {
1926
                        if ($mode == 1) {
1927
                            $line->subprice = 0;
1928
                        }
1929
1930
                        switch ($this->element) {
1931
                            case 'propal':
1932
                                $this->updateline(
1933
                                    $line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1934
                                    ($line->description ? $line->description : $line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1935
                                    $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start,
1936
                                    $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1937
                                );
1938
                                break;
1939
                            case 'commande':
1940
                                $this->updateline(
1941
                                    $line->id, ($line->description ? $line->description : $line->desc), $line->subprice, $line->qty, $line->remise_percent,
1942
                                    $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->date_start, $line->date_end,
1943
                                    $line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1944
                                    $line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1945
                                );
1946
                                break;
1947
                            case 'facture':
1948
                                $this->updateline(
1949
                                    $line->id, ($line->description ? $line->description : $line->desc), $line->subprice, $line->qty, $line->remise_percent,
1950
                                    $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits,
1951
                                    $line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label,
1952
                                    $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice
1953
                                );
1954
                                break;
1955
                            case 'supplier_proposal':
1956
                                $this->updateline(
1957
                                    $line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx,
1958
                                    ($line->description ? $line->description : $line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line,
1959
                                    $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->array_options,
1960
                                    $line->ref_fourn, $line->multicurrency_subprice
1961
                                );
1962
                                break;
1963
                            case 'order_supplier':
1964
                                $this->updateline(
1965
                                    $line->id, ($line->description ? $line->description : $line->desc), $line->subprice, $line->qty, $line->remise_percent,
1966
                                    $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, false,
1967
                                    $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1968
                                );
1969
                                break;
1970
                            case 'invoice_supplier':
1971
                                $this->updateline(
1972
                                    $line->id, ($line->description ? $line->description : $line->desc), $line->subprice, $line->tva_tx, $line->localtax1_tx,
1973
                                    $line->localtax2_tx, $line->qty, 0, 'HT', $line->info_bits, $line->product_type, $line->remise_percent, false,
1974
                                    $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice
1975
                                );
1976
                                break;
1977
                            default:
1978
                                dol_syslog(get_class($this) . '::setMulticurrencyRate no updateline defined', LOG_DEBUG);
1979
                                break;
1980
                        }
1981
                    }
1982
                }
1983
1984
                return 1;
1985
            } else {
1986
                dol_syslog(get_class($this) . '::setMulticurrencyRate Erreur ' . $sql . ' - ' . $this->db->error());
1987
                $this->error = $this->db->error();
1988
                return -1;
1989
            }
1990
        } else {
1991
            dol_syslog(get_class($this) . '::setMulticurrencyRate, status of the object is incompatible');
1992
            $this->error = 'Status of the object is incompatible ' . $this->statut;
1993
            return -2;
1994
        }
1995
    }
1996
1997
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1998
1999
    /**
2000
     *  Change the payments terms
2001
     *
2002
     * @param int $id Id of new payment terms
2003
     * @return        int                >0 if OK, <0 if KO
2004
     */
2005
    function setPaymentTerms($id)
2006
    {
2007
        dol_syslog(get_class($this) . '::setPaymentTerms(' . $id . ')');
2008
        if ($this->statut >= 0 || $this->element == 'societe') {
2009
            // TODO uniformize field name
2010
            $fieldname = 'fk_cond_reglement';
2011
            if ($this->element == 'societe') $fieldname = 'cond_reglement';
2012
            if (get_class($this) == 'Fournisseur') $fieldname = 'cond_reglement_supplier';
2013
2014
            $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
2015
            $sql .= ' SET ' . $fieldname . ' = ' . $id;
2016
            $sql .= ' WHERE rowid=' . $this->id;
2017
2018
            if ($this->db->query($sql)) {
2019
                $this->cond_reglement_id = $id;
2020
                // for supplier
2021
                if (get_class($this) == 'Fournisseur') $this->cond_reglement_supplier_id = $id;
2022
                $this->cond_reglement = $id;    // for compatibility
0 ignored issues
show
Deprecated Code introduced by
The property Alixar\Base\AlixarModel::$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

2022
                /** @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...
2023
                return 1;
2024
            } else {
2025
                dol_syslog(get_class($this) . '::setPaymentTerms Erreur ' . $sql . ' - ' . $this->db->error());
2026
                $this->error = $this->db->error();
2027
                return -1;
2028
            }
2029
        } else {
2030
            dol_syslog(get_class($this) . '::setPaymentTerms, status of the object is incompatible');
2031
            $this->error = 'Status of the object is incompatible ' . $this->statut;
2032
            return -2;
2033
        }
2034
    }
2035
2036
    /**
2037
     *    Define delivery address
2038
     * @param int $id Address id
2039
     * @return     int                <0 si ko, >0 si ok
2040
     * @deprecated
2041
     *
2042
     */
2043
    function setDeliveryAddress($id)
2044
    {
2045
        $fieldname = 'fk_delivery_address';
2046
        if ($this->element == 'delivery' || $this->element == 'shipping') $fieldname = 'fk_address';
2047
2048
        $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element . " SET " . $fieldname . " = " . $id;
2049
        $sql .= " WHERE rowid = " . $this->id . " AND fk_statut = 0";
2050
2051
        if ($this->db->query($sql)) {
2052
            $this->fk_delivery_address = $id;
2053
            return 1;
2054
        } else {
2055
            $this->error = $this->db->error();
2056
            dol_syslog(get_class($this) . '::setDeliveryAddress Erreur ' . $sql . ' - ' . $this->error);
2057
            return -1;
2058
        }
2059
    }
2060
2061
    /**
2062
     *  Change the shipping method
2063
     *
2064
     * @param int $shipping_method_id Id of shipping method
2065
     * @param bool $notrigger false=launch triggers after, true=disable triggers
2066
     * @param User $userused Object user
2067
     *
2068
     * @return     int              1 if OK, 0 if KO
2069
     */
2070
    function setShippingMethod($shipping_method_id, $notrigger = false, $userused = null)
2071
    {
2072
        global $user;
2073
2074
        if (empty($userused)) $userused = $user;
2075
2076
        $error = 0;
2077
2078
        if (!$this->table_element) {
2079
            dol_syslog(get_class($this) . "::setShippingMethod was called on objet with property table_element not defined", LOG_ERR);
2080
            return -1;
2081
        }
2082
2083
        $this->db->begin();
2084
2085
        if ($shipping_method_id < 0) $shipping_method_id = 'NULL';
2086
        dol_syslog(get_class($this) . '::setShippingMethod(' . $shipping_method_id . ')');
2087
2088
        $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element;
2089
        $sql .= " SET fk_shipping_method = " . $shipping_method_id;
2090
        $sql .= " WHERE rowid=" . $this->id;
2091
        $resql = $this->db->query($sql);
2092
        if (!$resql) {
2093
            dol_syslog(get_class($this) . '::setShippingMethod Error ', LOG_DEBUG);
2094
            $this->error = $this->db->lasterror();
2095
            $error++;
2096
        } else {
2097
            if (!$notrigger) {
2098
                // Call trigger
2099
                $this->context = array('shippingmethodupdate' => 1);
2100
                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2101
                if ($result < 0) $error++;
2102
                // End call trigger
2103
            }
2104
        }
2105
        if ($error) {
2106
            $this->db->rollback();
2107
            return -1;
2108
        } else {
2109
            $this->shipping_method_id = ($shipping_method_id == 'NULL') ? null : $shipping_method_id;
0 ignored issues
show
Documentation Bug introduced by
It seems like $shipping_method_id == '...l : $shipping_method_id can also be of type string. However, the property $shipping_method_id is declared as type integer. Maybe add an additional type check?

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

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

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

class Id
{
    public $id;

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

}

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

$account_id = false;

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

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
2110
            $this->db->commit();
2111
            return 1;
2112
        }
2113
    }
2114
2115
    /**
2116
     *  Change the warehouse
2117
     *
2118
     * @param int $warehouse_id Id of warehouse
2119
     * @return     int              1 if OK, 0 if KO
2120
     */
2121
    function setWarehouse($warehouse_id)
2122
    {
2123
        if (!$this->table_element) {
2124
            dol_syslog(get_class($this) . "::setWarehouse was called on objet with property table_element not defined", LOG_ERR);
2125
            return -1;
2126
        }
2127
        if ($warehouse_id < 0) $warehouse_id = 'NULL';
2128
        dol_syslog(get_class($this) . '::setWarehouse(' . $warehouse_id . ')');
2129
2130
        $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element;
2131
        $sql .= " SET fk_warehouse = " . $warehouse_id;
2132
        $sql .= " WHERE rowid=" . $this->id;
2133
2134
        if ($this->db->query($sql)) {
2135
            $this->warehouse_id = ($warehouse_id == 'NULL') ? null : $warehouse_id;
2136
            return 1;
2137
        } else {
2138
            dol_syslog(get_class($this) . '::setWarehouse Error ', LOG_DEBUG);
2139
            $this->error = $this->db->error();
2140
            return 0;
2141
        }
2142
    }
2143
2144
    /**
2145
     *        Set last model used by doc generator
2146
     *
2147
     * @param User $user User object that make change
2148
     * @param string $modelpdf Modele name
2149
     * @return        int                    <0 if KO, >0 if OK
2150
     */
2151
    function setDocModel($user, $modelpdf)
2152
    {
2153
        if (!$this->table_element) {
2154
            dol_syslog(get_class($this) . "::setDocModel was called on objet with property table_element not defined", LOG_ERR);
2155
            return -1;
2156
        }
2157
2158
        $newmodelpdf = dol_trunc($modelpdf, 255);
2159
2160
        $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element;
2161
        $sql .= " SET model_pdf = '" . $this->db->escape($newmodelpdf) . "'";
2162
        $sql .= " WHERE rowid = " . $this->id;
2163
        // if ($this->element == 'facture') $sql.= " AND fk_statut < 2";
2164
        // if ($this->element == 'propal')  $sql.= " AND fk_statut = 0";
2165
2166
        dol_syslog(get_class($this) . "::setDocModel", LOG_DEBUG);
2167
        $resql = $this->db->query($sql);
2168
        if ($resql) {
2169
            $this->modelpdf = $modelpdf;
2170
            return 1;
2171
        } else {
2172
            dol_print_error($this->db);
2173
            return 0;
2174
        }
2175
    }
2176
2177
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2178
2179
    /**
2180
     *  Change the bank account
2181
     *
2182
     * @param int $fk_account Id of bank account
2183
     * @param bool $notrigger false=launch triggers after, true=disable triggers
2184
     * @param User $userused Object user
2185
     * @return        int                1 if OK, 0 if KO
2186
     */
2187
    function setBankAccount($fk_account, $notrigger = false, $userused = null)
2188
    {
2189
        global $user;
2190
2191
        if (empty($userused)) $userused = $user;
2192
2193
        $error = 0;
2194
2195
        if (!$this->table_element) {
2196
            dol_syslog(get_class($this) . "::setBankAccount was called on objet with property table_element not defined", LOG_ERR);
2197
            return -1;
2198
        }
2199
        $this->db->begin();
2200
2201
        if ($fk_account < 0) $fk_account = 'NULL';
2202
        dol_syslog(get_class($this) . '::setBankAccount(' . $fk_account . ')');
2203
2204
        $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element;
2205
        $sql .= " SET fk_account = " . $fk_account;
2206
        $sql .= " WHERE rowid=" . $this->id;
2207
2208
        $resql = $this->db->query($sql);
2209
        if (!$resql) {
2210
            dol_syslog(get_class($this) . '::setBankAccount Error ' . $sql . ' - ' . $this->db->error());
2211
            $this->error = $this->db->lasterror();
2212
            $error++;
2213
        } else {
2214
            if (!$notrigger) {
2215
                // Call trigger
2216
                $this->context = array('bankaccountupdate' => 1);
2217
                $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused);
2218
                if ($result < 0) $error++;
2219
                // End call trigger
2220
            }
2221
        }
2222
        if ($error) {
2223
            $this->db->rollback();
2224
            return -1;
2225
        } else {
2226
            $this->fk_account = ($fk_account == 'NULL') ? null : $fk_account;
0 ignored issues
show
Documentation Bug introduced by
It seems like $fk_account == 'NULL' ? null : $fk_account can also be of type string. However, the property $fk_account is declared as type integer. Maybe add an additional type check?

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

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

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

class Id
{
    public $id;

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

}

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

$account_id = false;

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

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

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

Loading history...
2788
                        }
2789
                        $sqlfix = "UPDATE " . MAIN_DB_PREFIX . $this->table_element_line . " SET " . $fieldtva . " = " . ($obj->total_tva - $diff) . ", total_ttc = " . ($obj->total_ttc - $diff) . " WHERE rowid = " . $obj->rowid;
2790
                        dol_syslog('We found a difference of ' . $diff . ' for line rowid = ' . $obj->rowid . ". We fix the total_vat and total_ttc of line by running sqlfix = " . $sqlfix);
2791
                        $resqlfix = $this->db->query($sqlfix);
2792
                        if (!$resqlfix) dol_print_error($this->db, 'Failed to update line');
2793
                        $this->total_tva -= $diff;
2794
                        $this->total_ttc -= $diff;
2795
                        $total_tva_by_vats[$obj->vatrate] -= $diff;
2796
                        $total_ttc_by_vats[$obj->vatrate] -= $diff;
2797
                    }
2798
                }
2799
2800
                $i++;
2801
            }
2802
2803
            // Add revenue stamp to total
2804
            $this->total_ttc += isset($this->revenuestamp) ? $this->revenuestamp : 0;
2805
            $this->multicurrency_total_ttc += isset($this->revenuestamp) ? ($this->revenuestamp * $multicurrency_tx) : 0;
2806
2807
            // Situations totals
2808
            if ($this->situation_cycle_ref && $this->situation_counter > 1 && method_exists($this, 'get_prev_sits') && $this->type != $this::TYPE_CREDIT_NOTE) {
2809
                $prev_sits = $this->get_prev_sits();
2810
2811
                foreach ($prev_sits as $sit) {                // $sit is an object Facture loaded with a fetch.
2812
                    $this->total_ht -= $sit->total_ht;
2813
                    $this->total_tva -= $sit->total_tva;
2814
                    $this->total_localtax1 -= $sit->total_localtax1;
2815
                    $this->total_localtax2 -= $sit->total_localtax2;
2816
                    $this->total_ttc -= $sit->total_ttc;
2817
                    $this->multicurrency_total_ht -= $sit->multicurrency_total_ht;
2818
                    $this->multicurrency_total_tva -= $sit->multicurrency_total_tva;
2819
                    $this->multicurrency_total_ttc -= $sit->multicurrency_total_ttc;
2820
                }
2821
            }
2822
2823
            $this->db->free($resql);
2824
2825
            // Now update global field total_ht, total_ttc and tva
2826
            $fieldht = 'total_ht';
2827
            $fieldtva = 'tva';
2828
            $fieldlocaltax1 = 'localtax1';
2829
            $fieldlocaltax2 = 'localtax2';
2830
            $fieldttc = 'total_ttc';
2831
            // Specific code for backward compatibility with old field names
2832
            if ($this->element == 'facture' || $this->element == 'facturerec') $fieldht = 'total';
2833
            if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva = 'total_tva';
2834
            if ($this->element == 'propal') $fieldttc = 'total';
2835
            if ($this->element == 'expensereport') $fieldtva = 'total_tva';
2836
            if ($this->element == 'supplier_proposal') $fieldttc = 'total';
2837
2838
            if (empty($nodatabaseupdate)) {
2839
                $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . ' SET';
2840
                $sql .= " " . $fieldht . "='" . price2num($this->total_ht) . "',";
2841
                $sql .= " " . $fieldtva . "='" . price2num($this->total_tva) . "',";
2842
                $sql .= " " . $fieldlocaltax1 . "='" . price2num($this->total_localtax1) . "',";
2843
                $sql .= " " . $fieldlocaltax2 . "='" . price2num($this->total_localtax2) . "',";
2844
                $sql .= " " . $fieldttc . "='" . price2num($this->total_ttc) . "'";
2845
                $sql .= ", multicurrency_total_ht='" . price2num($this->multicurrency_total_ht, 'MT', 1) . "'";
2846
                $sql .= ", multicurrency_total_tva='" . price2num($this->multicurrency_total_tva, 'MT', 1) . "'";
2847
                $sql .= ", multicurrency_total_ttc='" . price2num($this->multicurrency_total_ttc, 'MT', 1) . "'";
2848
                $sql .= ' WHERE rowid = ' . $this->id;
2849
2850
2851
                dol_syslog(get_class($this) . "::update_price", LOG_DEBUG);
2852
                $resql = $this->db->query($sql);
2853
                if (!$resql) {
2854
                    $error++;
2855
                    $this->error = $this->db->lasterror();
2856
                    $this->errors[] = $this->db->lasterror();
2857
                }
2858
            }
2859
2860
            if (!$error) {
2861
                return 1;
2862
            } else {
2863
                return -1;
2864
            }
2865
        } else {
2866
            dol_print_error($this->db, 'Bad request in update_price');
2867
            return -1;
2868
        }
2869
    }
2870
2871
    /**
2872
     *    Add objects linked in llx_element_element.
2873
     *
2874
     * @param string $origin Linked element type
2875
     * @param int $origin_id Linked element id
2876
     * @return        int                    <=0 if KO, >0 if OK
2877
     * @see        fetchObjectLinked, updateObjectLinked, deleteObjectLinked
2878
     */
2879
    function add_object_linked($origin = null, $origin_id = null)
2880
    {
2881
        // phpcs:enable
2882
        $origin = (!empty($origin) ? $origin : $this->origin);
2883
        $origin_id = (!empty($origin_id) ? $origin_id : $this->origin_id);
2884
2885
        // Special case
2886
        if ($origin == 'order') $origin = 'commande';
2887
        if ($origin == 'invoice') $origin = 'facture';
2888
        if ($origin == 'invoice_template') $origin = 'facturerec';
2889
        if ($origin == 'supplierorder') $origin = 'order_supplier';
2890
        $this->db->begin();
2891
2892
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "element_element (";
2893
        $sql .= "fk_source";
2894
        $sql .= ", sourcetype";
2895
        $sql .= ", fk_target";
2896
        $sql .= ", targettype";
2897
        $sql .= ") VALUES (";
2898
        $sql .= $origin_id;
2899
        $sql .= ", '" . $this->db->escape($origin) . "'";
2900
        $sql .= ", " . $this->id;
2901
        $sql .= ", '" . $this->db->escape($this->element) . "'";
2902
        $sql .= ")";
2903
2904
        dol_syslog(get_class($this) . "::add_object_linked", LOG_DEBUG);
2905
        if ($this->db->query($sql)) {
2906
            $this->db->commit();
2907
            return 1;
2908
        } else {
2909
            $this->error = $this->db->lasterror();
2910
            $this->db->rollback();
2911
            return 0;
2912
        }
2913
    }
2914
2915
2916
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2917
2918
    /**
2919
     *    Fetch array of objects linked to current object (object of enabled modules only). Links are loaded into
2920
     *        this->linkedObjectsIds array and
2921
     *        this->linkedObjects array if $loadalsoobjects = 1
2922
     *  Possible usage for parameters:
2923
     *  - all parameters empty -> we look all link to current object (current object can be source or target)
2924
     *  - source id+type -> will get target list linked to source
2925
     *  - target id+type -> will get source list linked to target
2926
     *  - source id+type + target type -> will get target list of the type
2927
     *  - target id+type + target source -> will get source list of the type
2928
     *
2929
     * @param int $sourceid Object source id (if not defined, id of object)
2930
     * @param string $sourcetype Object source type (if not defined, element name of object)
2931
     * @param int $targetid Object target id (if not defined, id of object)
2932
     * @param string $targettype Object target type (if not defined, elemennt name of object)
2933
     * @param string $clause 'OR' or 'AND' clause used when both source id and target id are provided
2934
     * @param int $alsosametype 0=Return only links to object that differs from source type. 1=Include also link to objects of same type.
2935
     * @param string $orderby SQL 'ORDER BY' clause
2936
     * @param int $loadalsoobjects Load also array this->linkedObjects (Use 0 to increase performances)
2937
     * @return int                            <0 if KO, >0 if OK
2938
     * @see    add_object_linked, updateObjectLinked, deleteObjectLinked
2939
     */
2940
    function fetchObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '', $clause = 'OR', $alsosametype = 1, $orderby = 'sourcetype', $loadalsoobjects = 1)
2941
    {
2942
        global $conf;
2943
2944
        $this->linkedObjectsIds = array();
2945
        $this->linkedObjects = array();
2946
2947
        $justsource = false;
2948
        $justtarget = false;
2949
        $withtargettype = false;
2950
        $withsourcetype = false;
2951
2952
        if (!empty($sourceid) && !empty($sourcetype) && empty($targetid)) {
2953
            $justsource = true;  // the source (id and type) is a search criteria
2954
            if (!empty($targettype)) $withtargettype = true;
2955
        }
2956
        if (!empty($targetid) && !empty($targettype) && empty($sourceid)) {
2957
            $justtarget = true;  // the target (id and type) is a search criteria
2958
            if (!empty($sourcetype)) $withsourcetype = true;
2959
        }
2960
2961
        $sourceid = (!empty($sourceid) ? $sourceid : $this->id);
2962
        $targetid = (!empty($targetid) ? $targetid : $this->id);
2963
        $sourcetype = (!empty($sourcetype) ? $sourcetype : $this->element);
2964
        $targettype = (!empty($targettype) ? $targettype : $this->element);
2965
2966
        /*if (empty($sourceid) && empty($targetid))
2967
		 {
2968
		 dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR);
2969
		 return -1;
2970
		 }*/
2971
2972
        // Links between objects are stored in table element_element
2973
        $sql = 'SELECT rowid, fk_source, sourcetype, fk_target, targettype';
2974
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'element_element';
2975
        $sql .= " WHERE ";
2976
        if ($justsource || $justtarget) {
2977
            if ($justsource) {
2978
                $sql .= "fk_source = " . $sourceid . " AND sourcetype = '" . $sourcetype . "'";
2979
                if ($withtargettype) $sql .= " AND targettype = '" . $targettype . "'";
2980
            } else if ($justtarget) {
2981
                $sql .= "fk_target = " . $targetid . " AND targettype = '" . $targettype . "'";
2982
                if ($withsourcetype) $sql .= " AND sourcetype = '" . $sourcetype . "'";
2983
            }
2984
        } else {
2985
            $sql .= "(fk_source = " . $sourceid . " AND sourcetype = '" . $sourcetype . "')";
2986
            $sql .= " " . $clause . " (fk_target = " . $targetid . " AND targettype = '" . $targettype . "')";
2987
        }
2988
        $sql .= ' ORDER BY ' . $orderby;
2989
2990
        dol_syslog(get_class($this) . "::fetchObjectLink", LOG_DEBUG);
2991
        $resql = $this->db->query($sql);
2992
        if ($resql) {
2993
            $num = $this->db->num_rows($resql);
2994
            $i = 0;
2995
            while ($i < $num) {
2996
                $obj = $this->db->fetch_object($resql);
2997
                if ($justsource || $justtarget) {
2998
                    if ($justsource) {
2999
                        $this->linkedObjectsIds[$obj->targettype][$obj->rowid] = $obj->fk_target;
3000
                    } else if ($justtarget) {
3001
                        $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid] = $obj->fk_source;
3002
                    }
3003
                } else {
3004
                    if ($obj->fk_source == $sourceid && $obj->sourcetype == $sourcetype) {
3005
                        $this->linkedObjectsIds[$obj->targettype][$obj->rowid] = $obj->fk_target;
3006
                    }
3007
                    if ($obj->fk_target == $targetid && $obj->targettype == $targettype) {
3008
                        $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid] = $obj->fk_source;
3009
                    }
3010
                }
3011
                $i++;
3012
            }
3013
3014
            if (!empty($this->linkedObjectsIds)) {
3015
                $tmparray = $this->linkedObjectsIds;
3016
                foreach ($tmparray as $objecttype => $objectids)       // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...)
3017
                {
3018
                    // Parse element/subelement (ex: project_task, cabinetmed_consultation, ...)
3019
                    $module = $element = $subelement = $objecttype;
3020
                    if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier'
3021
                        && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
3022
                        $module = $element = $regs[1];
3023
                        $subelement = $regs[2];
3024
                    }
3025
3026
                    $classpath = $element . '/class';
3027
                    // To work with non standard classpath or module name
3028
                    if ($objecttype == 'facture') {
3029
                        $classpath = 'compta/facture/class';
3030
                    } else if ($objecttype == 'facturerec') {
3031
                        $classpath = 'compta/facture/class';
3032
                        $module = 'facture';
3033
                    } else if ($objecttype == 'propal') {
3034
                        $classpath = 'comm/propal/class';
3035
                    } else if ($objecttype == 'supplier_proposal') {
3036
                        $classpath = 'supplier_proposal/class';
3037
                    } else if ($objecttype == 'shipping') {
3038
                        $classpath = 'expedition/class';
3039
                        $subelement = 'expedition';
3040
                        $module = 'expedition_bon';
3041
                    } else if ($objecttype == 'delivery') {
3042
                        $classpath = 'livraison/class';
3043
                        $subelement = 'livraison';
3044
                        $module = 'livraison_bon';
3045
                    } else if ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier') {
3046
                        $classpath = 'fourn/class';
3047
                        $module = 'fournisseur';
3048
                    } else if ($objecttype == 'fichinter') {
3049
                        $classpath = 'fichinter/class';
3050
                        $subelement = 'fichinter';
3051
                        $module = 'ficheinter';
3052
                    } else if ($objecttype == 'subscription') {
3053
                        $classpath = 'adherents/class';
3054
                        $module = 'adherent';
3055
                    }
3056
3057
                    // Set classfile
3058
                    $classfile = strtolower($subelement);
3059
                    $classname = ucfirst($subelement);
3060
3061
                    if ($objecttype == 'order') {
3062
                        $classfile = 'commande';
3063
                        $classname = 'Commande';
3064
                    } else if ($objecttype == 'invoice_supplier') {
3065
                        $classfile = 'fournisseur.facture';
3066
                        $classname = 'FactureFournisseur';
3067
                    } else if ($objecttype == 'order_supplier') {
3068
                        $classfile = 'fournisseur.commande';
3069
                        $classname = 'CommandeFournisseur';
3070
                    } else if ($objecttype == 'supplier_proposal') {
3071
                        $classfile = 'supplier_proposal';
3072
                        $classname = 'SupplierProposal';
3073
                    } else if ($objecttype == 'facturerec') {
3074
                        $classfile = 'facture-rec';
3075
                        $classname = 'FactureRec';
3076
                    } else if ($objecttype == 'subscription') {
3077
                        $classfile = 'subscription';
3078
                        $classname = 'Subscription';
3079
                    }
3080
3081
                    // Here $module, $classfile and $classname are set
3082
                    if ($conf->$module->enabled && (($element != $this->element) || $alsosametype)) {
3083
                        if ($loadalsoobjects) {
3084
                            dol_include_once('/' . $classpath . '/' . $classfile . '.class.php');
3085
                            //print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname);
3086
                            if (class_exists($classname)) {
3087
                                foreach ($objectids as $i => $objectid)    // $i is rowid into llx_element_element
3088
                                {
3089
                                    $object = new $classname($this->db);
3090
                                    $ret = $object->fetch($objectid);
3091
                                    if ($ret >= 0) {
3092
                                        $this->linkedObjects[$objecttype][$i] = $object;
3093
                                    }
3094
                                }
3095
                            }
3096
                        }
3097
                    } else {
3098
                        unset($this->linkedObjectsIds[$objecttype]);
3099
                    }
3100
                }
3101
            }
3102
            return 1;
3103
        } else {
3104
            dol_print_error($this->db);
3105
            return -1;
3106
        }
3107
    }
3108
3109
    /**
3110
     *    Update object linked of a current object
3111
     *
3112
     * @param int $sourceid Object source id
3113
     * @param string $sourcetype Object source type
3114
     * @param int $targetid Object target id
3115
     * @param string $targettype Object target type
3116
     * @return                            int    >0 if OK, <0 if KO
3117
     * @see    add_object_linked, fetObjectLinked, deleteObjectLinked
3118
     */
3119
    function updateObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '')
3120
    {
3121
        $updatesource = false;
3122
        $updatetarget = false;
3123
3124
        if (!empty($sourceid) && !empty($sourcetype) && empty($targetid) && empty($targettype)) $updatesource = true;
3125
        else if (empty($sourceid) && empty($sourcetype) && !empty($targetid) && !empty($targettype)) $updatetarget = true;
3126
3127
        $sql = "UPDATE " . MAIN_DB_PREFIX . "element_element SET ";
3128
        if ($updatesource) {
3129
            $sql .= "fk_source = " . $sourceid;
3130
            $sql .= ", sourcetype = '" . $this->db->escape($sourcetype) . "'";
3131
            $sql .= " WHERE fk_target = " . $this->id;
3132
            $sql .= " AND targettype = '" . $this->db->escape($this->element) . "'";
3133
        } else if ($updatetarget) {
3134
            $sql .= "fk_target = " . $targetid;
3135
            $sql .= ", targettype = '" . $this->db->escape($targettype) . "'";
3136
            $sql .= " WHERE fk_source = " . $this->id;
3137
            $sql .= " AND sourcetype = '" . $this->db->escape($this->element) . "'";
3138
        }
3139
3140
        dol_syslog(get_class($this) . "::updateObjectLinked", LOG_DEBUG);
3141
        if ($this->db->query($sql)) {
3142
            return 1;
3143
        } else {
3144
            $this->error = $this->db->lasterror();
3145
            return -1;
3146
        }
3147
    }
3148
3149
    /**
3150
     *    Delete all links between an object $this
3151
     *
3152
     * @param int $sourceid Object source id
3153
     * @param string $sourcetype Object source type
3154
     * @param int $targetid Object target id
3155
     * @param string $targettype Object target type
3156
     * @param int $rowid Row id of line to delete. If defined, other parameters are not used.
3157
     * @return                        int    >0 if OK, <0 if KO
3158
     * @see    add_object_linked, updateObjectLinked, fetchObjectLinked
3159
     */
3160
    function deleteObjectLinked($sourceid = null, $sourcetype = '', $targetid = null, $targettype = '', $rowid = '')
3161
    {
3162
        $deletesource = false;
3163
        $deletetarget = false;
3164
3165
        if (!empty($sourceid) && !empty($sourcetype) && empty($targetid) && empty($targettype)) $deletesource = true;
3166
        else if (empty($sourceid) && empty($sourcetype) && !empty($targetid) && !empty($targettype)) $deletetarget = true;
3167
3168
        $sourceid = (!empty($sourceid) ? $sourceid : $this->id);
3169
        $sourcetype = (!empty($sourcetype) ? $sourcetype : $this->element);
3170
        $targetid = (!empty($targetid) ? $targetid : $this->id);
3171
        $targettype = (!empty($targettype) ? $targettype : $this->element);
3172
3173
        $sql = "DELETE FROM " . MAIN_DB_PREFIX . "element_element";
3174
        $sql .= " WHERE";
3175
        if ($rowid > 0) {
3176
            $sql .= " rowid = " . $rowid;
3177
        } else {
3178
            if ($deletesource) {
3179
                $sql .= " fk_source = " . $sourceid . " AND sourcetype = '" . $this->db->escape($sourcetype) . "'";
3180
                $sql .= " AND fk_target = " . $this->id . " AND targettype = '" . $this->db->escape($this->element) . "'";
3181
            } else if ($deletetarget) {
3182
                $sql .= " fk_target = " . $targetid . " AND targettype = '" . $this->db->escape($targettype) . "'";
3183
                $sql .= " AND fk_source = " . $this->id . " AND sourcetype = '" . $this->db->escape($this->element) . "'";
3184
            } else {
3185
                $sql .= " (fk_source = " . $this->id . " AND sourcetype = '" . $this->db->escape($this->element) . "')";
3186
                $sql .= " OR";
3187
                $sql .= " (fk_target = " . $this->id . " AND targettype = '" . $this->db->escape($this->element) . "')";
3188
            }
3189
        }
3190
3191
        dol_syslog(get_class($this) . "::deleteObjectLinked", LOG_DEBUG);
3192
        if ($this->db->query($sql)) {
3193
            return 1;
3194
        } else {
3195
            $this->error = $this->db->lasterror();
3196
            $this->errors[] = $this->error;
3197
            return -1;
3198
        }
3199
    }
3200
3201
3202
    // --------------------
3203
    // TODO: All functions here must be redesigned and moved as they are not business functions but output functions
3204
    // --------------------
3205
3206
    /* This is to show add lines */
3207
3208
    /**
3209
     *      Set status of an object
3210
     *
3211
     * @param int $status Status to set
3212
     * @param int $elementId Id of element to force (use this->id by default)
3213
     * @param string $elementType Type of element to force (use this->table_element by default)
3214
     * @param string $trigkey Trigger key to use for trigger
3215
     * @return int                        <0 if KO, >0 if OK
3216
     */
3217
    function setStatut($status, $elementId = null, $elementType = '', $trigkey = '')
3218
    {
3219
        global $user, $langs, $conf;
3220
3221
        $savElementId = $elementId;  // To be used later to know if we were using the method using the id of this or not.
3222
3223
        $elementId = (!empty($elementId) ? $elementId : $this->id);
3224
        $elementTable = (!empty($elementType) ? $elementType : $this->table_element);
3225
3226
        $this->db->begin();
3227
3228
        $fieldstatus = "fk_statut";
3229
        if ($elementTable == 'facture_rec') $fieldstatus = "suspended";
3230
        if ($elementTable == 'mailing') $fieldstatus = "statut";
3231
        if ($elementTable == 'cronjob') $fieldstatus = "status";
3232
        if ($elementTable == 'user') $fieldstatus = "statut";
3233
        if ($elementTable == 'expensereport') $fieldstatus = "fk_statut";
3234
        if ($elementTable == 'commande_fournisseur_dispatch') $fieldstatus = "status";
3235
3236
        $sql = "UPDATE " . MAIN_DB_PREFIX . $elementTable;
3237
        $sql .= " SET " . $fieldstatus . " = " . $status;
3238
        // If status = 1 = validated, update also fk_user_valid
3239
        if ($status == 1 && $elementTable == 'expensereport') $sql .= ", fk_user_valid = " . $user->id;
3240
        $sql .= " WHERE rowid=" . $elementId;
3241
3242
        dol_syslog(get_class($this) . "::setStatut", LOG_DEBUG);
3243
        if ($this->db->query($sql)) {
3244
            $error = 0;
3245
3246
            // Try autoset of trigkey
3247
            if (empty($trigkey)) {
3248
                if ($this->element == 'supplier_proposal' && $status == 2) $trigkey = 'SUPPLIER_PROPOSAL_SIGN';   // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class
3249
                if ($this->element == 'supplier_proposal' && $status == 3) $trigkey = 'SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class
3250
                if ($this->element == 'supplier_proposal' && $status == 4) $trigkey = 'SUPPLIER_PROPOSAL_CLOSE';  // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class
3251
                if ($this->element == 'fichinter' && $status == 3) $trigkey = 'FICHINTER_CLASSIFY_DONE';
3252
                if ($this->element == 'fichinter' && $status == 2) $trigkey = 'FICHINTER_CLASSIFY_BILLED';
3253
                if ($this->element == 'fichinter' && $status == 1) $trigkey = 'FICHINTER_CLASSIFY_UNBILLED';
3254
            }
3255
3256
            if ($trigkey) {
3257
                // Appel des triggers
3258
                include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
3259
                $interface = new Interfaces($this->db);
3260
                $result = $interface->run_triggers($trigkey, $this, $user, $langs, $conf);
3261
                if ($result < 0) {
3262
                    $error++;
3263
                    $this->errors = $interface->errors;
3264
                }
3265
                // Fin appel triggers
3266
            }
3267
3268
            if (!$error) {
3269
                $this->db->commit();
3270
3271
                if (empty($savElementId))    // If the element we update was $this (so $elementId is null)
3272
                {
3273
                    $this->statut = $status;
3274
                    $this->status = $status;
3275
                }
3276
3277
                return 1;
3278
            } else {
3279
                $this->db->rollback();
3280
                dol_syslog(get_class($this) . "::setStatus " . $this->error, LOG_ERR);
3281
                return -1;
3282
            }
3283
        } else {
3284
            $this->error = $this->db->lasterror();
3285
            $this->db->rollback();
3286
            return -1;
3287
        }
3288
    }
3289
3290
3291
3292
    /* This is to show array of line of details */
3293
3294
    /**
3295
     *  Load type of canvas of an object if it exists
3296
     *
3297
     * @param int $id Record id
3298
     * @param string $ref Record ref
3299
     * @return        int                <0 if KO, 0 if nothing done, >0 if OK
3300
     */
3301
    function getCanvas($id = 0, $ref = '')
3302
    {
3303
        global $conf;
3304
3305
        if (empty($id) && empty($ref)) return 0;
3306
        if (!empty($conf->global->MAIN_DISABLE_CANVAS)) return 0;    // To increase speed. Not enabled by default.
3307
3308
        // Clean parameters
3309
        $ref = trim($ref);
3310
3311
        $sql = "SELECT rowid, canvas";
3312
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
3313
        $sql .= " WHERE entity IN (" . getEntity($this->element) . ")";
3314
        if (!empty($id)) $sql .= " AND rowid = " . $id;
3315
        if (!empty($ref)) $sql .= " AND ref = '" . $this->db->escape($ref) . "'";
3316
3317
        $resql = $this->db->query($sql);
3318
        if ($resql) {
3319
            $obj = $this->db->fetch_object($resql);
3320
            if ($obj) {
3321
                $this->canvas = $obj->canvas;
3322
                return 1;
3323
            } else return 0;
3324
        } else {
3325
            dol_print_error($this->db);
3326
            return -1;
3327
        }
3328
    }
3329
3330
    /**
3331
     *    Get special code of a line
3332
     *
3333
     * @param int $lineid Id of line
3334
     * @return    int                    Special code
3335
     */
3336
    function getSpecialCode($lineid)
3337
    {
3338
        $sql = 'SELECT special_code FROM ' . MAIN_DB_PREFIX . $this->table_element_line;
3339
        $sql .= ' WHERE rowid = ' . $lineid;
3340
        $resql = $this->db->query($sql);
3341
        if ($resql) {
3342
            $row = $this->db->fetch_row($resql);
3343
            return $row[0];
3344
        }
3345
    }
3346
3347
3348
    /* This is to show array of line of details of source object */
3349
3350
    /**
3351
     *  Function to say how many lines object contains
3352
     *
3353
     * @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
3354
     * @return    int                        <0 if KO, 0 if no predefined products, nb of lines with predefined products if found
3355
     */
3356
    function hasProductsOrServices($predefined = -1)
3357
    {
3358
        $nb = 0;
3359
3360
        foreach ($this->lines as $key => $val) {
3361
            $qualified = 0;
3362
            if ($predefined == -1) $qualified = 1;
3363
            if ($predefined == 1 && $val->fk_product > 0) $qualified = 1;
3364
            if ($predefined == 0 && $val->fk_product <= 0) $qualified = 1;
3365
            if ($predefined == 2 && $val->fk_product > 0 && $val->product_type == 0) $qualified = 1;
3366
            if ($predefined == 3 && $val->fk_product > 0 && $val->product_type == 1) $qualified = 1;
3367
            if ($qualified) $nb++;
3368
        }
3369
        dol_syslog(get_class($this) . '::hasProductsOrServices we found ' . $nb . ' qualified lines of products/servcies');
3370
        return $nb;
3371
    }
3372
3373
    /**
3374
     * Function that returns the total amount HT of discounts applied for all lines.
3375
     *
3376
     * @return    float
3377
     */
3378
    function getTotalDiscount()
3379
    {
3380
        $total_discount = 0.00;
3381
3382
        $sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht";
3383
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . "det";
3384
        $sql .= " WHERE " . $this->fk_element . " = " . $this->id;
3385
3386
        dol_syslog(get_class($this) . '::getTotalDiscount', LOG_DEBUG);
3387
        $resql = $this->db->query($sql);
3388
        if ($resql) {
3389
            $num = $this->db->num_rows($resql);
3390
            $i = 0;
3391
            while ($i < $num) {
3392
                $obj = $this->db->fetch_object($resql);
3393
3394
                $pu_ht = $obj->pu_ht;
3395
                $qty = $obj->qty;
3396
                $total_ht = $obj->total_ht;
3397
3398
                $total_discount_line = floatval(price2num(($pu_ht * $qty) - $total_ht, 'MT'));
3399
                $total_discount += $total_discount_line;
3400
3401
                $i++;
3402
            }
3403
        }
3404
3405
        //print $total_discount; exit;
3406
        return price2num($total_discount);
3407
    }
3408
3409
3410
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3411
3412
    /**
3413
     * Return into unit=0, the calculated total of weight and volume of all lines * qty
3414
     * Calculate by adding weight and volume of each product line, so properties ->volume/volume_units/weight/weight_units must be loaded on line.
3415
     *
3416
     * @return  array                           array('weight'=>...,'volume'=>...)
3417
     */
3418
    function getTotalWeightVolume()
3419
    {
3420
        $totalWeight = 0;
3421
        $totalVolume = 0;
3422
        // defined for shipment only
3423
        $totalOrdered = '';
3424
        // defined for shipment only
3425
        $totalToShip = '';
3426
3427
        foreach ($this->lines as $line) {
3428
            if (isset($line->qty_asked)) {
3429
                if (empty($totalOrdered)) $totalOrdered = 0;  // Avoid warning because $totalOrdered is ''
3430
                $totalOrdered += $line->qty_asked;    // defined for shipment only
3431
            }
3432
            if (isset($line->qty_shipped)) {
3433
                if (empty($totalToShip)) $totalToShip = 0;    // Avoid warning because $totalToShip is ''
3434
                $totalToShip += $line->qty_shipped;   // defined for shipment only
3435
            } else if ($line->element == 'commandefournisseurdispatch' && isset($line->qty)) {
3436
                if (empty($totalToShip)) $totalToShip = 0;
3437
                $totalToShip += $line->qty;   // defined for reception only
3438
            }
3439
3440
            // Define qty, weight, volume, weight_units, volume_units
3441
            if ($this->element == 'shipping') {
3442
                // for shipments
3443
                $qty = $line->qty_shipped ? $line->qty_shipped : 0;
3444
            } else {
3445
                $qty = $line->qty ? $line->qty : 0;
3446
            }
3447
3448
            $weight = $line->weight ? $line->weight : 0;
3449
            ($weight == 0 && !empty($line->product->weight)) ? $weight = $line->product->weight : 0;
3450
            $volume = $line->volume ? $line->volume : 0;
3451
            ($volume == 0 && !empty($line->product->volume)) ? $volume = $line->product->volume : 0;
3452
3453
            $weight_units = $line->weight_units;
3454
            ($weight_units == 0 && !empty($line->product->weight_units)) ? $weight_units = $line->product->weight_units : 0;
3455
            $volume_units = $line->volume_units;
3456
            ($volume_units == 0 && !empty($line->product->volume_units)) ? $volume_units = $line->product->volume_units : 0;
3457
3458
            $weightUnit = 0;
3459
            $volumeUnit = 0;
3460
            if (!empty($weight_units)) $weightUnit = $weight_units;
3461
            if (!empty($volume_units)) $volumeUnit = $volume_units;
3462
3463
            if (empty($totalWeight)) $totalWeight = 0;  // Avoid warning because $totalWeight is ''
3464
            if (empty($totalVolume)) $totalVolume = 0;  // Avoid warning because $totalVolume is ''
3465
3466
            //var_dump($line->volume_units);
3467
            if ($weight_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3468
            {
3469
                $trueWeightUnit = pow(10, $weightUnit);
3470
                $totalWeight += $weight * $qty * $trueWeightUnit;
3471
            } else {
3472
                if ($weight_units == 99) {
3473
                    // conversion 1 Pound = 0.45359237 KG
3474
                    $trueWeightUnit = 0.45359237;
3475
                    $totalWeight += $weight * $qty * $trueWeightUnit;
3476
                } elseif ($weight_units == 98) {
3477
                    // conversion 1 Ounce = 0.0283495 KG
3478
                    $trueWeightUnit = 0.0283495;
3479
                    $totalWeight += $weight * $qty * $trueWeightUnit;
3480
                } else
3481
                    $totalWeight += $weight * $qty;   // This may be wrong if we mix different units
3482
            }
3483
            if ($volume_units < 50)   // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch)
3484
            {
3485
                //print $line->volume."x".$line->volume_units."x".($line->volume_units < 50)."x".$volumeUnit;
3486
                $trueVolumeUnit = pow(10, $volumeUnit);
3487
                //print $line->volume;
3488
                $totalVolume += $volume * $qty * $trueVolumeUnit;
3489
            } else {
3490
                $totalVolume += $volume * $qty;   // This may be wrong if we mix different units
3491
            }
3492
        }
3493
3494
        return array('weight' => $totalWeight, 'volume' => $totalVolume, 'ordered' => $totalOrdered, 'toship' => $totalToShip);
3495
    }
3496
3497
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3498
3499
    /**
3500
     *    Set extra parameters
3501
     *
3502
     * @return    int      <0 if KO, >0 if OK
3503
     */
3504
    function setExtraParameters()
3505
    {
3506
        $this->db->begin();
3507
3508
        $extraparams = (!empty($this->extraparams) ? json_encode($this->extraparams) : null);
3509
3510
        $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element;
3511
        $sql .= " SET extraparams = " . (!empty($extraparams) ? "'" . $this->db->escape($extraparams) . "'" : "null");
3512
        $sql .= " WHERE rowid = " . $this->id;
3513
3514
        dol_syslog(get_class($this) . "::setExtraParameters", LOG_DEBUG);
3515
        $resql = $this->db->query($sql);
3516
        if (!$resql) {
3517
            $this->error = $this->db->lasterror();
3518
            $this->db->rollback();
3519
            return -1;
3520
        } else {
3521
            $this->db->commit();
3522
            return 1;
3523
        }
3524
    }
3525
3526
    /**
3527
     *    Return incoterms informations
3528
     *    TODO Use a cache for label get
3529
     *
3530
     * @return    string    incoterms info
3531
     */
3532
    function display_incoterms()
3533
    {
3534
        // phpcs:enable
3535
        $out = '';
3536
        $this->libelle_incoterms = '';
3537
        if (!empty($this->fk_incoterms)) {
3538
            $sql = 'SELECT code FROM ' . MAIN_DB_PREFIX . 'c_incoterms WHERE rowid = ' . (int)$this->fk_incoterms;
3539
            $result = $this->db->query($sql);
3540
            if ($result) {
3541
                $res = $this->db->fetch_object($result);
3542
                $out .= $res->code;
3543
            }
3544
        }
3545
3546
        $out .= (($res->code && $this->location_incoterms) ? ' - ' : '') . $this->location_incoterms;
3547
3548
        return $out;
3549
    }
3550
3551
    /**
3552
     *    Return incoterms informations for pdf display
3553
     *
3554
     * @return    string        incoterms info
3555
     */
3556
    function getIncotermsForPDF()
3557
    {
3558
        $sql = 'SELECT code FROM ' . MAIN_DB_PREFIX . 'c_incoterms WHERE rowid = ' . (int)$this->fk_incoterms;
3559
        $resql = $this->db->query($sql);
3560
        if ($resql) {
3561
            $num = $this->db->num_rows($resql);
3562
            if ($num > 0) {
3563
                $res = $this->db->fetch_object($resql);
3564
                return 'Incoterm : ' . $res->code . ' - ' . $this->location_incoterms;
3565
            } else {
3566
                return '';
3567
            }
3568
        } else {
3569
            $this->errors[] = $this->db->lasterror();
3570
            return false;
3571
        }
3572
    }
3573
3574
    /**
3575
     *    Define incoterms values of current object
3576
     *
3577
     * @param int $id_incoterm Id of incoterm to set or '' to remove
3578
     * @param string $location location of incoterm
3579
     * @return    int            <0 if KO, >0 if OK
3580
     */
3581
    function setIncoterms($id_incoterm, $location)
3582
    {
3583
        if ($this->id && $this->table_element) {
3584
            $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element;
3585
            $sql .= " SET fk_incoterms = " . ($id_incoterm > 0 ? $id_incoterm : "null");
3586
            $sql .= ", location_incoterms = " . ($id_incoterm > 0 ? "'" . $this->db->escape($location) . "'" : "null");
3587
            $sql .= " WHERE rowid = " . $this->id;
3588
            dol_syslog(get_class($this) . '::setIncoterms', LOG_DEBUG);
3589
            $resql = $this->db->query($sql);
3590
            if ($resql) {
3591
                $this->fk_incoterms = $id_incoterm;
3592
                $this->location_incoterms = $location;
3593
3594
                $sql = 'SELECT libelle FROM ' . MAIN_DB_PREFIX . 'c_incoterms WHERE rowid = ' . (int)$this->fk_incoterms;
3595
                $res = $this->db->query($sql);
3596
                if ($res) {
3597
                    $obj = $this->db->fetch_object($res);
3598
                    $this->libelle_incoterms = $obj->libelle;
3599
                }
3600
                return 1;
3601
            } else {
3602
                $this->errors[] = $this->db->lasterror();
3603
                return -1;
3604
            }
3605
        } else return -1;
3606
    }
3607
3608
3609
    /* Functions common to commonobject and commonobjectline */
3610
3611
    /* For default values */
3612
3613
    /**
3614
     *    Show add free and predefined products/services form
3615
     *
3616
     * @param int $dateSelector 1=Show also date range input fields
3617
     * @param Societe $seller Object thirdparty who sell
3618
     * @param Societe $buyer Object thirdparty who buy
3619
     * @return    void
3620
     */
3621
    function formAddObjectLine($dateSelector, $seller, $buyer)
3622
    {
3623
        global $conf, $user, $langs, $object, $hookmanager;
3624
        global $form, $bcnd, $var;
3625
3626
        // Line extrafield
3627
        require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
3628
        $extrafieldsline = new ExtraFields($this->db);
0 ignored issues
show
Bug introduced by
The type Alixar\Base\ExtraFields was not found. Did you mean ExtraFields? If so, make sure to prefix the type with \.
Loading history...
3629
        $extralabelslines = $extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3630
3631
        // Output template part (modules that overwrite templates must declare this into descriptor)
3632
        // Use global variables + $dateSelector + $seller and $buyer
3633
        $dirtpls = array_merge($conf->modules_parts['tpl'], array('/core/tpl'));
3634
        foreach ($dirtpls as $reldir) {
3635
            $tpl = dol_buildpath($reldir . '/objectline_create.tpl.php');
3636
            if (empty($conf->file->strict_mode)) {
3637
                $res = @include $tpl;
3638
            } else {
3639
                $res = include $tpl; // for debug
3640
            }
3641
            if ($res) break;
3642
        }
3643
    }
3644
3645
3646
    /* For triggers */
3647
3648
3649
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3650
3651
    /**
3652
     *    Return HTML table for object lines
3653
     *    TODO Move this into an output class file (htmlline.class.php)
3654
     *    If lines are into a template, title must also be into a template
3655
     *    But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
3656
     *
3657
     * @param string $action Action code
3658
     * @param string $seller Object of seller third party
3659
     * @param string $buyer Object of buyer third party
3660
     * @param int $selected Object line selected
3661
     * @param int $dateSelector 1=Show also date range input fields
3662
     * @return    void
3663
     */
3664
    function printObjectLines($action, $seller, $buyer, $selected = 0, $dateSelector = 0)
3665
    {
3666
        global $conf, $hookmanager, $langs, $user;
3667
        // TODO We should not use global var for this !
3668
        global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax;
3669
3670
        // Define usemargins
3671
        $usemargins = 0;
3672
        if (!empty($conf->margin->enabled) && !empty($this->element) && in_array($this->element, array('facture', 'propal', 'commande'))) $usemargins = 1;
3673
3674
        $num = count($this->lines);
3675
3676
        // Line extrafield
3677
        require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
3678
        $extrafieldsline = new ExtraFields($this->db);
3679
        $extralabelslines = $extrafieldsline->fetch_name_optionals_label($this->table_element_line);
3680
3681
        $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...
3682
        $reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3683
        if (empty($reshook)) {
3684
            // Title line
3685
            print "<thead>\n";
3686
3687
            print '<tr class="liste_titre nodrag nodrop">';
3688
3689
            // Adds a line numbering column
3690
            if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) print '<td class="linecolnum" align="center" width="5">&nbsp;</td>';
3691
3692
            // Description
3693
            print '<td class="linecoldescription">' . $langs->trans('Description') . '</td>';
3694
3695
            if ($this->element == 'supplier_proposal' || $this->element == 'order_supplier' || $this->element == 'invoice_supplier') {
3696
                print '<td class="linerefsupplier"><span id="title_fourn_ref">' . $langs->trans("SupplierRef") . '</span></td>';
3697
            }
3698
3699
            // VAT
3700
            print '<td class="linecolvat" align="right" width="80">' . $langs->trans('VAT') . '</td>';
3701
3702
            // Price HT
3703
            print '<td class="linecoluht" align="right" width="80">' . $langs->trans('PriceUHT') . '</td>';
3704
3705
            // Multicurrency
3706
            if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) print '<td class="linecoluht_currency" align="right" width="80">' . $langs->trans('PriceUHTCurrency', $this->multicurrency_code) . '</td>';
3707
3708
            if ($inputalsopricewithtax) print '<td align="right" width="80">' . $langs->trans('PriceUTTC') . '</td>';
3709
3710
            // Qty
3711
            print '<td class="linecolqty" align="right">' . $langs->trans('Qty') . '</td>';
3712
3713
            if ($conf->global->PRODUCT_USE_UNITS) {
3714
                print '<td class="linecoluseunit" align="left">' . $langs->trans('Unit') . '</td>';
3715
            }
3716
3717
            // Reduction short
3718
            print '<td class="linecoldiscount" align="right">' . $langs->trans('ReductionShort') . '</td>';
3719
3720
            if ($this->situation_cycle_ref) {
3721
                print '<td class="linecolcycleref" align="right">' . $langs->trans('Progress') . '</td>';
3722
            }
3723
3724
            if ($usemargins && !empty($conf->margin->enabled) && empty($user->societe_id)) {
3725
                if (!empty($user->rights->margins->creer)) {
3726
                    if ($conf->global->MARGIN_TYPE == "1")
3727
                        print '<td class="linecolmargin1 margininfos" align="right" width="80">' . $langs->trans('BuyingPrice') . '</td>';
3728
                    else
3729
                        print '<td class="linecolmargin1 margininfos" align="right" width="80">' . $langs->trans('CostPrice') . '</td>';
3730
                }
3731
3732
                if (!empty($conf->global->DISPLAY_MARGIN_RATES) && $user->rights->margins->liretous)
3733
                    print '<td class="linecolmargin2 margininfos" align="right" width="50">' . $langs->trans('MarginRate') . '</td>';
3734
                if (!empty($conf->global->DISPLAY_MARK_RATES) && $user->rights->margins->liretous)
3735
                    print '<td class="linecolmargin2 margininfos" align="right" width="50">' . $langs->trans('MarkRate') . '</td>';
3736
            }
3737
3738
            // Total HT
3739
            print '<td class="linecolht" align="right">' . $langs->trans('TotalHTShort') . '</td>';
3740
3741
            // Multicurrency
3742
            if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) print '<td class="linecoltotalht_currency" align="right">' . $langs->trans('TotalHTShortCurrency', $this->multicurrency_code) . '</td>';
3743
3744
            if ($outputalsopricetotalwithtax) print '<td align="right" width="80">' . $langs->trans('TotalTTCShort') . '</td>';
3745
3746
            print '<td class="linecoledit"></td>';  // No width to allow autodim
3747
3748
            print '<td class="linecoldelete" width="10"></td>';
3749
3750
            print '<td class="linecolmove" width="10"></td>';
3751
3752
            if ($action == 'selectlines') {
3753
                print '<td class="linecolcheckall" align="center">';
3754
                print '<input type="checkbox" class="linecheckboxtoggle" />';
3755
                print '<script type="text/javascript">$(document).ready(function() {$(".linecheckboxtoggle").click(function() {var checkBoxes = $(".linecheckbox");checkBoxes.prop("checked", this.checked);})});</script>';
3756
                print '</td>';
3757
            }
3758
3759
            print "</tr>\n";
3760
            print "</thead>\n";
3761
        }
3762
3763
        $var = true;
3764
        $i = 0;
3765
3766
        print "<tbody>\n";
3767
        foreach ($this->lines as $line) {
3768
            //Line extrafield
3769
            $line->fetch_optionals();
3770
3771
            //if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
3772
            if (is_object($hookmanager))   // Old code is commented on preceding line.
3773
            {
3774
                if (empty($line->fk_parent_line)) {
3775
                    $parameters = array('line' => $line, 'var' => $var, 'num' => $num, 'i' => $i, 'dateSelector' => $dateSelector, 'seller' => $seller, 'buyer' => $buyer, 'selected' => $selected, 'extrafieldsline' => $extrafieldsline);
3776
                    $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3777
                } else {
3778
                    $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);
3779
                    $reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3780
                }
3781
            }
3782
            if (empty($reshook)) {
3783
                $this->printObjectLine($action, $line, $var, $num, $i, $dateSelector, $seller, $buyer, $selected, $extrafieldsline);
3784
            }
3785
3786
            $i++;
3787
        }
3788
        print "</tbody>\n";
3789
    }
3790
3791
3792
    /* Functions for extrafields */
3793
3794
3795
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3796
3797
    /**
3798
     *    Return HTML content of a detail line
3799
     *    TODO Move this into an output class file (htmlline.class.php)
3800
     *
3801
     * @param string $action GET/POST action
3802
     * @param CommonObjectLine $line Selected object line to output
0 ignored issues
show
Bug introduced by
The type Alixar\Base\CommonObjectLine was not found. Did you mean CommonObjectLine? If so, make sure to prefix the type with \.
Loading history...
3803
     * @param string $var Is it a an odd line (true)
3804
     * @param int $num Number of line (0)
3805
     * @param int $i I
3806
     * @param int $dateSelector 1=Show also date range input fields
3807
     * @param string $seller Object of seller third party
3808
     * @param string $buyer Object of buyer third party
3809
     * @param int $selected Object line selected
3810
     * @param int $extrafieldsline Object of extrafield line attribute
3811
     * @return    void
3812
     */
3813
    function printObjectLine($action, $line, $var, $num, $i, $dateSelector, $seller, $buyer, $selected = 0, $extrafieldsline = 0)
3814
    {
3815
        global $conf, $langs, $user, $object, $hookmanager;
3816
        global $form, $bc, $bcdd;
3817
        global $object_rights, $disableedit, $disablemove, $disableremove;   // TODO We should not use global var for this !
3818
3819
        $object_rights = $this->getRights();
3820
3821
        $element = $this->element;
3822
3823
        $text = '';
3824
        $description = '';
3825
        $type = 0;
3826
3827
        // Show product and description
3828
        $type = (!empty($line->product_type) ? $line->product_type : $line->fk_product_type);
3829
        // Try to enhance type detection using date_start and date_end for free lines where type was not saved.
3830
        if (!empty($line->date_start)) $type = 1; // deprecated
3831
        if (!empty($line->date_end)) $type = 1; // deprecated
3832
3833
        // Ligne en mode visu
3834
        if ($action != 'editline' || $selected != $line->id) {
3835
            // Product
3836
            if ($line->fk_product > 0) {
3837
                $product_static = new Product($this->db);
3838
                $product_static->fetch($line->fk_product);
3839
3840
                $product_static->ref = $line->ref; //can change ref in hook
3841
                $product_static->label = $line->label; //can change label in hook
3842
                $text = $product_static->getNomUrl(1);
3843
3844
                // Define output language and label
3845
                if (!empty($conf->global->MAIN_MULTILANGS)) {
3846
                    if (!is_object($this->thirdparty)) {
3847
                        dol_print_error('', 'Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before');
3848
                        return;
3849
                    }
3850
3851
                    $prod = new Product($this->db);
3852
                    $prod->fetch($line->fk_product);
3853
3854
                    $outputlangs = $langs;
3855
                    $newlang = '';
3856
                    if (empty($newlang) && GETPOST('lang_id', 'aZ09')) $newlang = GETPOST('lang_id', 'aZ09');
3857
                    if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && empty($newlang)) $newlang = $this->thirdparty->default_lang;        // For language to language of customer
3858
                    if (!empty($newlang)) {
3859
                        $outputlangs = new Translate("", $conf);
3860
                        $outputlangs->setDefaultLang($newlang);
3861
                    }
3862
3863
                    $label = (!empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $line->product_label;
3864
                } else {
3865
                    $label = $line->product_label;
3866
                }
3867
3868
                $text .= ' - ' . (!empty($line->label) ? $line->label : $label);
3869
                $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.
3870
            }
3871
3872
            $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx / 100)), 'MU');
3873
3874
            // Output template part (modules that overwrite templates must declare this into descriptor)
3875
            // Use global variables + $dateSelector + $seller and $buyer
3876
            $dirtpls = array_merge($conf->modules_parts['tpl'], array('/core/tpl'));
3877
            foreach ($dirtpls as $reldir) {
3878
                $tpl = dol_buildpath($reldir . '/objectline_view.tpl.php');
3879
                if (empty($conf->file->strict_mode)) {
3880
                    $res = @include $tpl;
3881
                } else {
3882
                    $res = include $tpl; // for debug
3883
                }
3884
                if ($res) break;
3885
            }
3886
        }
3887
3888
        // Ligne en mode update
3889
        if ($this->statut == 0 && $action == 'editline' && $selected == $line->id) {
3890
            $label = (!empty($line->label) ? $line->label : (($line->fk_product > 0) ? $line->product_label : ''));
3891
            $placeholder = ' placeholder="' . $langs->trans("Label") . '"';
3892
3893
            $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx / 100)), 'MU');
3894
3895
            // Output template part (modules that overwrite templates must declare this into descriptor)
3896
            // Use global variables + $dateSelector + $seller and $buyer
3897
            $dirtpls = array_merge($conf->modules_parts['tpl'], array('/core/tpl'));
3898
            foreach ($dirtpls as $reldir) {
3899
                $tpl = dol_buildpath($reldir . '/objectline_edit.tpl.php');
3900
                if (empty($conf->file->strict_mode)) {
3901
                    $res = @include $tpl;
3902
                } else {
3903
                    $res = include $tpl; // for debug
3904
                }
3905
                if ($res) break;
3906
            }
3907
        }
3908
    }
3909
3910
    /**
3911
     * Returns the rights used for this class
3912
     * @return stdClass
3913
     */
3914
    public function getRights()
3915
    {
3916
        global $user;
3917
3918
        $element = $this->element;
3919
        if ($element == 'facturerec') $element = 'facture';
3920
3921
        return $user->rights->{$element};
3922
    }
3923
3924
    /**
3925
     *    Return HTML table table of source object lines
3926
     *  TODO Move this and previous function into output html class file (htmlline.class.php).
3927
     *  If lines are into a template, title must also be into a template
3928
     *  But for the moment we don't know if it's possible, so we keep the method available on overloaded objects.
3929
     *
3930
     * @param string $restrictlist ''=All lines, 'services'=Restrict to services only
3931
     * @return    void
3932
     */
3933
    function printOriginLinesList($restrictlist = '')
3934
    {
3935
        global $langs, $hookmanager, $conf;
3936
3937
        print '<tr class="liste_titre">';
3938
        print '<td>' . $langs->trans('Ref') . '</td>';
3939
        print '<td>' . $langs->trans('Description') . '</td>';
3940
        print '<td align="right">' . $langs->trans('VATRate') . '</td>';
3941
        print '<td align="right">' . $langs->trans('PriceUHT') . '</td>';
3942
        if (!empty($conf->multicurrency->enabled)) print '<td align="right">' . $langs->trans('PriceUHTCurrency') . '</td>';
3943
        print '<td align="right">' . $langs->trans('Qty') . '</td>';
3944
        if ($conf->global->PRODUCT_USE_UNITS) {
3945
            print '<td align="left">' . $langs->trans('Unit') . '</td>';
3946
        }
3947
        print '<td align="right">' . $langs->trans('ReductionShort') . '</td></tr>';
3948
3949
        $var = true;
3950
        $i = 0;
3951
3952
        if (!empty($this->lines)) {
3953
            foreach ($this->lines as $line) {
3954
                if (is_object($hookmanager) && (($line->product_type == 9 && !empty($line->special_code)) || !empty($line->fk_parent_line))) {
3955
                    if (empty($line->fk_parent_line)) {
3956
                        $parameters = array('line' => $line, 'var' => $var, 'i' => $i);
3957
                        $action = '';
3958
                        $hookmanager->executeHooks('printOriginObjectLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
3959
                    }
3960
                } else {
3961
                    $this->printOriginLine($line, $var, $restrictlist);
3962
                }
3963
3964
                $i++;
3965
            }
3966
        }
3967
    }
3968
3969
    /**
3970
     *    Return HTML with a line of table array of source object lines
3971
     *  TODO Move this and previous function into output html class file (htmlline.class.php).
3972
     *  If lines are into a template, title must also be into a template
3973
     *  But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
3974
     *
3975
     * @param CommonObjectLine $line Line
3976
     * @param string $var Var
3977
     * @param string $restrictlist ''=All lines, 'services'=Restrict to services only (strike line if not)
3978
     * @return    void
3979
     */
3980
    function printOriginLine($line, $var, $restrictlist = '')
3981
    {
3982
        global $langs, $conf;
3983
3984
        //var_dump($line);
3985
        if (!empty($line->date_start)) {
3986
            $date_start = $line->date_start;
3987
        } else {
3988
            $date_start = $line->date_debut_prevue;
3989
            if ($line->date_debut_reel) $date_start = $line->date_debut_reel;
3990
        }
3991
        if (!empty($line->date_end)) {
3992
            $date_end = $line->date_end;
3993
        } else {
3994
            $date_end = $line->date_fin_prevue;
3995
            if ($line->date_fin_reel) $date_end = $line->date_fin_reel;
3996
        }
3997
3998
        $this->tpl['label'] = '';
3999
        if (!empty($line->fk_parent_line)) $this->tpl['label'] .= img_picto('', 'rightarrow');
4000
4001
        if (($line->info_bits & 2) == 2)  // TODO Not sure this is used for source object
4002
        {
4003
            $discount = new DiscountAbsolute($this->db);
0 ignored issues
show
Bug introduced by
The type Alixar\Base\DiscountAbsolute was not found. Did you mean DiscountAbsolute? If so, make sure to prefix the type with \.
Loading history...
4004
            $discount->fk_soc = $this->socid;
4005
            $this->tpl['label'] .= $discount->getNomUrl(0, 'discount');
4006
        } else if (!empty($line->fk_product)) {
4007
            $productstatic = new Product($this->db);
4008
            $productstatic->id = $line->fk_product;
4009
            $productstatic->ref = $line->ref;
4010
            $productstatic->type = $line->fk_product_type;
4011
            if (empty($productstatic->ref)) {
4012
                $line->fetch_product();
4013
                $productstatic = $line->product;
4014
            }
4015
4016
            $this->tpl['label'] .= $productstatic->getNomUrl(1);
4017
            $this->tpl['label'] .= ' - ' . (!empty($line->label) ? $line->label : $line->product_label);
4018
            // Dates
4019
            if ($line->product_type == 1 && ($date_start || $date_end)) {
4020
                $this->tpl['label'] .= get_date_range($date_start, $date_end);
4021
            }
4022
        } else {
4023
            $this->tpl['label'] .= ($line->product_type == -1 ? '&nbsp;' : ($line->product_type == 1 ? img_object($langs->trans(''), 'service') : img_object($langs->trans(''), 'product')));
4024
            if (!empty($line->desc)) {
4025
                $this->tpl['label'] .= $line->desc;
4026
            } else {
4027
                $this->tpl['label'] .= ($line->label ? '&nbsp;' . $line->label : '');
4028
            }
4029
4030
            // Dates
4031
            if ($line->product_type == 1 && ($date_start || $date_end)) {
4032
                $this->tpl['label'] .= get_date_range($date_start, $date_end);
4033
            }
4034
        }
4035
4036
        if (!empty($line->desc)) {
4037
            if ($line->desc == '(CREDIT_NOTE)')  // TODO Not sure this is used for source object
4038
            {
4039
                $discount = new DiscountAbsolute($this->db);
4040
                $discount->fetch($line->fk_remise_except);
4041
                $this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote", $discount->getNomUrl(0));
4042
            } elseif ($line->desc == '(DEPOSIT)')  // TODO Not sure this is used for source object
4043
            {
4044
                $discount = new DiscountAbsolute($this->db);
4045
                $discount->fetch($line->fk_remise_except);
4046
                $this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit", $discount->getNomUrl(0));
4047
            } elseif ($line->desc == '(EXCESS RECEIVED)') {
4048
                $discount = new DiscountAbsolute($this->db);
4049
                $discount->fetch($line->fk_remise_except);
4050
                $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessReceived", $discount->getNomUrl(0));
4051
            } elseif ($line->desc == '(EXCESS PAID)') {
4052
                $discount = new DiscountAbsolute($this->db);
4053
                $discount->fetch($line->fk_remise_except);
4054
                $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessPaid", $discount->getNomUrl(0));
4055
            } else {
4056
                $this->tpl['description'] = dol_trunc($line->desc, 60);
4057
            }
4058
        } else {
4059
            $this->tpl['description'] = '&nbsp;';
4060
        }
4061
4062
        // VAT Rate
4063
        $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
4064
        $this->tpl['vat_rate'] .= (($line->info_bits & 1) == 1) ? '*' : '';
4065
        if (!empty($line->vat_src_code) && !preg_match('/\(/', $this->tpl['vat_rate'])) $this->tpl['vat_rate'] .= ' (' . $line->vat_src_code . ')';
4066
4067
        $this->tpl['price'] = price($line->subprice);
4068
        $this->tpl['multicurrency_price'] = price($line->multicurrency_subprice);
4069
        $this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : '&nbsp;';
4070
        if ($conf->global->PRODUCT_USE_UNITS) $this->tpl['unit'] = $langs->transnoentities($line->getLabelOfUnit('long'));
4071
        $this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : '&nbsp;';
4072
4073
        // Is the line strike or not
4074
        $this->tpl['strike'] = 0;
4075
        if ($restrictlist == 'services' && $line->product_type != Product::TYPE_SERVICE) $this->tpl['strike'] = 1;
4076
4077
        // Output template part (modules that overwrite templates must declare this into descriptor)
4078
        // Use global variables + $dateSelector + $seller and $buyer
4079
        $dirtpls = array_merge($conf->modules_parts['tpl'], array('/core/tpl'));
4080
        foreach ($dirtpls as $reldir) {
4081
            $tpl = dol_buildpath($reldir . '/originproductline.tpl.php');
4082
            if (empty($conf->file->strict_mode)) {
4083
                $res = @include $tpl;
4084
            } else {
4085
                $res = include $tpl; // for debug
4086
            }
4087
            if ($res) break;
4088
        }
4089
    }
4090
4091
    /**
4092
     *    Add resources to the current object : add entry into llx_element_resources
4093
     *    Need $this->element & $this->id
4094
     *
4095
     * @param int $resource_id Resource id
4096
     * @param string $resource_type 'resource'
4097
     * @param int $busy Busy or not
4098
     * @param int $mandatory Mandatory or not
4099
     * @return        int                            <=0 if KO, >0 if OK
4100
     */
4101
    function add_element_resource($resource_id, $resource_type, $busy = 0, $mandatory = 0)
4102
    {
4103
        // phpcs:enable
4104
        $this->db->begin();
4105
4106
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "element_resources (";
4107
        $sql .= "resource_id";
4108
        $sql .= ", resource_type";
4109
        $sql .= ", element_id";
4110
        $sql .= ", element_type";
4111
        $sql .= ", busy";
4112
        $sql .= ", mandatory";
4113
        $sql .= ") VALUES (";
4114
        $sql .= $resource_id;
4115
        $sql .= ", '" . $this->db->escape($resource_type) . "'";
4116
        $sql .= ", '" . $this->db->escape($this->id) . "'";
4117
        $sql .= ", '" . $this->db->escape($this->element) . "'";
4118
        $sql .= ", '" . $this->db->escape($busy) . "'";
4119
        $sql .= ", '" . $this->db->escape($mandatory) . "'";
4120
        $sql .= ")";
4121
4122
        dol_syslog(get_class($this) . "::add_element_resource", LOG_DEBUG);
4123
        if ($this->db->query($sql)) {
4124
            $this->db->commit();
4125
            return 1;
4126
        } else {
4127
            $this->error = $this->db->lasterror();
4128
            $this->db->rollback();
4129
            return 0;
4130
        }
4131
    }
4132
4133
    /**
4134
     *    Delete a link to resource line
4135
     *
4136
     * @param int $rowid Id of resource line to delete
4137
     * @param int $element element name (for trigger) TODO: use $this->element into commonobject class
4138
     * @param int $notrigger Disable all triggers
4139
     * @return   int                        >0 if OK, <0 if KO
4140
     */
4141
    function delete_resource($rowid, $element, $notrigger = 0)
4142
    {
4143
        // phpcs:enable
4144
        global $user;
4145
4146
        $this->db->begin();
4147
4148
        $sql = "DELETE FROM " . MAIN_DB_PREFIX . "element_resources";
4149
        $sql .= " WHERE rowid=" . $rowid;
4150
4151
        dol_syslog(get_class($this) . "::delete_resource", LOG_DEBUG);
4152
4153
        $resql = $this->db->query($sql);
4154
        if (!$resql) {
4155
            $this->error = $this->db->lasterror();
4156
            $this->db->rollback();
4157
            return -1;
4158
        } else {
4159
            if (!$notrigger) {
4160
                $result = $this->call_trigger(strtoupper($element) . '_DELETE_RESOURCE', $user);
4161
                if ($result < 0) {
4162
                    $this->db->rollback();
4163
                    return -1;
4164
                }
4165
            }
4166
            $this->db->commit();
4167
            return 1;
4168
        }
4169
    }
4170
4171
    /**
4172
     * Overwrite magic function to solve problem of cloning object that are kept as references
4173
     *
4174
     * @return void
4175
     */
4176
    function __clone()
4177
    {
4178
        // Force a copy of this->lines, otherwise it will point to same object.
4179
        if (isset($this->lines) && is_array($this->lines)) {
4180
            $nboflines = count($this->lines);
4181
            for ($i = 0; $i < $nboflines; $i++) {
4182
                $this->lines[$i] = clone $this->lines[$i];
4183
            }
4184
        }
4185
    }
4186
4187
    /**
4188
     *  Build thumb
4189
     * @TODO Move this into files.lib.php
4190
     *
4191
     * @param string $file Path file in UTF8 to original file to create thumbs from.
4192
     * @return        void
4193
     */
4194
    function addThumbs($file)
4195
    {
4196
        global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini, $quality;
4197
4198
        require_once DOL_DOCUMENT_ROOT . '/core/lib/images.lib.php';        // This define also $maxwidthsmall, $quality, ...
4199
4200
        $file_osencoded = dol_osencode($file);
4201
        if (file_exists($file_osencoded)) {
4202
            // Create small thumbs for company (Ratio is near 16/9)
4203
            // Used on logon for example
4204
            vignette($file_osencoded, $maxwidthsmall, $maxheightsmall, '_small', $quality);
4205
4206
            // Create mini thumbs for company (Ratio is near 16/9)
4207
            // Used on menu or for setup page for example
4208
            vignette($file_osencoded, $maxwidthmini, $maxheightmini, '_mini', $quality);
4209
        }
4210
    }
4211
4212
    /**
4213
     * Return the default value to use for a field when showing the create form of object.
4214
     * Return values in this order:
4215
     * 1) If parameter is available into POST, we return it first.
4216
     * 2) If not but an alternate value was provided as parameter of function, we return it.
4217
     * 3) If not but a constant $conf->global->OBJECTELEMENT_FIELDNAME is set, we return it (It is better to use the dedicated table).
4218
     * 4) Return value found into database (TODO No yet implemented)
4219
     *
4220
     * @param string $fieldname Name of field
4221
     * @param string $alternatevalue Alternate value to use
4222
     * @return  string|string[]                         Default value (can be an array if the GETPOST return an array)
4223
     **/
4224
    function getDefaultCreateValueFor($fieldname, $alternatevalue = null)
4225
    {
4226
        global $conf, $_POST;
4227
4228
        // If param here has been posted, we use this value first.
4229
        if (isset($_POST[$fieldname])) return GETPOST($fieldname, 2);
4230
4231
        if (isset($alternatevalue)) return $alternatevalue;
4232
4233
        $newelement = $this->element;
4234
        if ($newelement == 'facture') $newelement = 'invoice';
4235
        if ($newelement == 'commande') $newelement = 'order';
4236
        if (empty($newelement)) {
4237
            dol_syslog("Ask a default value using common method getDefaultCreateValueForField on an object with no property ->element defined. Return empty string.", LOG_WARNING);
4238
            return '';
4239
        }
4240
4241
        $keyforfieldname = strtoupper($newelement . '_DEFAULT_' . $fieldname);
4242
        //var_dump($keyforfieldname);
4243
        if (isset($conf->global->$keyforfieldname)) return $conf->global->$keyforfieldname;
4244
4245
        // TODO Ad here a scan into table llx_overwrite_default with a filter on $this->element and $fieldname
4246
    }
4247
4248
    /**
4249
     *  Function to get extra fields of an object into $this->array_options
4250
     *  This method is in most cases called by method fetch of objects but you can call it separately.
4251
     *
4252
     * @param int $rowid Id of line. Use the id of object if not defined. Deprecated. Function must be called without parameters.
4253
     * @param array $optionsArray Array resulting of call of extrafields->fetch_name_optionals_label(). Deprecated. Function must be called without parameters.
4254
     * @return    int                        <0 if error, 0 if no values of extrafield to find nor found, 1 if an attribute is found and value loaded
4255
     */
4256
    function fetch_optionals($rowid = null, $optionsArray = null)
4257
    {
4258
        // phpcs:enable
4259
        if (empty($rowid)) $rowid = $this->id;
4260
4261
        // To avoid SQL errors. Probably not the better solution though
4262
        if (!$this->table_element) {
4263
            return 0;
4264
        }
4265
4266
        $this->array_options = array();
4267
4268
        if (!is_array($optionsArray)) {
4269
            // If $extrafields is not a known object, we initialize it. Best practice is to have $extrafields defined into card.php or list.php page.
4270
            // TODO Use of existing $extrafield is not yet ready (must mutualize code that use extrafields in form first)
4271
            // global $extrafields;
4272
            //if (! is_object($extrafields))
4273
            //{
4274
            require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
4275
            $extrafields = new ExtraFields($this->db);
4276
            //}
4277
4278
            // Load array of extrafields for elementype = $this->table_element
4279
            if (empty($extrafields->attributes[$this->table_element]['loaded'])) {
4280
                $extrafields->fetch_name_optionals_label($this->table_element);
4281
            }
4282
            $optionsArray = (!empty($extrafields->attributes[$this->table_element]['label']) ? $extrafields->attributes[$this->table_element]['label'] : null);
4283
        } else {
4284
            global $extrafields;
4285
            dol_syslog("Warning: fetch_optionals was called with param optionsArray defined when you should pass null now", LOG_WARNING);
4286
        }
4287
4288
        $table_element = $this->table_element;
4289
        if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4290
4291
        // Request to get complementary values
4292
        if (is_array($optionsArray) && count($optionsArray) > 0) {
4293
            $sql = "SELECT rowid";
4294
            foreach ($optionsArray as $name => $label) {
4295
                if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] != 'separate') {
4296
                    $sql .= ", " . $name;
4297
                }
4298
            }
4299
            $sql .= " FROM " . MAIN_DB_PREFIX . $table_element . "_extrafields";
4300
            $sql .= " WHERE fk_object = " . $rowid;
4301
4302
            //dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG);		// Too verbose
4303
            $resql = $this->db->query($sql);
4304
            if ($resql) {
4305
                $this->array_options = array();
4306
                $numrows = $this->db->num_rows($resql);
4307
                if ($numrows) {
4308
                    $tab = $this->db->fetch_array($resql);
4309
4310
                    foreach ($tab as $key => $value) {
4311
                        // 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)
4312
                        if ($key != 'rowid' && $key != 'tms' && $key != 'fk_member' && !is_int($key)) {
4313
                            // we can add this attribute to object
4314
                            if (!empty($extrafields) && in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date', 'datetime'))) {
4315
                                //var_dump($extrafields->attributes[$this->table_element]['type'][$key]);
4316
                                $this->array_options["options_" . $key] = $this->db->jdate($value);
4317
                            } else {
4318
                                $this->array_options["options_" . $key] = $value;
4319
                            }
4320
4321
                            //var_dump('key '.$key.' '.$value.' type='.$extrafields->attributes[$this->table_element]['type'][$key].' '.$this->array_options["options_".$key]);
4322
                        }
4323
                    }
4324
                }
4325
4326
                $this->db->free($resql);
4327
4328
                if ($numrows) return $numrows;
4329
                else return 0;
4330
            } else {
4331
                dol_print_error($this->db);
4332
                return -1;
4333
            }
4334
        }
4335
        return 0;
4336
    }
4337
4338
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4339
4340
    /**
4341
     *    Delete all extra fields values for the current object.
4342
     *
4343
     * @return    int        <0 if KO, >0 if OK
4344
     */
4345
    function deleteExtraFields()
4346
    {
4347
        $this->db->begin();
4348
4349
        $table_element = $this->table_element;
4350
        if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
4351
4352
        $sql_del = "DELETE FROM " . MAIN_DB_PREFIX . $table_element . "_extrafields WHERE fk_object = " . $this->id;
4353
        dol_syslog(get_class($this) . "::deleteExtraFields delete", LOG_DEBUG);
4354
        $resql = $this->db->query($sql_del);
4355
        if (!$resql) {
4356
            $this->error = $this->db->lasterror();
4357
            $this->db->rollback();
4358
            return -1;
4359
        } else {
4360
            $this->db->commit();
4361
            return 1;
4362
        }
4363
    }
4364
4365
    /**
4366
     *    Update an extra field value for the current object.
4367
     *  Data to describe values to update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
4368
     *
4369
     * @param string $key Key of the extrafield (without starting 'options_')
4370
     * @param string $trigger If defined, call also the trigger (for example COMPANY_MODIFY)
4371
     * @param User $userused Object user
4372
     * @return int                        -1=error, O=did nothing, 1=OK
4373
     * @see setValueFrom, insertExtraFields
4374
     */
4375
    function updateExtraField($key, $trigger = null, $userused = null)
4376
    {
4377
        global $conf, $langs, $user;
4378
4379
        if (empty($userused)) $userused = $user;
4380
4381
        $error = 0;
4382
4383
        if (!empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0;    // For avoid conflicts if trigger used
4384
4385
        if (!empty($this->array_options) && isset($this->array_options["options_" . $key])) {
4386
            // Check parameters
4387
            $langs->load('admin');
4388
            require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
4389
            $extrafields = new ExtraFields($this->db);
4390
            $target_extrafields = $extrafields->fetch_name_optionals_label($this->table_element);
4391
4392
            $value = $this->array_options["options_" . $key];
4393
4394
            $attributeType = $extrafields->attributes[$this->table_element]['type'][$key];
4395
            $attributeLabel = $extrafields->attributes[$this->table_element]['label'][$key];
4396
            $attributeParam = $extrafields->attributes[$this->table_element]['param'][$key];
4397
            $attributeRequired = $extrafields->attributes[$this->table_element]['required'][$key];
4398
4399
            //dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
4400
            //dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
4401
4402
            switch ($attributeType) {
4403
                case 'int':
4404
                    if (!is_numeric($value) && $value != '') {
4405
                        $this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4406
                        return -1;
4407
                    } elseif ($value == '') {
4408
                        $this->array_options["options_" . $key] = null;
4409
                    }
4410
                    break;
4411
                case 'double':
4412
                    $value = price2num($value);
4413
                    if (!is_numeric($value) && $value != '') {
4414
                        dol_syslog($langs->trans("ExtraFieldHasWrongValue") . " sur " . $attributeLabel . "(" . $value . "is not '" . $attributeType . "')", LOG_DEBUG);
4415
                        $this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
4416
                        return -1;
4417
                    } elseif ($value == '') {
4418
                        $this->array_options["options_" . $key] = null;
4419
                    }
4420
                    //dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
4421
                    $this->array_options["options_" . $key] = $value;
4422
                    break;
4423
                /*case 'select':	// Not required, we chosed value='0' for undefined values
4424
             		if ($value=='-1')
4425
             		{
4426
             			$this->array_options[$key] = null;
4427
             		}
4428
             		break;*/
4429
                case 'price':
4430
                    $this->array_options["options_" . $key] = price2num($this->array_options["options_" . $key]);
4431
                    break;
4432
                case 'date':
4433
                    $this->array_options["options_" . $key] = $this->db->idate($this->array_options["options_" . $key]);
4434
                    break;
4435
                case 'datetime':
4436
                    $this->array_options["options_" . $key] = $this->db->idate($this->array_options["options_" . $key]);
4437
                    break;
4438
                case 'link':
4439
                    $param_list = array_keys($attributeParam['options']);
4440
                    // 0 : ObjectName
4441
                    // 1 : classPath
4442
                    $InfoFieldList = explode(":", $param_list[0]);
4443
                    dol_include_once($InfoFieldList[1]);
4444
                    if ($value) {
4445
                        $object = new $InfoFieldList[0]($this->db);
4446
                        $object->fetch(0, $value);
4447
                        $this->array_options["options_" . $key] = $object->id;
4448
                    }
4449
                    break;
4450
            }
4451
4452
            $this->db->begin();
4453
            $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element . "_extrafields SET " . $key . "='" . $this->db->escape($this->array_options["options_" . $key]) . "'";
4454
            $sql .= " WHERE fk_object = " . $this->id;
4455
            $resql = $this->db->query($sql);
4456
            if (!$resql) {
4457
                $error++;
4458
                $this->error = $this->db->lasterror();
4459
            }
4460
4461
            if (!$error && $trigger) {
4462
                // Call trigger
4463
                $this->context = array('extrafieldupdate' => 1);
4464
                $result = $this->call_trigger($trigger, $userused);
4465
                if ($result < 0) $error++;
4466
                // End call trigger
4467
            }
4468
4469
            if ($error) {
4470
                dol_syslog(get_class($this) . "::" . __METHOD__ . $this->error, LOG_ERR);
4471
                $this->db->rollback();
4472
                return -1;
4473
            } else {
4474
                $this->db->commit();
4475
                return 1;
4476
            }
4477
        } else return 0;
4478
    }
4479
4480
    /**
4481
     * Return HTML string to put an input field into a page
4482
     * Code very similar with showInputField of extra fields
4483
     *
4484
     * @param array $val Array of properties for field to show
4485
     * @param string $key Key of attribute
4486
     * @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)
4487
     * @param string $moreparam To add more parameters on html input tag
4488
     * @param string $keysuffix Prefix string to add into name and id of field (can be used to avoid duplicate names)
4489
     * @param string $keyprefix Suffix string to add into name and id of field (can be used to avoid duplicate names)
4490
     * @param string|int $morecss Value for css to define style/length of field. May also be a numeric.
4491
     * @return string
4492
     */
4493
    function showInputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = 0)
4494
    {
4495
        global $conf, $langs, $form;
4496
4497
        if (!is_object($form)) {
4498
            require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php';
4499
            $form = new Form($this->db);
0 ignored issues
show
Bug introduced by
The type Alixar\Base\Form was not found. Did you mean Form? If so, make sure to prefix the type with \.
Loading history...
4500
        }
4501
4502
        $val = $this->fields[$key];
4503
4504
        $out = '';
4505
        $type = '';
4506
        $param = array();
4507
        $param['options'] = array();
4508
        $size = $this->fields[$key]['size'];
4509
        // Because we work on extrafields
4510
        if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
4511
            $param['options'] = array($reg[1] . ':' . $reg[2] => 'N');
4512
            $type = 'link';
4513
        } elseif (preg_match('/^link:(.*):(.*)/i', $val['type'], $reg)) {
4514
            $param['options'] = array($reg[1] . ':' . $reg[2] => 'N');
4515
            $type = 'link';
4516
        } elseif (preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
4517
            $param['options'] = array($reg[1] . ':' . $reg[2] . ':' . $reg[3] . ':' . $reg[4] => 'N');
4518
            $type = 'sellist';
4519
        } elseif (preg_match('/varchar\((\d+)\)/', $val['type'], $reg)) {
4520
            $param['options'] = array();
4521
            $type = 'varchar';
4522
            $size = $reg[1];
4523
        } elseif (preg_match('/varchar/', $val['type'])) {
4524
            $param['options'] = array();
4525
            $type = 'varchar';
4526
        } elseif (is_array($this->fields[$key]['arrayofkeyval'])) {
4527
            $param['options'] = $this->fields[$key]['arrayofkeyval'];
4528
            $type = 'select';
4529
        } else {
4530
            $param['options'] = array();
4531
            $type = $this->fields[$key]['type'];
4532
        }
4533
4534
        $label = $this->fields[$key]['label'];
4535
        //$elementtype=$this->fields[$key]['elementtype'];	// Seems not used
4536
        $default = $this->fields[$key]['default'];
4537
        $computed = $this->fields[$key]['computed'];
4538
        $unique = $this->fields[$key]['unique'];
4539
        $required = $this->fields[$key]['required'];
4540
4541
        $langfile = $this->fields[$key]['langfile'];
4542
        $list = $this->fields[$key]['list'];
4543
        $hidden = abs($this->fields[$key]['visible']) != 1 ? 1 : 0;
4544
4545
        $objectid = $this->id;
4546
4547
4548
        if ($computed) {
4549
            if (!preg_match('/^search_/', $keyprefix)) return '<span class="opacitymedium">' . $langs->trans("AutomaticallyCalculated") . '</span>';
4550
            else return '';
4551
        }
4552
4553
4554
        // Use in priority showsize from parameters, then $val['css'] then autodefine
4555
        if (empty($morecss) && !empty($val['css'])) {
4556
            $showsize = $val['css'];
4557
        }
4558
        if (empty($morecss)) {
4559
            if ($type == 'date') {
4560
                $morecss = 'minwidth100imp';
4561
            } elseif ($type == 'datetime') {
4562
                $morecss = 'minwidth200imp';
4563
            } elseif (in_array($type, array('int', 'integer', 'price')) || preg_match('/^double(\([0-9],[0-9]\)){0,1}/', $type)) {
4564
                $morecss = 'maxwidth75';
4565
            } elseif ($type == 'url') {
4566
                $morecss = 'minwidth400';
4567
            } elseif ($type == 'boolean') {
4568
                $morecss = '';
4569
            } else {
4570
                if (round($size) < 12) {
4571
                    $morecss = 'minwidth100';
4572
                } else if (round($size) <= 48) {
4573
                    $morecss = 'minwidth200';
4574
                } else {
4575
                    $morecss = 'minwidth400';
4576
                }
4577
            }
4578
        }
4579
4580
        if (in_array($type, array('date', 'datetime'))) {
4581
            $tmp = explode(',', $size);
4582
            $newsize = $tmp[0];
4583
4584
            $showtime = in_array($type, array('datetime')) ? 1 : 0;
4585
4586
            // Do not show current date when field not required (see selectDate() method)
4587
            if (!$required && $value == '') $value = '-1';
4588
4589
            // TODO Must also support $moreparam
4590
            $out = $form->selectDate($value, $keyprefix . $key . $keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
4591
        } elseif (in_array($type, array('int', 'integer'))) {
4592
            $tmp = explode(',', $size);
4593
            $newsize = $tmp[0];
4594
            $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 : '') . '>';
4595
        } elseif (preg_match('/varchar/', $type)) {
4596
            $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 : '') . '>';
4597
        } elseif (in_array($type, array('mail', 'phone', 'url'))) {
4598
            $out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . dol_escape_htmltag($value) . '" ' . ($moreparam ? $moreparam : '') . '>';
4599
        } elseif ($type == 'text') {
4600
            if (!preg_match('/search_/', $keyprefix))        // If keyprefix is search_ or search_options_, we must just use a simple text field
4601
            {
4602
                require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
4603
                $doleditor = new DolEditor($keyprefix . $key . $keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%');
0 ignored issues
show
Bug introduced by
The type Alixar\Base\DolEditor was not found. Did you mean DolEditor? If so, make sure to prefix the type with \.
Loading history...
4604
                $out = $doleditor->Create(1);
4605
            } else {
4606
                $out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . dol_escape_htmltag($value) . '" ' . ($moreparam ? $moreparam : '') . '>';
4607
            }
4608
        } elseif ($type == 'html') {
4609
            if (!preg_match('/search_/', $keyprefix))        // If keyprefix is search_ or search_options_, we must just use a simple text field
4610
            {
4611
                require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
4612
                $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%');
4613
                $out = $doleditor->Create(1);
4614
            } else {
4615
                $out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . dol_escape_htmltag($value) . '" ' . ($moreparam ? $moreparam : '') . '>';
4616
            }
4617
        } elseif ($type == 'boolean') {
4618
            $checked = '';
4619
            if (!empty($value)) {
4620
                $checked = ' checked value="1" ';
4621
            } else {
4622
                $checked = ' value="1" ';
4623
            }
4624
            $out = '<input type="checkbox" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" ' . $checked . ' ' . ($moreparam ? $moreparam : '') . '>';
4625
        } elseif ($type == 'price') {
4626
            if (!empty($value)) {        // $value in memory is a php numeric, we format it into user number format.
4627
                $value = price($value);
4628
            }
4629
            $out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . $value . '" ' . ($moreparam ? $moreparam : '') . '> ' . $langs->getCurrencySymbol($conf->currency);
4630
        } elseif (preg_match('/^double(\([0-9],[0-9]\)){0,1}/', $type)) {
4631
            if (!empty($value)) {        // $value in memory is a php numeric, we format it into user number format.
4632
                $value = price($value);
4633
            }
4634
            $out = '<input type="text" class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . $value . '" ' . ($moreparam ? $moreparam : '') . '> ';
4635
        } elseif ($type == 'select') {
4636
            $out = '';
4637
            if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2)) {
4638
                include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4639
                $out .= ajax_combobox($keyprefix . $key . $keysuffix, array(), 0);
4640
            }
4641
4642
            $out .= '<select class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" ' . ($moreparam ? $moreparam : '') . '>';
4643
            if ((!isset($this->fields[$key]['default'])) || ($this->fields[$key]['notnull'] != 1)) $out .= '<option value="0">&nbsp;</option>';
4644
            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...
4645
                if ((string)$key == '') continue;
4646
                list($val, $parent) = explode('|', $val);
4647
                $out .= '<option value="' . $key . '"';
4648
                $out .= (((string)$value == (string)$key) ? ' selected' : '');
4649
                $out .= (!empty($parent) ? ' parent="' . $parent . '"' : '');
4650
                $out .= '>' . $val . '</option>';
4651
            }
4652
            $out .= '</select>';
4653
        } elseif ($type == 'sellist') {
4654
            $out = '';
4655
            if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2)) {
4656
                include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4657
                $out .= ajax_combobox($keyprefix . $key . $keysuffix, array(), 0);
4658
            }
4659
4660
            $out .= '<select class="flat ' . $morecss . ' maxwidthonsmartphone" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" ' . ($moreparam ? $moreparam : '') . '>';
4661
            if (is_array($param['options'])) {
4662
                $param_list = array_keys($param['options']);
4663
                $InfoFieldList = explode(":", $param_list[0]);
4664
                $parentName = '';
4665
                $parentField = '';
4666
                // 0 : tableName
4667
                // 1 : label field name
4668
                // 2 : key fields name (if differ of rowid)
4669
                // 3 : key field parent (for dependent lists)
4670
                // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
4671
                $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
4672
4673
4674
                if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
4675
                    if (strpos($InfoFieldList[4], 'extra.') !== false) {
4676
                        $keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
4677
                    } else {
4678
                        $keyList = $InfoFieldList[2] . ' as rowid';
4679
                    }
4680
                }
4681
                if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
4682
                    list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
4683
                    $keyList .= ', ' . $parentField;
4684
                }
4685
4686
                $fields_label = explode('|', $InfoFieldList[1]);
4687
                if (is_array($fields_label)) {
4688
                    $keyList .= ', ';
4689
                    $keyList .= implode(', ', $fields_label);
4690
                }
4691
4692
                $sqlwhere = '';
4693
                $sql = 'SELECT ' . $keyList;
4694
                $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
4695
                if (!empty($InfoFieldList[4])) {
4696
                    // can use SELECT request
4697
                    if (strpos($InfoFieldList[4], '$SEL$') !== false) {
4698
                        $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
4699
                    }
4700
4701
                    // current object id can be use into filter
4702
                    if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
4703
                        $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
4704
                    } else {
4705
                        $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
4706
                    }
4707
                    //We have to join on extrafield table
4708
                    if (strpos($InfoFieldList[4], 'extra') !== false) {
4709
                        $sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
4710
                        $sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
4711
                    } else {
4712
                        $sqlwhere .= ' WHERE ' . $InfoFieldList[4];
4713
                    }
4714
                } else {
4715
                    $sqlwhere .= ' WHERE 1=1';
4716
                }
4717
                // Some tables may have field, some other not. For the moment we disable it.
4718
                if (in_array($InfoFieldList[0], array('tablewithentity'))) {
4719
                    $sqlwhere .= ' AND entity = ' . $conf->entity;
4720
                }
4721
                $sql .= $sqlwhere;
4722
                //print $sql;
4723
4724
                $sql .= ' ORDER BY ' . implode(', ', $fields_label);
4725
4726
                dol_syslog(get_class($this) . '::showInputField type=sellist', LOG_DEBUG);
4727
                $resql = $this->db->query($sql);
4728
                if ($resql) {
4729
                    $out .= '<option value="0">&nbsp;</option>';
4730
                    $num = $this->db->num_rows($resql);
4731
                    $i = 0;
4732
                    while ($i < $num) {
4733
                        $labeltoshow = '';
4734
                        $obj = $this->db->fetch_object($resql);
4735
4736
                        // Several field into label (eq table:code|libelle:rowid)
4737
                        $notrans = false;
4738
                        $fields_label = explode('|', $InfoFieldList[1]);
4739
                        if (is_array($fields_label)) {
4740
                            $notrans = true;
4741
                            foreach ($fields_label as $field_toshow) {
4742
                                $labeltoshow .= $obj->$field_toshow . ' ';
4743
                            }
4744
                        } else {
4745
                            $labeltoshow = $obj->{$InfoFieldList[1]};
4746
                        }
4747
                        $labeltoshow = dol_trunc($labeltoshow, 45);
4748
4749
                        if ($value == $obj->rowid) {
4750
                            foreach ($fields_label as $field_toshow) {
4751
                                $translabel = $langs->trans($obj->$field_toshow);
4752
                                if ($translabel != $obj->$field_toshow) {
4753
                                    $labeltoshow = dol_trunc($translabel, 18) . ' ';
4754
                                } else {
4755
                                    $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
4756
                                }
4757
                            }
4758
                            $out .= '<option value="' . $obj->rowid . '" selected>' . $labeltoshow . '</option>';
4759
                        } else {
4760
                            if (!$notrans) {
4761
                                $translabel = $langs->trans($obj->{$InfoFieldList[1]});
4762
                                if ($translabel != $obj->{$InfoFieldList[1]}) {
4763
                                    $labeltoshow = dol_trunc($translabel, 18);
4764
                                } else {
4765
                                    $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
4766
                                }
4767
                            }
4768
                            if (empty($labeltoshow)) $labeltoshow = '(not defined)';
4769
                            if ($value == $obj->rowid) {
4770
                                $out .= '<option value="' . $obj->rowid . '" selected>' . $labeltoshow . '</option>';
4771
                            }
4772
4773
                            if (!empty($InfoFieldList[3]) && $parentField) {
4774
                                $parent = $parentName . ':' . $obj->{$parentField};
4775
                            }
4776
4777
                            $out .= '<option value="' . $obj->rowid . '"';
4778
                            $out .= ($value == $obj->rowid ? ' selected' : '');
4779
                            $out .= (!empty($parent) ? ' parent="' . $parent . '"' : '');
4780
                            $out .= '>' . $labeltoshow . '</option>';
4781
                        }
4782
4783
                        $i++;
4784
                    }
4785
                    $this->db->free($resql);
4786
                } else {
4787
                    print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
4788
                }
4789
            }
4790
            $out .= '</select>';
4791
        } elseif ($type == 'checkbox') {
4792
            $value_arr = explode(',', $value);
4793
            $out = $form->multiselectarray($keyprefix . $key . $keysuffix, (empty($param['options']) ? null : $param['options']), $value_arr, '', 0, '', 0, '100%');
4794
        } elseif ($type == 'radio') {
4795
            $out = '';
4796
            foreach ($param['options'] as $keyopt => $val) {
0 ignored issues
show
introduced by
$val is overwriting one of the parameters of this function.
Loading history...
4797
                $out .= '<input class="flat ' . $morecss . '" type="radio" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" ' . ($moreparam ? $moreparam : '');
4798
                $out .= ' value="' . $keyopt . '"';
4799
                $out .= ' id="' . $keyprefix . $key . $keysuffix . '_' . $keyopt . '"';
4800
                $out .= ($value == $keyopt ? 'checked' : '');
4801
                $out .= '/><label for="' . $keyprefix . $key . $keysuffix . '_' . $keyopt . '">' . $val . '</label><br>';
4802
            }
4803
        } elseif ($type == 'chkbxlst') {
4804
            if (is_array($value)) {
4805
                $value_arr = $value;
4806
            } else {
4807
                $value_arr = explode(',', $value);
4808
            }
4809
4810
            if (is_array($param['options'])) {
4811
                $param_list = array_keys($param['options']);
4812
                $InfoFieldList = explode(":", $param_list[0]);
4813
                $parentName = '';
4814
                $parentField = '';
4815
                // 0 : tableName
4816
                // 1 : label field name
4817
                // 2 : key fields name (if differ of rowid)
4818
                // 3 : key field parent (for dependent lists)
4819
                // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
4820
                $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
4821
4822
                if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
4823
                    list ($parentName, $parentField) = explode('|', $InfoFieldList[3]);
4824
                    $keyList .= ', ' . $parentField;
4825
                }
4826
                if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
4827
                    if (strpos($InfoFieldList[4], 'extra.') !== false) {
4828
                        $keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
4829
                    } else {
4830
                        $keyList = $InfoFieldList[2] . ' as rowid';
4831
                    }
4832
                }
4833
4834
                $fields_label = explode('|', $InfoFieldList[1]);
4835
                if (is_array($fields_label)) {
4836
                    $keyList .= ', ';
4837
                    $keyList .= implode(', ', $fields_label);
4838
                }
4839
4840
                $sqlwhere = '';
4841
                $sql = 'SELECT ' . $keyList;
4842
                $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
4843
                if (!empty($InfoFieldList[4])) {
4844
4845
                    // can use SELECT request
4846
                    if (strpos($InfoFieldList[4], '$SEL$') !== false) {
4847
                        $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
4848
                    }
4849
4850
                    // current object id can be use into filter
4851
                    if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
4852
                        $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
4853
                    } else {
4854
                        $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
4855
                    }
4856
4857
                    // We have to join on extrafield table
4858
                    if (strpos($InfoFieldList[4], 'extra') !== false) {
4859
                        $sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
4860
                        $sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
4861
                    } else {
4862
                        $sqlwhere .= ' WHERE ' . $InfoFieldList[4];
4863
                    }
4864
                } else {
4865
                    $sqlwhere .= ' WHERE 1=1';
4866
                }
4867
                // Some tables may have field, some other not. For the moment we disable it.
4868
                if (in_array($InfoFieldList[0], array('tablewithentity'))) {
4869
                    $sqlwhere .= ' AND entity = ' . $conf->entity;
4870
                }
4871
                // $sql.=preg_replace('/^ AND /','',$sqlwhere);
4872
                // print $sql;
4873
4874
                $sql .= $sqlwhere;
4875
                dol_syslog(get_class($this) . '::showInputField type=chkbxlst', LOG_DEBUG);
4876
                $resql = $this->db->query($sql);
4877
                if ($resql) {
4878
                    $num = $this->db->num_rows($resql);
4879
                    $i = 0;
4880
4881
                    $data = array();
4882
4883
                    while ($i < $num) {
4884
                        $labeltoshow = '';
4885
                        $obj = $this->db->fetch_object($resql);
4886
4887
                        $notrans = false;
4888
                        // Several field into label (eq table:code|libelle:rowid)
4889
                        $fields_label = explode('|', $InfoFieldList[1]);
4890
                        if (is_array($fields_label)) {
4891
                            $notrans = true;
4892
                            foreach ($fields_label as $field_toshow) {
4893
                                $labeltoshow .= $obj->$field_toshow . ' ';
4894
                            }
4895
                        } else {
4896
                            $labeltoshow = $obj->{$InfoFieldList[1]};
4897
                        }
4898
                        $labeltoshow = dol_trunc($labeltoshow, 45);
4899
4900
                        if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
4901
                            foreach ($fields_label as $field_toshow) {
4902
                                $translabel = $langs->trans($obj->$field_toshow);
4903
                                if ($translabel != $obj->$field_toshow) {
4904
                                    $labeltoshow = dol_trunc($translabel, 18) . ' ';
4905
                                } else {
4906
                                    $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
4907
                                }
4908
                            }
4909
4910
                            $data[$obj->rowid] = $labeltoshow;
4911
                        } else {
4912
                            if (!$notrans) {
4913
                                $translabel = $langs->trans($obj->{$InfoFieldList[1]});
4914
                                if ($translabel != $obj->{$InfoFieldList[1]}) {
4915
                                    $labeltoshow = dol_trunc($translabel, 18);
4916
                                } else {
4917
                                    $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
4918
                                }
4919
                            }
4920
                            if (empty($labeltoshow))
4921
                                $labeltoshow = '(not defined)';
4922
4923
                            if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
4924
                                $data[$obj->rowid] = $labeltoshow;
4925
                            }
4926
4927
                            if (!empty($InfoFieldList[3]) && $parentField) {
4928
                                $parent = $parentName . ':' . $obj->{$parentField};
4929
                            }
4930
4931
                            $data[$obj->rowid] = $labeltoshow;
4932
                        }
4933
4934
                        $i++;
4935
                    }
4936
                    $this->db->free($resql);
4937
4938
                    $out = $form->multiselectarray($keyprefix . $key . $keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
4939
                } else {
4940
                    print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
4941
                }
4942
            }
4943
        } elseif ($type == 'link') {
4944
            $param_list = array_keys($param['options']);                // $param_list='ObjectName:classPath'
4945
            $showempty = (($required && $default != '') ? 0 : 1);
4946
            $out = $form->selectForForms($param_list[0], $keyprefix . $key . $keysuffix, $value, $showempty);
4947
            if ($conf->global->MAIN_FEATURES_LEVEL >= 2) {
4948
                list($class, $classfile) = explode(':', $param_list[0]);
4949
                if (file_exists(dol_buildpath(dirname(dirname($classfile)) . '/card.php'))) $url_path = dol_buildpath(dirname(dirname($classfile)) . '/card.php', 1);
4950
                else $url_path = dol_buildpath(dirname(dirname($classfile)) . '/' . $class . '_card.php', 1);
4951
                $out .= '<a class="butActionNew" href="' . $url_path . '?action=create&backtopage=' . $_SERVER['PHP_SELF'] . '"><span class="fa fa-plus-circle valignmiddle"></span></a>';
4952
                // TODO Add Javascript code to add input fields contents to new elements urls
4953
            }
4954
        } elseif ($type == 'password') {
4955
            // If prefix is 'search_', field is used as a filter, we use a common text field.
4956
            $out = '<input type="' . ($keyprefix == 'search_' ? 'text' : 'password') . '" class="flat ' . $morecss . '" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '" value="' . $value . '" ' . ($moreparam ? $moreparam : '') . '>';
4957
        } elseif ($type == 'array') {
4958
            $newval = $val;
4959
            $newval['type'] = 'varchar(256)';
4960
4961
            $out = '';
4962
4963
            $inputs = array();
4964
            if (!empty($value)) {
4965
                foreach ($value as $option) {
0 ignored issues
show
Bug introduced by
The expression $value of type string is not traversable.
Loading history...
4966
                    $out .= '<span><a class="' . dol_escape_htmltag($keyprefix . $key . $keysuffix) . '_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
4967
                    $out .= $this->showInputField($newval, $keyprefix . $key . $keysuffix . '[]', $option, $moreparam, '', '', $showsize) . '<br></span>';
4968
                }
4969
            }
4970
4971
            $out .= '<a id="' . dol_escape_htmltag($keyprefix . $key . $keysuffix) . '_add" href="javascript:;"><span class="fa fa-plus-circle valignmiddle"></span></a>';
4972
4973
            $newInput = '<span><a class="' . dol_escape_htmltag($keyprefix . $key . $keysuffix) . '_del" href="javascript:;"><span class="fa fa-minus-circle valignmiddle"></span></a> ';
4974
            $newInput .= $this->showInputField($newval, $keyprefix . $key . $keysuffix . '[]', '', $moreparam, '', '', $showsize) . '<br></span>';
4975
4976
            if (!empty($conf->use_javascript_ajax)) {
4977
                $out .= '
4978
					<script type="text/javascript">
4979
					$(document).ready(function() {
4980
						$("a#' . dol_escape_js($keyprefix . $key . $keysuffix) . '_add").click(function() {
4981
							$("' . dol_escape_js($newInput) . '").insertBefore(this);
4982
						});
4983
4984
						$(document).on("click", "a.' . dol_escape_js($keyprefix . $key . $keysuffix) . '_del", function() {
4985
							$(this).parent().remove();
4986
						});
4987
					});
4988
					</script>';
4989
            }
4990
        }
4991
        if (!empty($hidden)) {
4992
            $out = '<input type="hidden" value="' . $value . '" name="' . $keyprefix . $key . $keysuffix . '" id="' . $keyprefix . $key . $keysuffix . '"/>';
4993
        }
4994
        /* Add comments
4995
		 if ($type == 'date') $out.=' (YYYY-MM-DD)';
4996
		 elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
4997
		 */
4998
        return $out;
4999
    }
5000
5001
    /**
5002
     * Return HTML string to show a field into a page
5003
     * Code very similar with showOutputField of extra fields
5004
     *
5005
     * @param array $val Array of properties of field to show
5006
     * @param string $key Key of attribute
5007
     * @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)
5008
     * @param string $moreparam To add more parametes on html input tag
5009
     * @param string $keysuffix Prefix string to add into name and id of field (can be used to avoid duplicate names)
5010
     * @param string $keyprefix Suffix string to add into name and id of field (can be used to avoid duplicate names)
5011
     * @param mixed $showsize Value for css to define size. May also be a numeric.
5012
     * @return string
5013
     */
5014
    function showOutputField($val, $key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $showsize = 0)
5015
    {
5016
        global $conf, $langs, $form;
5017
5018
        if (!is_object($form)) {
5019
            require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php';
5020
            $form = new Form($this->db);
5021
        }
5022
5023
        $objectid = $this->id;
5024
        $label = $val['label'];
5025
        $type = $val['type'];
5026
        $size = $val['css'];
5027
5028
        // Convert var to be able to share same code than showOutputField of extrafields
5029
        if (preg_match('/varchar\((\d+)\)/', $type, $reg)) {
5030
            $type = 'varchar';        // convert varchar(xx) int varchar
5031
            $size = $reg[1];
5032
        } elseif (preg_match('/varchar/', $type)) $type = 'varchar';        // convert varchar(xx) int varchar
5033
        if (is_array($val['arrayofkeyval'])) $type = 'select';
5034
        if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) $type = 'link';
5035
5036
        $default = $val['default'];
5037
        $computed = $val['computed'];
5038
        $unique = $val['unique'];
5039
        $required = $val['required'];
5040
        $param = $val['param'];
5041
        if (is_array($val['arrayofkeyval'])) $param['options'] = $val['arrayofkeyval'];
5042
        if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
5043
            $type = 'link';
5044
            $param['options'] = array($reg[1] . ':' . $reg[2] => $reg[1] . ':' . $reg[2]);
5045
        }
5046
        $langfile = $val['langfile'];
5047
        $list = $val['list'];
5048
        $help = $val['help'];
5049
        $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)
5050
5051
        if ($hidden) return '';
5052
5053
        // If field is a computed field, value must become result of compute
5054
        if ($computed) {
5055
            // Make the eval of compute string
5056
            //var_dump($computed);
5057
            $value = dol_eval($computed, 1, 0);
5058
        }
5059
5060
        if (empty($showsize)) {
5061
            if ($type == 'date') {
5062
                //$showsize=10;
5063
                $showsize = 'minwidth100imp';
5064
            } elseif ($type == 'datetime') {
5065
                //$showsize=19;
5066
                $showsize = 'minwidth200imp';
5067
            } elseif (in_array($type, array('int', 'double', 'price'))) {
5068
                //$showsize=10;
5069
                $showsize = 'maxwidth75';
5070
            } elseif ($type == 'url') {
5071
                $showsize = 'minwidth400';
5072
            } elseif ($type == 'boolean') {
5073
                $showsize = '';
5074
            } else {
5075
                if (round($size) < 12) {
5076
                    $showsize = 'minwidth100';
5077
                } else if (round($size) <= 48) {
5078
                    $showsize = 'minwidth200';
5079
                } else {
5080
                    //$showsize=48;
5081
                    $showsize = 'minwidth400';
5082
                }
5083
            }
5084
        }
5085
5086
        // Format output value differently according to properties of field
5087
        if ($key == 'ref' && method_exists($this, 'getNomUrl')) $value = $this->getNomUrl(1, '', 0, '', 1);
5088
        elseif ($key == 'status' && method_exists($this, 'getLibStatut')) $value = $this->getLibStatut(3);
5089
        elseif ($type == 'date') {
5090
            if (!empty($value)) {
5091
                $value = dol_print_date($value, 'day');
5092
            } else {
5093
                $value = '';
5094
            }
5095
        } elseif ($type == 'datetime') {
5096
            if (!empty($value)) {
5097
                $value = dol_print_date($value, 'dayhour');
5098
            } else {
5099
                $value = '';
5100
            }
5101
        } elseif ($type == 'double') {
5102
            if (!empty($value)) {
5103
                $value = price($value);
5104
            }
5105
        } elseif ($type == 'boolean') {
5106
            $checked = '';
5107
            if (!empty($value)) {
5108
                $checked = ' checked ';
5109
            }
5110
            $value = '<input type="checkbox" ' . $checked . ' ' . ($moreparam ? $moreparam : '') . ' readonly disabled>';
5111
        } elseif ($type == 'mail') {
5112
            $value = dol_print_email($value, 0, 0, 0, 64, 1, 1);
5113
        } elseif ($type == 'url') {
5114
            $value = dol_print_url($value, '_blank', 32, 1);
5115
        } elseif ($type == 'phone') {
5116
            $value = dol_print_phone($value, '', 0, 0, '', '&nbsp;', 1);
5117
        } elseif ($type == 'price') {
5118
            $value = price($value, 0, $langs, 0, 0, -1, $conf->currency);
5119
        } elseif ($type == 'select') {
5120
            $value = $param['options'][$value];
5121
        } elseif ($type == 'sellist') {
5122
            $param_list = array_keys($param['options']);
5123
            $InfoFieldList = explode(":", $param_list[0]);
5124
5125
            $selectkey = "rowid";
5126
            $keyList = 'rowid';
5127
5128
            if (count($InfoFieldList) >= 3) {
5129
                $selectkey = $InfoFieldList[2];
5130
                $keyList = $InfoFieldList[2] . ' as rowid';
5131
            }
5132
5133
            $fields_label = explode('|', $InfoFieldList[1]);
5134
            if (is_array($fields_label)) {
5135
                $keyList .= ', ';
5136
                $keyList .= implode(', ', $fields_label);
5137
            }
5138
5139
            $sql = 'SELECT ' . $keyList;
5140
            $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
5141
            if (strpos($InfoFieldList[4], 'extra') !== false) {
5142
                $sql .= ' as main';
5143
            }
5144
            if ($selectkey == 'rowid' && empty($value)) {
5145
                $sql .= " WHERE " . $selectkey . "=0";
5146
            } elseif ($selectkey == 'rowid') {
5147
                $sql .= " WHERE " . $selectkey . "=" . $this->db->escape($value);
5148
            } else {
5149
                $sql .= " WHERE " . $selectkey . "='" . $this->db->escape($value) . "'";
5150
            }
5151
5152
            //$sql.= ' AND entity = '.$conf->entity;
5153
5154
            dol_syslog(get_class($this) . ':showOutputField:$type=sellist', LOG_DEBUG);
5155
            $resql = $this->db->query($sql);
5156
            if ($resql) {
5157
                $value = '';    // value was used, so now we reste it to use it to build final output
5158
5159
                $obj = $this->db->fetch_object($resql);
5160
5161
                // Several field into label (eq table:code|libelle:rowid)
5162
                $fields_label = explode('|', $InfoFieldList[1]);
5163
5164
                if (is_array($fields_label) && count($fields_label) > 1) {
5165
                    foreach ($fields_label as $field_toshow) {
5166
                        $translabel = '';
5167
                        if (!empty($obj->$field_toshow)) {
5168
                            $translabel = $langs->trans($obj->$field_toshow);
5169
                        }
5170
                        if ($translabel != $field_toshow) {
5171
                            $value .= dol_trunc($translabel, 18) . ' ';
5172
                        } else {
5173
                            $value .= $obj->$field_toshow . ' ';
5174
                        }
5175
                    }
5176
                } else {
5177
                    $translabel = '';
5178
                    if (!empty($obj->{$InfoFieldList[1]})) {
5179
                        $translabel = $langs->trans($obj->{$InfoFieldList[1]});
5180
                    }
5181
                    if ($translabel != $obj->{$InfoFieldList[1]}) {
5182
                        $value = dol_trunc($translabel, 18);
5183
                    } else {
5184
                        $value = $obj->{$InfoFieldList[1]};
5185
                    }
5186
                }
5187
            } else dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING);
5188
        } elseif ($type == 'radio') {
5189
            $value = $param['options'][$value];
5190
        } elseif ($type == 'checkbox') {
5191
            $value_arr = explode(',', $value);
5192
            $value = '';
5193
            if (is_array($value_arr) && count($value_arr) > 0) {
5194
                foreach ($value_arr as $keyval => $valueval) {
5195
                    $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">' . $param['options'][$valueval] . '</li>';
5196
                }
5197
                $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $toprint seems to be defined by a foreach iteration on line 5194. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
5198
            }
5199
        } elseif ($type == 'chkbxlst') {
5200
            $value_arr = explode(',', $value);
5201
5202
            $param_list = array_keys($param['options']);
5203
            $InfoFieldList = explode(":", $param_list[0]);
5204
5205
            $selectkey = "rowid";
5206
            $keyList = 'rowid';
5207
5208
            if (count($InfoFieldList) >= 3) {
5209
                $selectkey = $InfoFieldList[2];
5210
                $keyList = $InfoFieldList[2] . ' as rowid';
5211
            }
5212
5213
            $fields_label = explode('|', $InfoFieldList[1]);
5214
            if (is_array($fields_label)) {
5215
                $keyList .= ', ';
5216
                $keyList .= implode(', ', $fields_label);
5217
            }
5218
5219
            $sql = 'SELECT ' . $keyList;
5220
            $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
5221
            if (strpos($InfoFieldList[4], 'extra') !== false) {
5222
                $sql .= ' as main';
5223
            }
5224
            // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
5225
            // $sql.= ' AND entity = '.$conf->entity;
5226
5227
            dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst', LOG_DEBUG);
5228
            $resql = $this->db->query($sql);
5229
            if ($resql) {
5230
                $value = ''; // value was used, so now we reste it to use it to build final output
5231
                $toprint = array();
5232
                while ($obj = $this->db->fetch_object($resql)) {
5233
5234
                    // Several field into label (eq table:code|libelle:rowid)
5235
                    $fields_label = explode('|', $InfoFieldList[1]);
5236
                    if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
5237
                        if (is_array($fields_label) && count($fields_label) > 1) {
5238
                            foreach ($fields_label as $field_toshow) {
5239
                                $translabel = '';
5240
                                if (!empty($obj->$field_toshow)) {
5241
                                    $translabel = $langs->trans($obj->$field_toshow);
5242
                                }
5243
                                if ($translabel != $field_toshow) {
5244
                                    $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">' . dol_trunc($translabel, 18) . '</li>';
5245
                                } else {
5246
                                    $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">' . $obj->$field_toshow . '</li>';
5247
                                }
5248
                            }
5249
                        } else {
5250
                            $translabel = '';
5251
                            if (!empty($obj->{$InfoFieldList[1]})) {
5252
                                $translabel = $langs->trans($obj->{$InfoFieldList[1]});
5253
                            }
5254
                            if ($translabel != $obj->{$InfoFieldList[1]}) {
5255
                                $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">' . dol_trunc($translabel, 18) . '</li>';
5256
                            } else {
5257
                                $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">' . $obj->{$InfoFieldList[1]} . '</li>';
5258
                            }
5259
                        }
5260
                    }
5261
                }
5262
                $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
5263
            } else {
5264
                dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING);
5265
            }
5266
        } elseif ($type == 'link') {
5267
            $out = '';
5268
5269
            // only if something to display (perf)
5270
            if ($value) {
5271
                $param_list = array_keys($param['options']);                // $param_list='ObjectName:classPath'
5272
5273
                $InfoFieldList = explode(":", $param_list[0]);
5274
                $classname = $InfoFieldList[0];
5275
                $classpath = $InfoFieldList[1];
5276
                $getnomurlparam = (empty($InfoFieldList[2]) ? 3 : $InfoFieldList[2]);
5277
                if (!empty($classpath)) {
5278
                    dol_include_once($InfoFieldList[1]);
5279
                    if ($classname && class_exists($classname)) {
5280
                        $object = new $classname($this->db);
5281
                        $object->fetch($value);
5282
                        $value = $object->getNomUrl($getnomurlparam);
5283
                    }
5284
                } else {
5285
                    dol_syslog('Error bad setup of extrafield', LOG_WARNING);
5286
                    return 'Error bad setup of extrafield';
5287
                }
5288
            } else $value = '';
5289
        } elseif ($type == 'text' || $type == 'html') {
5290
            $value = dol_htmlentitiesbr($value);
5291
        } elseif ($type == 'password') {
5292
            $value = preg_replace('/./i', '*', $value);
5293
        } elseif ($type == 'array') {
5294
            $value = implode('<br>', $value);
5295
        }
5296
5297
        //print $type.'-'.$size;
5298
        $out = $value;
5299
5300
        return $out;
5301
    }
5302
5303
    /**
5304
     * Function to show lines of extrafields with output datas
5305
     *
5306
     * @param Extrafields $extrafields Extrafield Object
0 ignored issues
show
Bug introduced by
The type Alixar\Base\Extrafields was not found. Did you mean Extrafields? If so, make sure to prefix the type with \.
Loading history...
5307
     * @param string $mode Show output (view) or input (edit) for extrafield
5308
     * @param array $params Optional parameters. Example: array('style'=>'class="oddeven"', 'colspan'=>$colspan)
5309
     * @param string $keysuffix Suffix string to add after name and id of field (can be used to avoid duplicate names)
5310
     * @param string $keyprefix Prefix string to add before name and id of field (can be used to avoid duplicate names)
5311
     * @param string $onetrtd All fields in same tr td
5312
     * @return    string
5313
     */
5314
    function showOptionals($extrafields, $mode = 'view', $params = null, $keysuffix = '', $keyprefix = '', $onetrtd = 0)
5315
    {
5316
        global $db, $conf, $langs, $action, $form;
5317
5318
        if (!is_object($form)) $form = new Form($db);
5319
5320
        $out = '';
5321
5322
        if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label']) > 0) {
5323
            $out .= "\n";
5324
            $out .= '<!-- showOptionalsInput --> ';
5325
            $out .= "\n";
5326
5327
            $e = 0;
5328
            foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $label) {
5329
                // Show only the key field in params
5330
                if (is_array($params) && array_key_exists('onlykey', $params) && $key != $params['onlykey']) continue;
5331
5332
                $enabled = 1;
5333
                if ($enabled && isset($extrafields->attributes[$this->table_element]['list'][$key])) {
5334
                    $enabled = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1);
5335
                }
5336
5337
                $perms = 1;
5338
                if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key])) {
5339
                    $perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1);
5340
                }
5341
5342
                if (($mode == 'create' || $mode == 'edit') && abs($enabled) != 1 && abs($enabled) != 3) continue;    // <> -1 and <> 1 and <> 3 = not visible on forms, only on list
5343
                if (empty($perms)) continue;
5344
5345
                // Load language if required
5346
                if (!empty($extrafields->attributes[$this->table_element]['langfile'][$key])) $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
5347
5348
                $colspan = '3';
5349
                if (is_array($params) && count($params) > 0) {
5350
                    if (array_key_exists('colspan', $params)) {
5351
                        $colspan = $params['colspan'];
5352
                    }
5353
                }
5354
5355
                switch ($mode) {
5356
                    case "view":
5357
                        $value = $this->array_options["options_" . $key . $keysuffix];
5358
                        break;
5359
                    case "edit":
5360
                        $getposttemp = GETPOST($keyprefix . 'options_' . $key . $keysuffix, 'none');                // GETPOST can get value from GET, POST or setup of default values.
5361
                        // GETPOST("options_" . $key) can be 'abc' or array(0=>'abc')
5362
                        if (is_array($getposttemp) || $getposttemp != '' || GETPOSTISSET($keyprefix . 'options_' . $key . $keysuffix)) {
5363
                            if (is_array($getposttemp)) {
5364
                                // $getposttemp is an array but following code expects a comma separated string
5365
                                $value = implode(",", $getposttemp);
5366
                            } else {
5367
                                $value = $getposttemp;
5368
                            }
5369
                        } else {
5370
                            $value = $this->array_options["options_" . $key];            // No GET, no POST, no default value, so we take value of object.
5371
                        }
5372
                        //var_dump($keyprefix.' - '.$key.' - '.$keysuffix.' - '.$keyprefix.'options_'.$key.$keysuffix.' - '.$this->array_options["options_".$key.$keysuffix].' - '.$getposttemp.' - '.$value);
5373
                        break;
5374
                }
5375
5376
                if ($extrafields->attributes[$this->table_element]['type'][$key] == 'separate') {
5377
                    $out .= $extrafields->showSeparator($key, $this);
5378
                } else {
5379
                    $csstyle = '';
5380
                    $class = (!empty($extrafields->attributes[$this->table_element]['hidden'][$key]) ? 'hideobject ' : '');
5381
                    if (is_array($params) && count($params) > 0) {
5382
                        if (array_key_exists('style', $params)) {
5383
                            $csstyle = $params['style'];
5384
                        }
5385
                    }
5386
5387
                    // add html5 elements
5388
                    $domData = ' data-element="extrafield"';
5389
                    $domData .= ' data-targetelement="' . $this->element . '"';
5390
                    $domData .= ' data-targetid="' . $this->id . '"';
5391
5392
                    $html_id = !empty($this->id) ? 'extrarow-' . $this->element . '_' . $key . '_' . $this->id : '';
5393
5394
                    $out .= '<tr id="' . $html_id . '" ' . $csstyle . ' class="' . $class . $this->element . '_extras_' . $key . '" ' . $domData . ' >';
5395
5396
                    if (!empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) {
5397
                        if (!empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) {
5398
                            $colspan = '0';
5399
                        }
5400
                    }
5401
5402
                    if ($action == 'selectlines') {
5403
                        $colspan++;
5404
                    }
5405
5406
                    // Convert date into timestamp format (value in memory must be a timestamp)
5407
                    if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('date', 'datetime'))) {
5408
                        $datenotinstring = $this->array_options['options_' . $key];
5409
                        if (!is_numeric($this->array_options['options_' . $key]))    // For backward compatibility
5410
                        {
5411
                            $datenotinstring = $this->db->jdate($datenotinstring);
5412
                        }
5413
                        $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;
5414
                    }
5415
                    // Convert float submited string into real php numeric (value in memory must be a php numeric)
5416
                    if (in_array($extrafields->attributes[$this->table_element]['type'][$key], array('price', 'double'))) {
5417
                        $value = GETPOSTISSET($keyprefix . 'options_' . $key . $keysuffix) ? price2num(GETPOST($keyprefix . 'options_' . $key . $keysuffix, 'alpha', 3)) : $this->array_options['options_' . $key];
5418
                    }
5419
5420
                    $labeltoshow = $langs->trans($label);
5421
5422
                    $out .= '<td class="titlefield';
5423
                    if (GETPOST('action', 'none') == 'create') $out .= 'create';
5424
                    if ($mode != 'view' && !empty($extrafields->attributes[$this->table_element]['required'][$key])) $out .= ' fieldrequired';
5425
                    $out .= '">';
5426
                    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...
5427
                    else $out .= $labeltoshow;
5428
                    $out .= '</td>';
5429
5430
                    $html_id = !empty($this->id) ? $this->element . '_extras_' . $key . '_' . $this->id : '';
5431
                    $out .= '<td id="' . $html_id . '" class="' . $this->element . '_extras_' . $key . '" ' . ($colspan ? ' colspan="' . $colspan . '"' : '') . '>';
5432
5433
                    switch ($mode) {
5434
                        case "view":
5435
                            $out .= $extrafields->showOutputField($key, $value);
5436
                            break;
5437
                        case "edit":
5438
                            $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id);
5439
                            break;
5440
                    }
5441
5442
                    $out .= '</td>';
5443
5444
                    if (!empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && (($e % 2) == 1)) $out .= '</tr>';
5445
                    else $out .= '</tr>';
5446
                    $e++;
5447
                }
5448
            }
5449
            $out .= "\n";
5450
            // Add code to manage list depending on others
5451
            if (!empty($conf->use_javascript_ajax)) {
5452
                $out .= '
5453
				<script type="text/javascript">
5454
				    jQuery(document).ready(function() {
5455
				    	function showOptions(child_list, parent_list)
5456
				    	{
5457
				    		var val = $("select[name=\"options_"+parent_list+"\"]").val();
5458
				    		var parentVal = parent_list + ":" + val;
5459
							if(val > 0) {
5460
					    		$("select[name=\""+child_list+"\"] option[parent]").hide();
5461
					    		$("select[name=\""+child_list+"\"] option[parent=\""+parentVal+"\"]").show();
5462
							} else {
5463
								$("select[name=\""+child_list+"\"] option").show();
5464
							}
5465
				    	}
5466
						function setListDependencies() {
5467
					    	jQuery("select option[parent]").parent().each(function() {
5468
					    		var child_list = $(this).attr("name");
5469
								var parent = $(this).find("option[parent]:first").attr("parent");
5470
								var infos = parent.split(":");
5471
								var parent_list = infos[0];
5472
								$("select[name=\""+parent_list+"\"]").change(function() {
5473
									showOptions(child_list, parent_list);
5474
								});
5475
					    	});
5476
						}
5477
5478
						setListDependencies();
5479
				    });
5480
				</script>' . "\n";
5481
                $out .= '<!-- /showOptionalsInput --> ' . "\n";
5482
            }
5483
        }
5484
        return $out;
5485
    }
5486
5487
    /**
5488
     * Get buy price to use for margin calculation. This function is called when buy price is unknown.
5489
     *     Set buy price = sell price if ForceBuyingPriceIfNull configured,
5490
     *   else if calculation MARGIN_TYPE = 'costprice' and costprice is defined, use costprice as buyprice
5491
     *     else if calculation MARGIN_TYPE = 'pmp' and pmp is calculated, use pmp as buyprice
5492
     *     else set min buy price as buy price
5493
     *
5494
     * @param float $unitPrice Product unit price
5495
     * @param float $discountPercent Line discount percent
5496
     * @param int $fk_product Product id
5497
     * @return    float                    <0 if KO, buyprice if OK
5498
     */
5499
    public function defineBuyPrice($unitPrice = 0.0, $discountPercent = 0.0, $fk_product = 0)
5500
    {
5501
        global $conf;
5502
5503
        $buyPrice = 0;
5504
5505
        if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) // In most cases, test here is false
5506
        {
5507
            $buyPrice = $unitPrice * (1 - $discountPercent / 100);
5508
        } else {
5509
            // Get cost price for margin calculation
5510
            if (!empty($fk_product)) {
5511
                if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'costprice') {
5512
                    require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
5513
                    $product = new Product($this->db);
5514
                    $result = $product->fetch($fk_product);
5515
                    if ($result <= 0) {
5516
                        $this->errors[] = 'ErrorProductIdDoesNotExists';
5517
                        return -1;
5518
                    }
5519
                    if ($product->cost_price > 0) {
5520
                        $buyPrice = $product->cost_price;
5521
                    } else if ($product->pmp > 0) {
5522
                        $buyPrice = $product->pmp;
5523
                    }
5524
                } else if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'pmp') {
5525
                    require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
5526
                    $product = new Product($this->db);
5527
                    $result = $product->fetch($fk_product);
5528
                    if ($result <= 0) {
5529
                        $this->errors[] = 'ErrorProductIdDoesNotExists';
5530
                        return -1;
5531
                    }
5532
                    if ($product->pmp > 0) {
5533
                        $buyPrice = $product->pmp;
5534
                    }
5535
                }
5536
5537
                if (empty($buyPrice) && isset($conf->global->MARGIN_TYPE) && in_array($conf->global->MARGIN_TYPE, array('1', 'pmp', 'costprice'))) {
5538
                    require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php';
5539
                    $productFournisseur = new ProductFournisseur($this->db);
0 ignored issues
show
Bug introduced by
The type Alixar\Base\ProductFournisseur was not found. Did you mean ProductFournisseur? If so, make sure to prefix the type with \.
Loading history...
5540
                    if (($result = $productFournisseur->find_min_price_product_fournisseur($fk_product)) > 0) {
5541
                        $buyPrice = $productFournisseur->fourn_unitprice;
5542
                    } else if ($result < 0) {
5543
                        $this->errors[] = $productFournisseur->error;
5544
                        return -2;
5545
                    }
5546
                }
5547
            }
5548
        }
5549
        return $buyPrice;
5550
    }
5551
5552
    /**
5553
     *  Show photos of an object (nbmax maximum), into several columns
5554
     *
5555
     * @param string $modulepart 'product', 'ticket', ...
5556
     * @param string $sdir Directory to scan (full absolute path)
5557
     * @param int $size 0=original size, 1='small' use thumbnail if possible
5558
     * @param int $nbmax Nombre maximum de photos (0=pas de max)
5559
     * @param int $nbbyrow Number of image per line or -1 to use div. Used only if size=1.
5560
     * @param int $showfilename 1=Show filename
5561
     * @param int $showaction 1=Show icon with action links (resize, delete)
5562
     * @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.
5563
     * @param int $maxWidth Max width of original image when size='small'
5564
     * @param int $nolink Do not add a href link to view enlarged imaged into a new tab
5565
     * @param int $notitle Do not add title tag on image
5566
     * @param int $usesharelink Use the public shared link of image (if not available, the 'nophoto' image will be shown instead)
5567
     * @return     string                    Html code to show photo. Number of photos shown is saved in this->nbphoto
5568
     */
5569
    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)
5570
    {
5571
        // phpcs:enable
5572
        global $conf, $user, $langs;
5573
5574
        include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
5575
        include_once DOL_DOCUMENT_ROOT . '/core/lib/images.lib.php';
5576
5577
        $sortfield = 'position_name';
5578
        $sortorder = 'asc';
5579
5580
        $dir = $sdir . '/';
5581
        $pdir = '/';
5582
        if ($modulepart == 'ticket') {
5583
            $dir .= get_exdir(0, 0, 0, 0, $this, $modulepart) . $this->track_id . '/';
5584
            $pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart) . $this->track_id . '/';
5585
        } else {
5586
            $dir .= get_exdir(0, 0, 0, 0, $this, $modulepart) . $this->ref . '/';
5587
            $pdir .= get_exdir(0, 0, 0, 0, $this, $modulepart) . $this->ref . '/';
5588
        }
5589
5590
        // For backward compatibility
5591
        if ($modulepart == 'product' && !empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) {
5592
            $dir = $sdir . '/' . get_exdir($this->id, 2, 0, 0, $this, $modulepart) . $this->id . "/photos/";
5593
            $pdir = '/' . get_exdir($this->id, 2, 0, 0, $this, $modulepart) . $this->id . "/photos/";
5594
        }
5595
5596
        // Defined relative dir to DOL_DATA_ROOT
5597
        $relativedir = '';
5598
        if ($dir) {
5599
            $relativedir = preg_replace('/^' . preg_quote(DOL_DATA_ROOT, '/') . '/', '', $dir);
5600
            $relativedir = preg_replace('/^[\\/]/', '', $relativedir);
5601
            $relativedir = preg_replace('/[\\/]$/', '', $relativedir);
5602
        }
5603
5604
        $dirthumb = $dir . 'thumbs/';
5605
        $pdirthumb = $pdir . 'thumbs/';
5606
5607
        $return = '<!-- Photo -->' . "\n";
5608
        $nbphoto = 0;
5609
5610
        $filearray = dol_dir_list($dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ? SORT_DESC : SORT_ASC), 1);
5611
5612
        /*if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))    // For backward compatiblity, we scan also old dirs
5613
		 {
5614
		 $filearrayold=dol_dir_list($dirold,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);
5615
		 $filearray=array_merge($filearray, $filearrayold);
5616
		 }*/
5617
5618
        completeFileArrayWithDatabaseInfo($filearray, $relativedir);
5619
5620
        if (count($filearray)) {
5621
            if ($sortfield && $sortorder) {
5622
                $filearray = dol_sort_array($filearray, $sortfield, $sortorder);
5623
            }
5624
5625
            foreach ($filearray as $key => $val) {
5626
                $photo = '';
5627
                $file = $val['name'];
5628
5629
                //if (! utf8_check($file)) $file=utf8_encode($file);	// To be sure file is stored in UTF8 in memory
5630
5631
                //if (dol_is_file($dir.$file) && image_format_supported($file) >= 0)
5632
                if (image_format_supported($file) >= 0) {
5633
                    $nbphoto++;
5634
                    $photo = $file;
5635
                    $viewfilename = $file;
5636
5637
                    if ($size == 1 || $size == 'small') {   // Format vignette
5638
5639
                        // Find name of thumb file
5640
                        $photo_vignette = basename(getImageFileNameForSize($dir . $file, '_small'));
5641
                        if (!dol_is_file($dirthumb . $photo_vignette)) $photo_vignette = '';
5642
5643
                        // Get filesize of original file
5644
                        $imgarray = dol_getImageSize($dir . $photo);
5645
5646
                        if ($nbbyrow > 0) {
5647
                            if ($nbphoto == 1) $return .= '<table width="100%" valign="top" align="center" border="0" cellpadding="2" cellspacing="2">';
5648
5649
                            if ($nbphoto % $nbbyrow == 1) $return .= '<tr align=center valign=middle border=1>';
5650
                            $return .= '<td width="' . ceil(100 / $nbbyrow) . '%" class="photo">';
5651
                        } else if ($nbbyrow < 0) $return .= '<div class="inline-block">';
5652
5653
                        $return .= "\n";
5654
5655
                        $relativefile = preg_replace('/^\//', '', $pdir . $photo);
5656
                        if (empty($nolink)) {
5657
                            $urladvanced = getAdvancedPreviewUrl($modulepart, $relativefile, 0, 'entity=' . $this->entity);
5658
                            if ($urladvanced) $return .= '<a href="' . $urladvanced . '">';
5659
                            else $return .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $this->entity . '&file=' . urlencode($pdir . $photo) . '" class="aphoto" target="_blank">';
5660
                        }
5661
5662
                        // Show image (width height=$maxHeight)
5663
                        // Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine
5664
                        $alt = $langs->transnoentitiesnoconv('File') . ': ' . $relativefile;
5665
                        $alt .= ' - ' . $langs->transnoentitiesnoconv('Size') . ': ' . $imgarray['width'] . 'x' . $imgarray['height'];
5666
                        if ($notitle) $alt = '';
5667
5668
                        if ($usesharelink) {
5669
                            if ($val['share']) {
5670
                                if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight) {
5671
                                    $return .= '<!-- Show original file (thumb not yet available with shared links) -->';
5672
                                    $return .= '<img class="photo photowithmargin" border="0" height="' . $maxHeight . '" src="' . DOL_URL_ROOT . '/viewimage.php?hashp=' . urlencode($val['share']) . '" title="' . dol_escape_htmltag($alt) . '">';
5673
                                } else {
5674
                                    $return .= '<!-- Show original file -->';
5675
                                    $return .= '<img class="photo photowithmargin" border="0" height="' . $maxHeight . '" src="' . DOL_URL_ROOT . '/viewimage.php?hashp=' . urlencode($val['share']) . '" title="' . dol_escape_htmltag($alt) . '">';
5676
                                }
5677
                            } else {
5678
                                $return .= '<!-- Show nophoto file (because file is not shared) -->';
5679
                                $return .= '<img class="photo photowithmargin" border="0" height="' . $maxHeight . '" src="' . DOL_URL_ROOT . '/public/theme/common/nophoto.png" title="' . dol_escape_htmltag($alt) . '">';
5680
                            }
5681
                        } else {
5682
                            if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight) {
5683
                                $return .= '<!-- Show thumb -->';
5684
                                $return .= '<img class="photo photowithmargin" border="0" height="' . $maxHeight . '" src="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $this->entity . '&file=' . urlencode($pdirthumb . $photo_vignette) . '" title="' . dol_escape_htmltag($alt) . '">';
5685
                            } else {
5686
                                $return .= '<!-- Show original file -->';
5687
                                $return .= '<img class="photo photowithmargin" border="0" height="' . $maxHeight . '" src="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $this->entity . '&file=' . urlencode($pdir . $photo) . '" title="' . dol_escape_htmltag($alt) . '">';
5688
                            }
5689
                        }
5690
5691
                        if (empty($nolink)) $return .= '</a>';
5692
                        $return .= "\n";
5693
5694
                        if ($showfilename) $return .= '<br>' . $viewfilename;
5695
                        if ($showaction) {
5696
                            $return .= '<br>';
5697
                            // On propose la generation de la vignette si elle n'existe pas et si la taille est superieure aux limites
5698
                            if ($photo_vignette && (image_format_supported($photo) > 0) && ($this->imgWidth > $maxWidth || $this->imgHeight > $maxHeight)) {
5699
                                $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>';
5700
                            }
5701
                            // Special cas for product
5702
                            if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer)) {
5703
                                // Link to resize
5704
                                $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; ';
5705
5706
                                // Link to delete
5707
                                $return .= '<a href="' . $_SERVER["PHP_SELF"] . '?id=' . $this->id . '&amp;action=delete&amp;file=' . urlencode($pdir . $viewfilename) . '">';
5708
                                $return .= img_delete() . '</a>';
5709
                            }
5710
                        }
5711
                        $return .= "\n";
5712
5713
                        if ($nbbyrow > 0) {
5714
                            $return .= '</td>';
5715
                            if (($nbphoto % $nbbyrow) == 0) $return .= '</tr>';
5716
                        } else if ($nbbyrow < 0) $return .= '</div>';
5717
                    }
5718
5719
                    if (empty($size)) {     // Format origine
5720
                        $return .= '<img class="photo photowithmargin" border="0" src="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $this->entity . '&file=' . urlencode($pdir . $photo) . '">';
5721
5722
                        if ($showfilename) $return .= '<br>' . $viewfilename;
5723
                        if ($showaction) {
5724
                            // Special case for product
5725
                            if ($modulepart == 'product' && ($user->rights->produit->creer || $user->rights->service->creer)) {
5726
                                // Link to resize
5727
                                $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; ';
5728
5729
                                // Link to delete
5730
                                $return .= '<a href="' . $_SERVER["PHP_SELF"] . '?id=' . $this->id . '&amp;action=delete&amp;file=' . urlencode($pdir . $viewfilename) . '">';
5731
                                $return .= img_delete() . '</a>';
5732
                            }
5733
                        }
5734
                    }
5735
5736
                    // On continue ou on arrete de boucler ?
5737
                    if ($nbmax && $nbphoto >= $nbmax) break;
5738
                }
5739
            }
5740
5741
            if ($size == 1 || $size == 'small') {
5742
                if ($nbbyrow > 0) {
5743
                    // Ferme tableau
5744
                    while ($nbphoto % $nbbyrow) {
5745
                        $return .= '<td width="' . ceil(100 / $nbbyrow) . '%">&nbsp;</td>';
5746
                        $nbphoto++;
5747
                    }
5748
5749
                    if ($nbphoto) $return .= '</table>';
5750
                }
5751
            }
5752
        }
5753
5754
        $this->nbphoto = $nbphoto;
5755
5756
        return $return;
5757
    }
5758
5759
    /**
5760
     * Function test if type is text
5761
     *
5762
     * @param array $info content informations of field
5763
     * @return                  bool
5764
     */
5765
    public function isText($info)
5766
    {
5767
        if (is_array($info)) {
5768
            if (isset($info['type']) && $info['type'] == 'text') return true;
5769
            else return false;
5770
        } else return false;
5771
    }
5772
5773
    /**
5774
     * Create object into database
5775
     *
5776
     * @param User $user User that creates
5777
     * @param bool $notrigger false=launch triggers after, true=disable triggers
5778
     * @return int             <0 if KO, Id of created object if OK
5779
     */
5780
    public function createCommon(User $user, $notrigger = false)
5781
    {
5782
        global $langs;
5783
5784
        $error = 0;
5785
5786
        $now = dol_now();
5787
5788
        $fieldvalues = $this->setSaveQuery();
5789
        if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) $fieldvalues['date_creation'] = $this->db->idate($now);
5790
        if (array_key_exists('fk_user_creat', $fieldvalues) && !($fieldvalues['fk_user_creat'] > 0)) $fieldvalues['fk_user_creat'] = $user->id;
5791
        unset($fieldvalues['rowid']);    // The field 'rowid' is reserved field name for autoincrement field so we don't need it into insert.
5792
5793
        $keys = array();
5794
        $values = array();
5795
        foreach ($fieldvalues as $k => $v) {
5796
            $keys[$k] = $k;
5797
            $value = $this->fields[$k];
5798
            $values[$k] = $this->quote($v, $value);
5799
        }
5800
5801
        // Clean and check mandatory
5802
        foreach ($keys as $key) {
5803
            // If field is an implicit foreign key field
5804
            if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key] = '';
5805
            if (!empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key] = '';
5806
5807
            //var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
5808
            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...
5809
                $error++;
5810
                $this->errors[] = $langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
5811
            }
5812
5813
            // If field is an implicit foreign key field
5814
            if (preg_match('/^integer:/i', $this->fields[$key]['type']) && empty($values[$key])) $values[$key] = 'null';
5815
            if (!empty($this->fields[$key]['foreignkey']) && empty($values[$key])) $values[$key] = 'null';
5816
        }
5817
5818
        if ($error) return -1;
5819
5820
        $this->db->begin();
5821
5822
        if (!$error) {
5823
            $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element;
5824
            $sql .= ' (' . implode(", ", $keys) . ')';
5825
            $sql .= ' VALUES (' . implode(", ", $values) . ')';
5826
5827
            $res = $this->db->query($sql);
5828
            if ($res === false) {
5829
                $error++;
5830
                $this->errors[] = $this->db->lasterror();
5831
            }
5832
        }
5833
5834
        if (!$error) {
5835
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
5836
        }
5837
5838
        // Create extrafields
5839
        if (!$error) {
5840
            $result = $this->insertExtraFields();
5841
            if ($result < 0) $error++;
5842
        }
5843
5844
        // Triggers
5845
        if (!$error && !$notrigger) {
5846
            // Call triggers
5847
            $result = $this->call_trigger(strtoupper(get_class($this)) . '_CREATE', $user);
5848
            if ($result < 0) {
5849
                $error++;
5850
            }
5851
            // End call triggers
5852
        }
5853
5854
        // Commit or rollback
5855
        if ($error) {
5856
            $this->db->rollback();
5857
            return -1;
5858
        } else {
5859
            $this->db->commit();
5860
            return $this->id;
5861
        }
5862
    }
5863
5864
    /**
5865
     * Function to prepare the values to insert.
5866
     * Note $this->${field} are set by the page that make the createCommon or the updateCommon.
5867
     *
5868
     * @return array
5869
     */
5870
    protected function setSaveQuery()
5871
    {
5872
        global $conf;
5873
5874
        $queryarray = array();
5875
        foreach ($this->fields as $field => $info)    // Loop on definition of fields
5876
        {
5877
            // Depending on field type ('datetime', ...)
5878
            if ($this->isDate($info)) {
5879
                if (empty($this->{$field})) {
5880
                    $queryarray[$field] = null;
5881
                } else {
5882
                    $queryarray[$field] = $this->db->idate($this->{$field});
5883
                }
5884
            } else if ($this->isArray($info)) {
5885
                if (!empty($this->{$field})) {
5886
                    if (!is_array($this->{$field})) {
5887
                        $this->{$field} = array($this->{$field});
5888
                    }
5889
                    $queryarray[$field] = serialize($this->{$field});
5890
                } else {
5891
                    $queryarray[$field] = null;
5892
                }
5893
            } else if ($this->isInt($info)) {
5894
                if ($field == 'entity' && is_null($this->{$field})) $queryarray[$field] = $conf->entity;
5895
                else {
5896
                    $queryarray[$field] = (int)price2num($this->{$field});
5897
                    if (empty($queryarray[$field])) $queryarray[$field] = 0;        // May be reset to null later if property 'notnull' is -1 for this field.
5898
                }
5899
            } else if ($this->isFloat($info)) {
5900
                $queryarray[$field] = (double)price2num($this->{$field});
5901
                if (empty($queryarray[$field])) $queryarray[$field] = 0;
5902
            } else {
5903
                $queryarray[$field] = $this->{$field};
5904
            }
5905
5906
            if ($info['type'] == 'timestamp' && empty($queryarray[$field])) unset($queryarray[$field]);
5907
            if (!empty($info['notnull']) && $info['notnull'] == -1 && empty($queryarray[$field])) $queryarray[$field] = null;
5908
        }
5909
5910
        return $queryarray;
5911
    }
5912
5913
    /**
5914
     *    Add/Update all extra fields values for the current object.
5915
     *  Data to describe values to insert/update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...)
5916
     *  This function delete record with all extrafields and insert them again from the array $this->array_options.
5917
     *
5918
     * @param string $trigger If defined, call also the trigger (for example COMPANY_MODIFY)
5919
     * @param User $userused Object user
5920
     * @return int                        -1=error, O=did nothing, 1=OK
5921
     * @see updateExtraField, setValueFrom
5922
     */
5923
    function insertExtraFields($trigger = '', $userused = null)
5924
    {
5925
        global $conf, $langs, $user;
5926
5927
        if (empty($userused)) $userused = $user;
5928
5929
        $error = 0;
5930
5931
        if (!empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0;    // For avoid conflicts if trigger used
5932
5933
        if (!empty($this->array_options)) {
5934
            // Check parameters
5935
            $langs->load('admin');
5936
            require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
5937
            $extrafields = new ExtraFields($this->db);
5938
            $target_extrafields = $extrafields->fetch_name_optionals_label($this->table_element);
5939
5940
            //Eliminate copied source object extra_fields that do not exist in target object
5941
            $new_array_options = array();
5942
            foreach ($this->array_options as $key => $value) {
5943
                if (in_array(substr($key, 8), array_keys($target_extrafields)))    // We remove the 'options_' from $key for test
5944
                    $new_array_options[$key] = $value;
5945
                elseif (in_array($key, array_keys($target_extrafields)))        // We test on $key that does not contains the 'options_' prefix
5946
                    $new_array_options['options_' . $key] = $value;
5947
            }
5948
5949
            foreach ($new_array_options as $key => $value) {
5950
                $attributeKey = substr($key, 8);   // Remove 'options_' prefix
5951
                $attributeType = $extrafields->attributes[$this->table_element]['type'][$attributeKey];
5952
                $attributeLabel = $extrafields->attributes[$this->table_element]['label'][$attributeKey];
5953
                $attributeParam = $extrafields->attributes[$this->table_element]['param'][$attributeKey];
5954
                $attributeRequired = $extrafields->attributes[$this->table_element]['required'][$attributeKey];
5955
5956
                if ($attributeRequired) {
5957
                    $mandatorypb = false;
5958
                    if ($attributeType == 'link' && $this->array_options[$key] == '-1') $mandatorypb = true;
5959
                    if ($this->array_options[$key] === '') $mandatorypb = true;
5960
                    if ($mandatorypb) {
5961
                        dol_syslog($this->error);
5962
                        $this->errors[] = $langs->trans('ErrorFieldRequired', $attributeLabel);
5963
                        return -1;
5964
                    }
5965
                }
5966
5967
                //dol_syslog("attributeLabel=".$attributeLabel, LOG_DEBUG);
5968
                //dol_syslog("attributeType=".$attributeType, LOG_DEBUG);
5969
5970
                switch ($attributeType) {
5971
                    case 'int':
5972
                        if (!is_numeric($value) && $value != '') {
5973
                            $this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
5974
                            return -1;
5975
                        } elseif ($value == '') {
5976
                            $new_array_options[$key] = null;
5977
                        }
5978
                        break;
5979
                    case 'double':
5980
                        $value = price2num($value);
5981
                        if (!is_numeric($value) && $value != '') {
5982
                            dol_syslog($langs->trans("ExtraFieldHasWrongValue") . " sur " . $attributeLabel . "(" . $value . "is not '" . $attributeType . "')", LOG_DEBUG);
5983
                            $this->errors[] = $langs->trans("ExtraFieldHasWrongValue", $attributeLabel);
5984
                            return -1;
5985
                        } elseif ($value == '') {
5986
                            $new_array_options[$key] = null;
5987
                        }
5988
                        //dol_syslog("double value"." sur ".$attributeLabel."(".$value." is '".$attributeType."')", LOG_DEBUG);
5989
                        $new_array_options[$key] = $value;
5990
                        break;
5991
                    /*case 'select':	// Not required, we chosed value='0' for undefined values
5992
             			if ($value=='-1')
5993
             			{
5994
             				$this->array_options[$key] = null;
5995
             			}
5996
             			break;*/
5997
                    case 'password':
5998
                        $algo = '';
5999
                        if ($this->array_options[$key] != '' && is_array($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options'])) {
6000
                            // If there is an encryption choice, we use it to crypt data before insert
6001
                            $tmparrays = array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']);
6002
                            $algo = reset($tmparrays);
6003
                            if ($algo != '') {
6004
                                //global $action;		// $action may be 'create', 'update', 'update_extras'...
6005
                                //var_dump($action);
6006
                                //var_dump($this->oldcopy);exit;
6007
                                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
6008
                                {
6009
                                    //var_dump($this->oldcopy->array_options[$key]); var_dump($this->array_options[$key]);
6010
                                    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.
6011
                                    {
6012
                                        $new_array_options[$key] = $this->array_options[$key];    // Value is kept
6013
                                    } else {
6014
                                        // var_dump($algo);
6015
                                        $newvalue = dol_hash($this->array_options[$key], $algo);
6016
                                        $new_array_options[$key] = $newvalue;
6017
                                    }
6018
                                } else {
6019
                                    $new_array_options[$key] = $this->array_options[$key];    // Value is kept
6020
                                }
6021
                            }
6022
                        } else    // Common usage
6023
                        {
6024
                            $new_array_options[$key] = $this->array_options[$key];
6025
                        }
6026
                        break;
6027
                    case 'price':
6028
                        $new_array_options[$key] = price2num($this->array_options[$key]);
6029
                        break;
6030
                    case 'date':
6031
                        $new_array_options[$key] = $this->db->idate($this->array_options[$key]);
6032
                        break;
6033
                    case 'datetime':
6034
                        // If data is a string instead of a timestamp, we convert it
6035
                        if (!is_int($this->array_options[$key])) {
6036
                            $this->array_options[$key] = strtotime($this->array_options[$key]);
6037
                        }
6038
                        $new_array_options[$key] = $this->db->idate($this->array_options[$key]);
6039
                        break;
6040
                    case 'link':
6041
                        $param_list = array_keys($attributeParam['options']);
6042
                        // 0 : ObjectName
6043
                        // 1 : classPath
6044
                        $InfoFieldList = explode(":", $param_list[0]);
6045
                        dol_include_once($InfoFieldList[1]);
6046
                        if ($InfoFieldList[0] && class_exists($InfoFieldList[0])) {
6047
                            if ($value == '-1')    // -1 is key for no defined in combo list of objects
6048
                            {
6049
                                $new_array_options[$key] = '';
6050
                            } elseif ($value) {
6051
                                $object = new $InfoFieldList[0]($this->db);
6052
                                if (is_numeric($value)) $res = $object->fetch($value);
6053
                                else $res = $object->fetch('', $value);
6054
6055
                                if ($res > 0) $new_array_options[$key] = $object->id;
6056
                                else {
6057
                                    $this->error = "Id/Ref '" . $value . "' for object '" . $object->element . "' not found";
6058
                                    $this->db->rollback();
6059
                                    return -1;
6060
                                }
6061
                            }
6062
                        } else {
6063
                            dol_syslog('Error bad setup of extrafield', LOG_WARNING);
6064
                        }
6065
                        break;
6066
                }
6067
            }
6068
6069
            $this->db->begin();
6070
6071
            $table_element = $this->table_element;
6072
            if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility
6073
6074
            $sql_del = "DELETE FROM " . MAIN_DB_PREFIX . $table_element . "_extrafields WHERE fk_object = " . $this->id;
6075
            dol_syslog(get_class($this) . "::insertExtraFields delete", LOG_DEBUG);
6076
            $this->db->query($sql_del);
6077
6078
            $sql = "INSERT INTO " . MAIN_DB_PREFIX . $table_element . "_extrafields (fk_object";
6079
            foreach ($new_array_options as $key => $value) {
6080
                $attributeKey = substr($key, 8);   // Remove 'options_' prefix
6081
                // Add field of attribut
6082
                if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator
6083
                    $sql .= "," . $attributeKey;
6084
            }
6085
            $sql .= ") VALUES (" . $this->id;
6086
6087
            foreach ($new_array_options as $key => $value) {
6088
                $attributeKey = substr($key, 8);   // Remove 'options_' prefix
6089
                // Add field of attribute
6090
                if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') // Only for other type than separator)
6091
                {
6092
                    if ($new_array_options[$key] != '') {
6093
                        $sql .= ",'" . $this->db->escape($new_array_options[$key]) . "'";
6094
                    } else {
6095
                        $sql .= ",null";
6096
                    }
6097
                }
6098
            }
6099
            $sql .= ")";
6100
6101
            dol_syslog(get_class($this) . "::insertExtraFields insert", LOG_DEBUG);
6102
            $resql = $this->db->query($sql);
6103
            if (!$resql) {
6104
                $this->error = $this->db->lasterror();
6105
                $error++;
6106
            }
6107
6108
            if (!$error && $trigger) {
6109
                // Call trigger
6110
                $this->context = array('extrafieldaddupdate' => 1);
6111
                $result = $this->call_trigger($trigger, $userused);
6112
                if ($result < 0) $error++;
6113
                // End call trigger
6114
            }
6115
6116
            if ($error) {
6117
                $this->db->rollback();
6118
                return -1;
6119
            } else {
6120
                $this->db->commit();
6121
                return 1;
6122
            }
6123
        } else return 0;
6124
    }
6125
6126
    /**
6127
     * Update object into database
6128
     *
6129
     * @param User $user User that modifies
6130
     * @param bool $notrigger false=launch triggers after, true=disable triggers
6131
     * @return int                <0 if KO, >0 if OK
6132
     */
6133
    public function updateCommon(User $user, $notrigger = false)
6134
    {
6135
        global $conf, $langs;
6136
6137
        $error = 0;
6138
6139
        $now = dol_now();
6140
6141
        $fieldvalues = $this->setSaveQuery();
6142
        if (array_key_exists('date_modification', $fieldvalues) && empty($fieldvalues['date_modification'])) $fieldvalues['date_modification'] = $this->db->idate($now);
6143
        if (array_key_exists('fk_user_modif', $fieldvalues) && !($fieldvalues['fk_user_modif'] > 0)) $fieldvalues['fk_user_modif'] = $user->id;
6144
        unset($fieldvalues['rowid']);    // The field 'rowid' is reserved field name for autoincrement field so we don't need it into update.
6145
6146
        $keys = array();
6147
        $values = array();
6148
        foreach ($fieldvalues as $k => $v) {
6149
            $keys[$k] = $k;
6150
            $value = $this->fields[$k];
6151
            $values[$k] = $this->quote($v, $value);
6152
            $tmp[] = $k . '=' . $this->quote($v, $this->fields[$k]);
6153
        }
6154
6155
        // Clean and check mandatory
6156
        foreach ($keys as $key) {
6157
            if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key] = '';        // This is an implicit foreign key field
6158
            if (!empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key] = '';                    // This is an explicit foreign key field
6159
6160
            //var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1));
6161
            /*
6162
			if ($this->fields[$key]['notnull'] == 1 && empty($values[$key]))
6163
			{
6164
				$error++;
6165
				$this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']);
6166
			}*/
6167
        }
6168
6169
        $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 6148. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
6170
6171
        $this->db->begin();
6172
        if (!$error) {
6173
            $res = $this->db->query($sql);
6174
            if ($res === false) {
6175
                $error++;
6176
                $this->errors[] = $this->db->lasterror();
6177
            }
6178
        }
6179
6180
        // Update extrafield
6181
        if (!$error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options) > 0) {
6182
            $result = $this->insertExtraFields();
6183
            if ($result < 0) {
6184
                $error++;
6185
            }
6186
        }
6187
6188
        // Triggers
6189
        if (!$error && !$notrigger) {
6190
            // Call triggers
6191
            $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $user);
6192
            if ($result < 0) {
6193
                $error++;
6194
            } //Do also here what you must do to rollback action if trigger fail
6195
            // End call triggers
6196
        }
6197
6198
        // Commit or rollback
6199
        if ($error) {
6200
            $this->db->rollback();
6201
            return -1;
6202
        } else {
6203
            $this->db->commit();
6204
            return $this->id;
6205
        }
6206
    }
6207
6208
    /**
6209
     * Delete object in database
6210
     *
6211
     * @param User $user User that deletes
6212
     * @param bool $notrigger false=launch triggers after, true=disable triggers
6213
     * @param int $forcechilddeletion 0=no, 1=Force deletion of children
6214
     * @return    int                            <=0 if KO, >0 if OK
6215
     */
6216
    public function deleteCommon(User $user, $notrigger = false, $forcechilddeletion = 0)
6217
    {
6218
        $error = 0;
6219
6220
        $this->db->begin();
6221
6222
        if ($forcechilddeletion) {
6223
            foreach ($this->childtables as $table) {
6224
                $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $table . ' WHERE ' . $this->fk_element . ' = ' . $this->id;
6225
                $resql = $this->db->query($sql);
6226
                if (!$resql) {
6227
                    $this->error = $this->db->lasterror();
6228
                    $this->errors[] = $this->error;
6229
                    $this->db->rollback();
6230
                    return -1;
6231
                }
6232
            }
6233
        } elseif (!empty($this->fk_element) && !empty($this->childtables))    // If object has childs linked with a foreign key field, we check all child tables.
6234
        {
6235
            $objectisused = $this->isObjectUsed($this->id);
6236
            if (!empty($objectisused)) {
6237
                dol_syslog(get_class($this) . "::deleteCommon Can't delete record as it has some child", LOG_WARNING);
6238
                $this->error = 'ErrorRecordHasChildren';
6239
                $this->errors[] = $this->error;
6240
                $this->db->rollback();
6241
                return 0;
6242
            }
6243
        }
6244
6245
        if (!$error) {
6246
            if (!$notrigger) {
6247
                // Call triggers
6248
                $result = $this->call_trigger(strtoupper(get_class($this)) . '_DELETE', $user);
6249
                if ($result < 0) {
6250
                    $error++;
6251
                } // Do also here what you must do to rollback action if trigger fail
6252
                // End call triggers
6253
            }
6254
        }
6255
6256
        if (!$error && !empty($this->isextrafieldmanaged)) {
6257
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element . "_extrafields";
6258
            $sql .= " WHERE fk_object=" . $this->id;
6259
6260
            $resql = $this->db->query($sql);
6261
            if (!$resql) {
6262
                $this->errors[] = $this->db->lasterror();
6263
                $error++;
6264
            }
6265
        }
6266
6267
        if (!$error) {
6268
            $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . ' WHERE rowid=' . $this->id;
6269
6270
            $res = $this->db->query($sql);
6271
            if ($res === false) {
6272
                $error++;
6273
                $this->errors[] = $this->db->lasterror();
6274
            }
6275
        }
6276
6277
        // Commit or rollback
6278
        if ($error) {
6279
            $this->db->rollback();
6280
            return -1;
6281
        } else {
6282
            $this->db->commit();
6283
            return 1;
6284
        }
6285
    }
6286
6287
    /**
6288
     *  Function to check if an object is used by others.
6289
     *  Check is done into this->childtables. There is no check into llx_element_element.
6290
     *
6291
     * @param int $id Force id of object
6292
     * @return    int                    <0 if KO, 0 if not used, >0 if already used
6293
     */
6294
    function isObjectUsed($id = 0)
6295
    {
6296
        global $langs;
6297
6298
        if (empty($id)) $id = $this->id;
6299
6300
        // Check parameters
6301
        if (!isset($this->childtables) || !is_array($this->childtables) || count($this->childtables) == 0) {
6302
            dol_print_error('Called isObjectUsed on a class with property this->childtables not defined');
6303
            return -1;
6304
        }
6305
6306
        $arraytoscan = $this->childtables;
6307
        // For backward compatibility, we check if array is old format array('table1', 'table2', ...)
6308
        $tmparray = array_keys($this->childtables);
6309
        if (is_numeric($tmparray[0])) {
6310
            $arraytoscan = array_flip($this->childtables);
6311
        }
6312
6313
        // Test if child exists
6314
        $haschild = 0;
6315
        foreach ($arraytoscan as $table => $elementname) {
6316
            //print $id.'-'.$table.'-'.$elementname.'<br>';
6317
            // Check if third party can be deleted
6318
            $sql = "SELECT COUNT(*) as nb from " . MAIN_DB_PREFIX . $table;
6319
            $sql .= " WHERE " . $this->fk_element . " = " . $id;
6320
            $resql = $this->db->query($sql);
6321
            if ($resql) {
6322
                $obj = $this->db->fetch_object($resql);
6323
                if ($obj->nb > 0) {
6324
                    $langs->load("errors");
6325
                    //print 'Found into table '.$table.', type '.$langs->transnoentitiesnoconv($elementname).', haschild='.$haschild;
6326
                    $haschild += $obj->nb;
6327
                    if (is_numeric($elementname))    // old usage
6328
                    {
6329
                        $this->errors[] = $langs->trans("ErrorRecordHasAtLeastOneChildOfType", $table);
6330
                    } else    // new usage: $elementname=Translation key
6331
                    {
6332
                        $this->errors[] = $langs->trans("ErrorRecordHasAtLeastOneChildOfType", $langs->transnoentitiesnoconv($elementname));
6333
                    }
6334
                    break;    // We found at least one, we stop here
6335
                }
6336
            } else {
6337
                $this->errors[] = $this->db->lasterror();
6338
                return -1;
6339
            }
6340
        }
6341
        if ($haschild > 0) {
6342
            $this->errors[] = "ErrorRecordHasChildren";
6343
            return $haschild;
6344
        } else return 0;
6345
    }
6346
6347
    /**
6348
     * Initialise object with example values
6349
     * Id must be 0 if object instance is a specimen
6350
     *
6351
     * @return void
6352
     */
6353
    public function initAsSpecimenCommon()
6354
    {
6355
        $this->id = 0;
6356
6357
        // TODO...
6358
    }
6359
6360
    /**
6361
     * Load comments linked with current task
6362
     * @return boolean    1 if ok
6363
     */
6364
    public function fetchComments()
6365
    {
6366
        require_once DOL_DOCUMENT_ROOT . '/core/class/comment.class.php';
6367
6368
        $comment = new Comment($this->db);
0 ignored issues
show
Bug introduced by
The type Alixar\Base\Comment was not found. Did you mean Comment? If so, make sure to prefix the type with \.
Loading history...
6369
        $result = $comment->fetchAllFor($this->element, $this->id);
6370
        if ($result < 0) {
6371
            $this->errors = array_merge($this->errors, $comment->errors);
6372
            return -1;
6373
        } else {
6374
            $this->comments = $comment->comments;
6375
        }
6376
        return count($this->comments);
6377
    }
6378
6379
    /**
6380
     * Return nb comments already posted
6381
     *
6382
     * @return int
6383
     */
6384
    public function getNbComments()
6385
    {
6386
        return count($this->comments);
6387
    }
6388
6389
6390
    /* Part for comments */
6391
6392
    /**
6393
     * Trim object parameters
6394
     * @param string[] $parameters array of parameters to trim
6395
     *
6396
     * @return void
6397
     */
6398
    public function trimParameters($parameters)
6399
    {
6400
        if (!is_array($parameters)) return;
6401
        foreach ($parameters as $parameter) {
6402
            if (isset($this->$parameter)) {
6403
                $this->$parameter = trim($this->$parameter);
6404
            }
6405
        }
6406
    }
6407
6408
    /**
6409
     * Common function for all objects extending CommonObject for generating documents
6410
     *
6411
     * @param string $modelspath Relative folder where generators are placed
6412
     * @param string $modele Generator to use. Caller must set it to obj->modelpdf or GETPOST('modelpdf') for example.
6413
     * @param Translate $outputlangs Output language to use
6414
     * @param int $hidedetails 1 to hide details. 0 by default
6415
     * @param int $hidedesc 1 to hide product description. 0 by default
6416
     * @param int $hideref 1 to hide product reference. 0 by default
6417
     * @param null|array $moreparams Array to provide more information
6418
     * @return    int                        >0 if OK, <0 if KO
6419
     * @see    addFileIntoDatabaseIndex
6420
     */
6421
    protected function commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams = null)
6422
    {
6423
        global $conf, $langs, $user;
6424
6425
        $srctemplatepath = '';
6426
6427
        // Increase limit for PDF build
6428
        $err = error_reporting();
6429
        error_reporting(0);
6430
        @set_time_limit(120);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for set_time_limit(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

6430
        /** @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...
6431
        error_reporting($err);
6432
6433
        // If selected model is a filename template (then $modele="modelname" or "modelname:filename")
6434
        $tmp = explode(':', $modele, 2);
6435
        if (!empty($tmp[1])) {
6436
            $modele = $tmp[0];
6437
            $srctemplatepath = $tmp[1];
6438
        }
6439
6440
        // Search template files
6441
        $file = '';
6442
        $classname = '';
6443
        $filefound = 0;
6444
        $dirmodels = array('/');
6445
        if (is_array($conf->modules_parts['models'])) $dirmodels = array_merge($dirmodels, $conf->modules_parts['models']);
6446
        foreach ($dirmodels as $reldir) {
6447
            foreach (array('doc', 'pdf') as $prefix) {
6448
                if (in_array(get_class($this), array('Adherent'))) $file = $prefix . "_" . $modele . ".class.php";     // Member module use prefix_module.class.php
6449
                else $file = $prefix . "_" . $modele . ".modules.php";
6450
6451
                // On verifie l'emplacement du modele
6452
                $file = dol_buildpath($reldir . $modelspath . $file, 0);
6453
                if (file_exists($file)) {
6454
                    $filefound = 1;
6455
                    $classname = $prefix . '_' . $modele;
6456
                    break;
6457
                }
6458
            }
6459
            if ($filefound) break;
6460
        }
6461
6462
        // If generator was found
6463
        if ($filefound) {
6464
            global $db;  // Required to solve a conception default in commonstickergenerator.class.php making an include of code using $db
6465
6466
            require_once $file;
6467
6468
            $obj = new $classname($this->db);
6469
6470
            // If generator is ODT, we must have srctemplatepath defined, if not we set it.
6471
            if ($obj->type == 'odt' && empty($srctemplatepath)) {
6472
                $varfortemplatedir = $obj->scandir;
6473
                if ($varfortemplatedir && !empty($conf->global->$varfortemplatedir)) {
6474
                    $dirtoscan = $conf->global->$varfortemplatedir;
6475
6476
                    $listoffiles = array();
6477
6478
                    // Now we add first model found in directories scanned
6479
                    $listofdir = explode(',', $dirtoscan);
6480
                    foreach ($listofdir as $key => $tmpdir) {
6481
                        $tmpdir = trim($tmpdir);
6482
                        $tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
6483
                        if (!$tmpdir) {
6484
                            unset($listofdir[$key]);
6485
                            continue;
6486
                        }
6487
                        if (is_dir($tmpdir)) {
6488
                            $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '\.od(s|t)$', '', 'name', SORT_ASC, 0);
6489
                            if (count($tmpfiles)) $listoffiles = array_merge($listoffiles, $tmpfiles);
6490
                        }
6491
                    }
6492
6493
                    if (count($listoffiles)) {
6494
                        foreach ($listoffiles as $record) {
6495
                            $srctemplatepath = $record['fullname'];
6496
                            break;
6497
                        }
6498
                    }
6499
                }
6500
6501
                if (empty($srctemplatepath)) {
6502
                    $this->error = 'ErrorGenerationAskedForOdtTemplateWithSrcFileNotDefined';
6503
                    return -1;
6504
                }
6505
            }
6506
6507
            if ($obj->type == 'odt' && !empty($srctemplatepath)) {
6508
                if (!dol_is_file($srctemplatepath)) {
6509
                    $this->error = 'ErrorGenerationAskedForOdtTemplateWithSrcFileNotFound';
6510
                    return -1;
6511
                }
6512
            }
6513
6514
            // We save charset_output to restore it because write_file can change it if needed for
6515
            // output format that does not support UTF8.
6516
            $sav_charset_output = $outputlangs->charset_output;
6517
6518
            if (in_array(get_class($this), array('Adherent'))) {
6519
                $arrayofrecords = array();   // The write_file of templates of adherent class need this var
6520
                $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, $moreparams);
6521
            } else {
6522
                $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams);
6523
            }
6524
            // After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index.
6525
6526
            if ($resultwritefile > 0) {
6527
                $outputlangs->charset_output = $sav_charset_output;
6528
6529
                // We delete old preview
6530
                require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
6531
                dol_delete_preview($this);
6532
6533
                // Index file in database
6534
                if (!empty($obj->result['fullpath'])) {
6535
                    $destfull = $obj->result['fullpath'];
6536
                    $upload_dir = dirname($destfull);
6537
                    $destfile = basename($destfull);
6538
                    $rel_dir = preg_replace('/^' . preg_quote(DOL_DATA_ROOT, '/') . '/', '', $upload_dir);
6539
6540
                    if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir))     // If not a tmp dir
6541
                    {
6542
                        $filename = basename($destfile);
6543
                        $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
6544
                        $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
6545
6546
                        include_once DOL_DOCUMENT_ROOT . '/ecm/class/ecmfiles.class.php';
6547
                        $ecmfile = new EcmFiles($this->db);
6548
                        $result = $ecmfile->fetch(0, '', ($rel_dir ? $rel_dir . '/' : '') . $filename);
6549
6550
                        // Set the public "share" key
6551
                        $setsharekey = false;
6552
                        if ($this->element == 'propal') {
6553
                            $useonlinesignature = $conf->global->MAIN_FEATURES_LEVEL;    // Replace this with 1 when feature to make online signature is ok
6554
                            if ($useonlinesignature) $setsharekey = true;
6555
                            if (!empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey = true;
6556
                        }
6557
                        if ($this->element == 'commande' && !empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey = true;
6558
                        if ($this->element == 'facture' && !empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey = true;
6559
                        if ($this->element == 'bank_account' && !empty($conf->global->BANK_ACCOUNT_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey = true;
6560
6561
                        if ($setsharekey) {
6562
                            if (empty($ecmfile->share))    // Because object not found or share not set yet
6563
                            {
6564
                                require_once DOL_DOCUMENT_ROOT . '/core/lib/security2.lib.php';
6565
                                $ecmfile->share = getRandomPassword(true);
6566
                            }
6567
                        }
6568
6569
                        if ($result > 0) {
6570
                            $ecmfile->label = md5_file(dol_osencode($destfull));    // hash of file content
6571
                            $ecmfile->fullpath_orig = '';
6572
                            $ecmfile->gen_or_uploaded = 'generated';
6573
                            $ecmfile->description = '';    // indexed content
6574
                            $ecmfile->keyword = '';        // keyword content
6575
                            $result = $ecmfile->update($user);
6576
                            if ($result < 0) {
6577
                                setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
6578
                            }
6579
                        } else {
6580
                            $ecmfile->entity = $conf->entity;
6581
                            $ecmfile->filepath = $rel_dir;
6582
                            $ecmfile->filename = $filename;
6583
                            $ecmfile->label = md5_file(dol_osencode($destfull));    // hash of file content
6584
                            $ecmfile->fullpath_orig = '';
6585
                            $ecmfile->gen_or_uploaded = 'generated';
6586
                            $ecmfile->description = '';    // indexed content
6587
                            $ecmfile->keyword = '';        // keyword content
6588
                            $ecmfile->src_object_type = $this->table_element;
6589
                            $ecmfile->src_object_id = $this->id;
6590
6591
                            $result = $ecmfile->create($user);
6592
                            if ($result < 0) {
6593
                                setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
6594
                            }
6595
                        }
6596
6597
                        /*$this->result['fullname']=$destfull;
6598
						$this->result['filepath']=$ecmfile->filepath;
6599
						$this->result['filename']=$ecmfile->filename;*/
6600
                        //var_dump($obj->update_main_doc_field);exit;
6601
6602
                        // Update the last_main_doc field into main object (if documenent generator has property ->update_main_doc_field set)
6603
                        $update_main_doc_field = 0;
6604
                        if (!empty($obj->update_main_doc_field)) $update_main_doc_field = 1;
6605
                        if ($update_main_doc_field && !empty($this->table_element)) {
6606
                            $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . " SET last_main_doc = '" . ($ecmfile->filepath . '/' . $ecmfile->filename) . "'";
6607
                            $sql .= ' WHERE rowid = ' . $this->id;
6608
                            $resql = $this->db->query($sql);
6609
                            if (!$resql) dol_print_error($this->db);
6610
                        }
6611
                    }
6612
                } else {
6613
                    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);
6614
                }
6615
6616
                // Success in building document. We build meta file.
6617
                dol_meta_create($this);
6618
6619
                return 1;
6620
            } else {
6621
                $outputlangs->charset_output = $sav_charset_output;
6622
                dol_print_error($this->db, "Error generating document for " . __CLASS__ . ". Error: " . $obj->error, $obj->errors);
6623
                return -1;
6624
            }
6625
        } else {
6626
            $this->error = $langs->trans("Error") . " " . $langs->trans("ErrorFileDoesNotExists", $file);
6627
            dol_print_error('', $this->error);
6628
            return -1;
6629
        }
6630
    }
6631
6632
    /**
6633
     * Function test if is indexed
6634
     *
6635
     * @param array $info content informations of field
6636
     * @return                  bool
6637
     */
6638
    protected function isIndex($info)
6639
    {
6640
        if (is_array($info)) {
6641
            if (isset($info['index']) && $info['index'] == true) return true;
6642
            else return false;
6643
        } else return false;
6644
    }
6645
}