CommonDocGenerator::printColDescContent()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 13
nc 2
nop 9
dl 0
loc 25
rs 9.8333
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* Copyright (C) 2003-2005  Rodolphe Quiedeville        <[email protected]>
4
 * Copyright (C) 2004-2010	Laurent Destailleur         <[email protected]>
5
 * Copyright (C) 2004		Eric Seigne                 <[email protected]>
6
 * Copyright (C) 2005-2012	Regis Houssin               <[email protected]>
7
 * Copyright (C) 2015       Marcos García               <[email protected]>
8
 * Copyright (C) 2016-2023  Charlene Benke              <[email protected]>
9
 * Copyright (C) 2018-2024  Frédéric France             <[email protected]>
10
 * Copyright (C) 2020       Josep Lluís Amador          <[email protected]>
11
 * Copyright (C) 2024		MDW	                        <[email protected]>
12
 * Copyright (C) 2024       Mélina Joum			        <[email protected]>
13
 * Copyright (C) 2024       Rafael San José             <[email protected]>
14
 *
15
 * This program is free software; you can redistribute it and/or modify
16
 * it under the terms of the GNU General Public License as published by
17
 * the Free Software Foundation; either version 3 of the License, or
18
 * (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU General Public License
26
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
27
 * or see https://www.gnu.org/
28
 */
29
30
namespace Dolibarr\Code\Core\Classes;
31
32
use Dolibarr\Code\Adherents\Classes\Adherent;
33
use Dolibarr\Code\Compta\Classes\Account;
34
use Dolibarr\Code\Compta\Classes\Facture;
35
use Dolibarr\Code\Contact\Classes\Contact;
36
use Dolibarr\Code\Expedition\Classes\Expedition;
37
use Dolibarr\Code\Fourn\Classes\CommandeFournisseur;
38
use Dolibarr\Code\Product\Classes\Product;
39
use Dolibarr\Code\Societe\Classes\Societe;
40
use Dolibarr\Code\User\Classes\User;
41
use Dolibarr\Core\Base\CommonObject;
42
use Dolibarr\Core\Base\CommonObjectLine;
43
use DoliDB;
44
use stdClass;
45
46
/**
47
 *      \file       htdocs/core/class/commondocgenerator.class.php
48
 *      \ingroup    core
49
 *      \brief      File of parent class for documents generators
50
 */
51
52
53
/**
54
 *  Parent class for documents (PDF, ODT, ...) generators
55
 */
56
abstract class CommonDocGenerator
57
{
58
    /**
59
     * @var string Model name
60
     */
61
    public $name = '';
62
63
    /**
64
     * @var string Version
65
     */
66
    public $version = '';
67
68
    /**
69
     * @var string Error code (or message)
70
     */
71
    public $error = '';
72
73
    /**
74
     * @var string[]    Array of error strings
75
     */
76
    public $errors = array();
77
78
    /**
79
     * @var DoliDB Database handler.
80
     */
81
    protected $db;
82
83
    /**
84
     * @var ?Extrafields object
85
     */
86
    public $extrafieldsCache;
87
88
    /**
89
     * @var int If set to 1, save the fullname of generated file with path as the main doc when generating a doc with this template.
90
     */
91
    public $update_main_doc_field;
92
93
    /**
94
     * @var string  The name of constant to use to scan ODT files (Example: 'COMMANDE_ADDON_PDF_ODT_PATH')
95
     */
96
    public $scandir;
97
98
    /**
99
     * @var string model description (short text)
100
     */
101
    public $description;
102
103
    /**
104
     * @var array
105
     */
106
    public $format;
107
108
    /**
109
     * @var string pdf, odt, etc
110
     */
111
    public $type;
112
113
    public $page_hauteur;
114
    public $page_largeur;
115
    public $marge_gauche;
116
    public $marge_droite;
117
    public $marge_haute;
118
    public $marge_basse;
119
120
    public $option_logo;
121
    public $option_tva;
122
    public $option_multilang;
123
    public $option_freetext;
124
    public $option_draft_watermark;
125
    public $watermark;
126
127
    public $option_modereg;
128
    public $option_condreg;
129
    public $option_escompte;
130
    public $option_credit_note;
131
132
    public $tva;
133
    public $tva_array;
134
    /**
135
     * Local tax rates Array[tax_type][tax_rate]
136
     *
137
     * @var array<int,array<string,float>>
138
     */
139
    public $localtax1;
140
141
    /**
142
     * Local tax rates Array[tax_type][tax_rate]
143
     *
144
     * @var array<int,array<string,float>>
145
     */
146
    public $localtax2;
147
148
    /**
149
     * @var int Tab Title Height
150
     */
151
    public $tabTitleHeight;
152
153
    /**
154
     * @var array default title fields style
155
     */
156
    public $defaultTitlesFieldsStyle;
157
158
    /**
159
     * @var array default content fields style
160
     */
161
    public $defaultContentsFieldsStyle;
162
163
    /**
164
     * @var Societe     Issuer of document
165
     */
166
    public $emetteur;
167
168
    /**
169
     * @var array{0:int,1:int} Minimum version of PHP required by module.
170
     * e.g.: PHP ≥ 7.1 = array(7, 1)
171
     */
172
    public $phpmin = array(7, 1);
173
174
    /**
175
     * @var array<string,array{rank:int,width:float|int,title:array{textkey:string,label:string,align:string,padding:array{0:float,1:float,2:float,3:float}},content:array{align:string,padding:array{0:float,1:float,2:float,3:float}}}>   Array of columns
176
     */
177
    public $cols;
178
179
    /**
180
     * @var array{fullpath:string}  Array with result of doc generation. content is array('fullpath'=>$file)
181
     */
182
    public $result;
183
184
    public $posxlabel;
185
    public $posxup;
186
    public $posxref;
187
    public $posxpicture;    // For picture
188
    public $posxdesc;       // For description
189
    public $posxqty;
190
    public $posxpuht;
191
    public $posxtva;
192
    public $posxtotalht;
193
    public $postotalht;
194
    public $posxunit;
195
    public $posxdiscount;
196
    public $posxworkload;
197
    public $posxtimespent;
198
    public $posxprogress;
199
    public $atleastonephoto;
200
    public $atleastoneratenotnull;
201
    public $atleastonediscount;
202
203
    /**
204
     *  Constructor
205
     *
206
     *  @param      DoliDB      $db      Database handler
207
     */
208
    public function __construct($db)
209
    {
210
        $this->db = $db;
211
    }
212
213
214
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
215
    /**
216
     * Define array with couple substitution key => substitution value
217
     *
218
     * @param   User        $user           User
219
     * @param   Translate   $outputlangs    Language object for output
220
     * @return  array                       Array of substitution key->code
221
     */
222
    public function get_substitutionarray_user($user, $outputlangs)
223
    {
224
		// phpcs:enable
225
        global $conf, $extrafields;
226
227
        $logotouse = $conf->user->dir_output . '/' . get_exdir(0, 0, 0, 0, $user, 'user') . 'photos/' . getImageFileNameForSize($user->photo, '_small');
228
229
        $array_user = array(
230
            'myuser_lastname' => $user->lastname,
231
            'myuser_firstname' => $user->firstname,
232
            'myuser_fullname' => $user->getFullName($outputlangs, 1),
233
            'myuser_login' => $user->login,
234
            'myuser_phone' => $user->office_phone,
235
            'myuser_address' => $user->address,
236
            'myuser_zip' => $user->zip,
237
            'myuser_town' => $user->town,
238
            'myuser_country' => $user->country,
239
            'myuser_country_code' => $user->country_code,
240
            'myuser_state' => $user->state,
241
            'myuser_state_code' => $user->state_code,
242
            'myuser_fax' => $user->office_fax,
243
            'myuser_mobile' => $user->user_mobile,
244
            'myuser_email' => $user->email,
245
            'myuser_logo' => $logotouse,
246
            'myuser_job' => $user->job,
247
            'myuser_web' => '', // url not exist in $user object
248
            'myuser_birth' => dol_print_date($user->birth, 'day', 'gmt'),
249
            'myuser_dateemployment' => dol_print_date($user->dateemployment, 'day', 'tzuser'),
250
            'myuser_dateemploymentend' => dol_print_date($user->dateemploymentend, 'day', 'tzuser'),
251
            'myuser_gender' => $user->gender,
252
        );
253
        // Retrieve extrafields
254
        if (is_array($user->array_options) && count($user->array_options)) {
255
            if (empty($extrafields->attributes[$user->table_element])) {
256
                $extrafields->fetch_name_optionals_label($user->table_element);
257
            }
258
            $array_user = $this->fill_substitutionarray_with_extrafields($user, $array_user, $extrafields, 'myuser', $outputlangs);
259
        }
260
        return $array_user;
261
    }
262
263
264
    /**
265
     * Define array with couple substitution key => substitution value
266
     *
267
     * @param   Adherent    $member         Member
268
     * @param   Translate   $outputlangs    Language object for output
269
     * @return  array                       Array of substitution key->code
270
     */
271
    public function getSubstitutionarrayMember($member, $outputlangs)
272
    {
273
        global $conf, $extrafields;
274
275
        if ($member->photo) {
276
            $logotouse = $conf->member->dir_output . '/' . get_exdir(0, 0, 0, 1, $member, 'user') . '/photos/' . $member->photo;
277
        } else {
278
            $logotouse = DOL_DOCUMENT_ROOT . '/public/theme/common/nophoto.png';
279
        }
280
281
        $array_member = array(
282
            'mymember_lastname' => $member->lastname,
283
            'mymember_firstname' => $member->firstname,
284
            'mymember_fullname' => $member->getFullName($outputlangs, 1),
285
            'mymember_login' => $member->login,
286
            'mymember_address' => $member->address,
287
            'mymember_zip' => $member->zip,
288
            'mymember_town' => $member->town,
289
            'mymember_country_code' => $member->country_code,
290
            'mymember_country' => $member->country,
291
            'mymember_state_code' => $member->state_code,
292
            'mymember_state' => $member->state,
293
            'mymember_phone_perso' => $member->phone_perso,
294
            'mymember_phone_pro' => $member->phone,
295
            'mymember_phone_mobile' => $member->phone_mobile,
296
            'mymember_email' => $member->email,
297
            'mymember_logo' => $logotouse,
298
            'mymember_gender' => $member->gender,
299
            'mymember_birth_locale' => dol_print_date($member->birth, 'day', 'tzuser', $outputlangs),
300
            'mymember_birth' => dol_print_date($member->birth, 'day', 'tzuser'),
301
        );
302
        // Retrieve extrafields
303
        if (is_array($member->array_options) && count($member->array_options)) {
304
            $array_member = $this->fill_substitutionarray_with_extrafields($member, $array_member, $extrafields, 'mymember', $outputlangs);
305
        }
306
        return $array_member;
307
    }
308
309
310
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
311
    /**
312
     * Define array with couple substitution key => substitution value
313
     *
314
     * @param   Societe     $mysoc          Object thirdparty
315
     * @param   Translate   $outputlangs    Language object for output
316
     * @return  array                       Array of substitution key->code
317
     */
318
    public function get_substitutionarray_mysoc($mysoc, $outputlangs)
319
    {
320
		// phpcs:enable
321
        global $conf;
322
323
        if (empty($mysoc->forme_juridique) && !empty($mysoc->forme_juridique_code)) {
324
            $mysoc->forme_juridique = getFormeJuridiqueLabel($mysoc->forme_juridique_code);
325
        }
326
        if (empty($mysoc->country) && !empty($mysoc->country_code)) {
327
            $mysoc->country = $outputlangs->transnoentitiesnoconv("Country" . $mysoc->country_code);
328
        }
329
        if (empty($mysoc->state) && !empty($mysoc->state_code)) {
330
            $mysoc->state = getState($mysoc->state_code, 0);
331
        }
332
333
        $logotouse = $conf->mycompany->dir_output . '/logos/thumbs/' . $mysoc->logo_small;
334
335
        return array(
336
            'mycompany_logo' => $logotouse,
337
            'mycompany_name' => $mysoc->name,
338
            'mycompany_email' => $mysoc->email,
339
            'mycompany_phone' => $mysoc->phone,
340
            'mycompany_fax' => $mysoc->fax,
341
            'mycompany_address' => $mysoc->address,
342
            'mycompany_zip' => $mysoc->zip,
343
            'mycompany_town' => $mysoc->town,
344
            'mycompany_country' => $mysoc->country,
345
            'mycompany_country_code' => $mysoc->country_code,
346
            'mycompany_state' => $mysoc->state,
347
            'mycompany_state_code' => $mysoc->state_code,
348
            'mycompany_web' => $mysoc->url,
349
            'mycompany_juridicalstatus' => $mysoc->forme_juridique,
350
            'mycompany_managers' => $mysoc->managers,
351
            'mycompany_capital' => $mysoc->capital,
352
            'mycompany_barcode' => $mysoc->barcode,
353
            'mycompany_idprof1' => $mysoc->idprof1,
354
            'mycompany_idprof2' => $mysoc->idprof2,
355
            'mycompany_idprof3' => $mysoc->idprof3,
356
            'mycompany_idprof4' => $mysoc->idprof4,
357
            'mycompany_idprof5' => $mysoc->idprof5,
358
            'mycompany_idprof6' => $mysoc->idprof6,
359
            'mycompany_vatnumber' => $mysoc->tva_intra,
360
            'mycompany_socialobject' => $mysoc->socialobject,
361
            'mycompany_note_private' => $mysoc->note_private,
362
            //'mycompany_note_public'=>$mysoc->note_public,        // Only private not exists for "mysoc" but both for thirdparties
363
        );
364
    }
365
366
367
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
368
    /**
369
     * Define array with couple substitution key => substitution value
370
     * For example {company_name}, {company_name_alias}
371
     *
372
     * @param   Societe     $object         Object
373
     * @param   Translate   $outputlangs    Language object for output
374
     * @param   string      $array_key      Name of the key for return array
375
     * @return  array                       Array of substitution key->code
376
     */
377
    public function get_substitutionarray_thirdparty($object, $outputlangs, $array_key = 'company')
378
    {
379
		// phpcs:enable
380
        global $extrafields;
381
382
        if (empty($object->country) && !empty($object->country_code)) {
383
            $object->country = $outputlangs->transnoentitiesnoconv("Country" . $object->country_code);
384
        }
385
        if (empty($object->state) && !empty($object->state_code)) {
386
            $object->state = getState($object->state_code, 0);
387
        }
388
389
        $array_thirdparty = array(
390
            'company_name' => $object->name,
391
            'company_name_alias' => $object->name_alias,
392
            'company_email' => $object->email,
393
            'company_phone' => $object->phone,
394
            'company_fax' => $object->fax,
395
            'company_address' => $object->address,
396
            'company_zip' => $object->zip,
397
            'company_town' => $object->town,
398
            'company_country' => $object->country,
399
            'company_country_code' => $object->country_code,
400
            'company_state' => $object->state,
401
            'company_state_code' => $object->state_code,
402
            'company_web' => $object->url,
403
            'company_barcode' => $object->barcode,
404
            'company_vatnumber' => $object->tva_intra,
405
            'company_customercode' => $object->code_client,
406
            'company_suppliercode' => $object->code_fournisseur,
407
            'company_customeraccountancycode' => $object->code_compta_client,
408
            'company_supplieraccountancycode' => $object->code_compta_fournisseur,
409
            'company_juridicalstatus' => $object->forme_juridique,
410
            'company_outstanding_limit' => $object->outstanding_limit,
411
            'company_capital' => $object->capital,
412
            'company_capital_formated' => price($object->capital, 0, '', 1, -1),
413
            'company_idprof1' => $object->idprof1,
414
            'company_idprof2' => $object->idprof2,
415
            'company_idprof3' => $object->idprof3,
416
            'company_idprof4' => $object->idprof4,
417
            'company_idprof5' => $object->idprof5,
418
            'company_idprof6' => $object->idprof6,
419
            'company_note_public' => $object->note_public,
420
            'company_note_private' => $object->note_private,
421
            'company_default_bank_iban' => (is_object($object->bank_account) ? $object->bank_account->iban : ''),
422
            'company_default_bank_bic' => (is_object($object->bank_account) ? $object->bank_account->bic : '')
423
        );
424
425
        // Retrieve extrafields
426
        if (is_array($object->array_options) && count($object->array_options)) {
427
            $object->fetch_optionals();
428
429
            $array_thirdparty = $this->fill_substitutionarray_with_extrafields($object, $array_thirdparty, $extrafields, $array_key, $outputlangs);
430
        }
431
        return $array_thirdparty;
432
    }
433
434
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
435
    /**
436
     * Define array with couple substitution key => substitution value
437
     *
438
     * @param   Contact     $object         contact
439
     * @param   Translate   $outputlangs    object for output
440
     * @param   string      $array_key      Name of the key for return array
441
     * @return  array                       Array of substitution key->code
442
     */
443
    public function get_substitutionarray_contact($object, $outputlangs, $array_key = 'object')
444
    {
445
		// phpcs:enable
446
        global $conf, $extrafields;
447
448
        if (empty($object->country) && !empty($object->country_code)) {
449
            $object->country = $outputlangs->transnoentitiesnoconv("Country" . $object->country_code);
450
        }
451
        if (empty($object->state) && !empty($object->state_code)) {
452
            $object->state = getState($object->state_code, 0);
0 ignored issues
show
Documentation Bug introduced by
It seems like getState($object->state_code, 0) can also be of type array or array. However, the property $state is declared as type string. 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...
453
        }
454
455
        $array_contact = array(
456
            $array_key . '_fullname' => $object->getFullName($outputlangs, 1),
457
            $array_key . '_lastname' => $object->lastname,
458
            $array_key . '_firstname' => $object->firstname,
459
            $array_key . '_address' => $object->address,
460
            $array_key . '_zip' => $object->zip,
461
            $array_key . '_town' => $object->town,
462
            $array_key . '_state_id' => $object->state_id,
463
            $array_key . '_state_code' => $object->state_code,
464
            $array_key . '_state' => $object->state,
465
            $array_key . '_country_id' => $object->country_id,
466
            $array_key . '_country_code' => $object->country_code,
467
            $array_key . '_country' => $object->country,
468
            $array_key . '_poste' => $object->poste,
469
            $array_key . '_socid' => $object->socid,
470
            $array_key . '_statut' => $object->statut,
471
            $array_key . '_code' => $object->code,
472
            $array_key . '_email' => $object->email,
473
            $array_key . '_phone_pro' => $object->phone_pro,
474
            $array_key . '_phone_perso' => $object->phone_perso,
475
            $array_key . '_phone_mobile' => $object->phone_mobile,
476
            $array_key . '_fax' => $object->fax,
477
            $array_key . '_birthday' => $object->birthday,
478
            $array_key . '_default_lang' => $object->default_lang,
479
            $array_key . '_note_public' => $object->note_public,
480
            $array_key . '_note_private' => $object->note_private,
481
            $array_key . '_civility' => $object->civility,
482
        );
483
484
        // Retrieve extrafields
485
        if (is_array($object->array_options) && count($object->array_options)) {
486
            $object->fetch_optionals();
487
488
            $array_contact = $this->fill_substitutionarray_with_extrafields($object, $array_contact, $extrafields, $array_key, $outputlangs);
489
        }
490
        return $array_contact;
491
    }
492
493
494
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
495
    /**
496
     * Define array with couple substitution key => substitution value
497
     *
498
     * @param   Translate   $outputlangs    Language object for output
499
     * @return  array                       Array of substitution key->code
500
     */
501
    public function get_substitutionarray_other($outputlangs)
502
    {
503
		// phpcs:enable
504
        global $conf;
505
506
        $now = dol_now('gmt'); // gmt
507
        $array_other = array(
508
            // Date in default language
509
            'current_date' => dol_print_date($now, 'day', 'tzuser'),
510
            'current_datehour' => dol_print_date($now, 'dayhour', 'tzuser'),
511
            'current_server_date' => dol_print_date($now, 'day', 'tzserver'),
512
            'current_server_datehour' => dol_print_date($now, 'dayhour', 'tzserver'),
513
            // Date in requested output language
514
            'current_date_locale' => dol_print_date($now, 'day', 'tzuser', $outputlangs),
515
            'current_datehour_locale' => dol_print_date($now, 'dayhour', 'tzuser', $outputlangs),
516
            'current_server_date_locale' => dol_print_date($now, 'day', 'tzserver', $outputlangs),
517
            'current_server_datehour_locale' => dol_print_date($now, 'dayhour', 'tzserver', $outputlangs),
518
        );
519
520
521
        foreach ($conf->global as $key => $val) {
522
            if (isASecretKey($key)) {
523
                $newval = '*****forbidden*****';
524
            } else {
525
                $newval = $val;
526
            }
527
            $array_other['__[' . $key . ']__'] = $newval;
528
        }
529
530
        return $array_other;
531
    }
532
533
534
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
535
    /**
536
     * Define array with couple substitution key => substitution value
537
     * Note that vars into substitutions array are formatted.
538
     *
539
     * @param   CommonObject    $object             Main object to use as data source
540
     * @param   Translate       $outputlangs        Lang object to use for output
541
     * @param   string          $array_key          Name of the key for return array
542
     * @return  array                               Array of substitution
543
     */
544
    public function get_substitutionarray_object($object, $outputlangs, $array_key = 'object')
545
    {
546
		// phpcs:enable
547
        global $extrafields;
548
549
        $sumpayed = $sumdeposit = $sumcreditnote = '';
550
        $already_payed_all = 0;
551
552
        if ($object->element == 'facture') {
553
            /** @var Facture $object */
554
            $invoice_source = new Facture($this->db);
555
            if ($object->fk_facture_source > 0) {
556
                $invoice_source->fetch($object->fk_facture_source);
557
            }
558
            $sumpayed = $object->getSommePaiement();
559
            $sumdeposit = $object->getSumDepositsUsed();
560
            $sumcreditnote = $object->getSumCreditNotesUsed();
561
            $already_payed_all = $sumpayed + $sumdeposit + $sumcreditnote;
562
        }
563
564
        $date = (isset($object->element) && $object->element == 'contrat' && isset($object->date_contrat)) ? $object->date_contrat : (isset($object->date) ? $object->date : null);
0 ignored issues
show
Bug Best Practice introduced by
The property date does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property date_contrat does not exist on Dolibarr\Code\Compta\Classes\Facture. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property date_contrat does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
565
566
        if (get_only_class($object) == 'CommandeFournisseur') {
567
            /** @var CommandeFournisseur $object*/
568
            $object->date_validation =  $object->date_valid;
569
            $object->date_commande = $object->date;
570
        }
571
        $resarray = array(
572
            $array_key . '_id' => $object->id,
573
            $array_key . '_ref' => (property_exists($object, 'ref') ? $object->ref : ''),
574
            $array_key . '_label' => (property_exists($object, 'label') ? $object->label : ''),
575
            $array_key . '_ref_ext' => (property_exists($object, 'ref_ext') ? $object->ref_ext : ''),
576
            $array_key . '_ref_customer' => (!empty($object->ref_client) ? $object->ref_client : (empty($object->ref_customer) ? '' : $object->ref_customer)),
0 ignored issues
show
Bug Best Practice introduced by
The property ref_client does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property ref_customer does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
577
            $array_key . '_ref_supplier' => (!empty($object->ref_fournisseur) ? $object->ref_fournisseur : (empty($object->ref_supplier) ? '' : $object->ref_supplier)),
0 ignored issues
show
Bug Best Practice introduced by
The property ref_supplier does not exist on Dolibarr\Code\Compta\Classes\Facture. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property ref_supplier does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property ref_fournisseur does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property ref_fournisseur does not exist on Dolibarr\Code\Compta\Classes\Facture. Since you implemented __get, consider adding a @property annotation.
Loading history...
578
            $array_key . '_source_invoice_ref' => ((empty($invoice_source) || empty($invoice_source->ref)) ? '' : $invoice_source->ref),
579
            // Dates
580
            $array_key . '_hour' => dol_print_date($date, 'hour'),
581
            $array_key . '_date' => dol_print_date($date, 'day'),
582
            $array_key . '_date_rfc' => dol_print_date($date, 'dayrfc'),
583
            $array_key . '_date_limit' => (!empty($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'day') : ''),
0 ignored issues
show
Bug Best Practice introduced by
The property date_lim_reglement does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
584
            $array_key . '_date_limit_rfc' => (!empty($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'dayrfc') : ''),
585
            $array_key . '_date_end' => (!empty($object->fin_validite) ? dol_print_date($object->fin_validite, 'day') : ''),
0 ignored issues
show
Bug Best Practice introduced by
The property fin_validite does not exist on Dolibarr\Code\Compta\Classes\Facture. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property fin_validite does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
586
            $array_key . '_date_creation' => dol_print_date($object->date_creation, 'day'),
587
            $array_key . '_date_modification' => (!empty($object->date_modification) ? dol_print_date($object->date_modification, 'day') : ''),
588
            $array_key . '_date_validation' => (!empty($object->date_validation) ? dol_print_date($object->date_validation, 'dayhour') : ''),
589
            $array_key . '_date_approve' => (!empty($object->date_approve) ? dol_print_date($object->date_approve, 'day') : ''),
0 ignored issues
show
Bug Best Practice introduced by
The property date_approve does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property date_approve does not exist on Dolibarr\Code\Compta\Classes\Facture. Since you implemented __get, consider adding a @property annotation.
Loading history...
590
            $array_key . '_date_delivery_planed' => (!empty($object->delivery_date) ? dol_print_date($object->delivery_date, 'day') : ''),
0 ignored issues
show
Bug Best Practice introduced by
The property delivery_date does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
591
            $array_key . '_date_close' => (!empty($object->date_cloture) ? dol_print_date($object->date_cloture, 'dayhour') : ''),
592
593
            $array_key . '_payment_mode_code' => $object->mode_reglement_code,
0 ignored issues
show
Bug Best Practice introduced by
The property mode_reglement_code does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
594
            $array_key . '_payment_mode' => ($outputlangs->transnoentitiesnoconv('PaymentType' . $object->mode_reglement_code) != 'PaymentType' . $object->mode_reglement_code ? $outputlangs->transnoentitiesnoconv('PaymentType' . $object->mode_reglement_code) : $object->mode_reglement),
0 ignored issues
show
Bug Best Practice introduced by
The property mode_reglement does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
595
            $array_key . '_payment_term_code' => $object->cond_reglement_code,
0 ignored issues
show
Bug Best Practice introduced by
The property cond_reglement_code does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
596
            $array_key . '_payment_term' => ($outputlangs->transnoentitiesnoconv('PaymentCondition' . $object->cond_reglement_code) != 'PaymentCondition' . $object->cond_reglement_code ? $outputlangs->transnoentitiesnoconv('PaymentCondition' . $object->cond_reglement_code) : ($object->cond_reglement_doc ? $object->cond_reglement_doc : $object->cond_reglement)),
0 ignored issues
show
Bug Best Practice introduced by
The property $cond_reglement is declared private in Dolibarr\Core\Base\CommonObject. Since you implement __get, consider adding a @property or @property-read.
Loading history...
Bug Best Practice introduced by
The property cond_reglement_doc does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
597
598
            $array_key . '_incoterms' => (method_exists($object, 'display_incoterms') ? $object->display_incoterms() : ''),
0 ignored issues
show
Bug introduced by
The method display_incoterms() does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

598
            $array_key . '_incoterms' => (method_exists($object, 'display_incoterms') ? $object->/** @scrutinizer ignore-call */ display_incoterms() : ''),
Loading history...
599
600
            $array_key . '_total_ht_locale' => price($object->total_ht, 0, $outputlangs),
601
            $array_key . '_total_vat_locale' => (!empty($object->total_vat) ? price($object->total_vat, 0, $outputlangs) : price($object->total_tva, 0, $outputlangs)),
0 ignored issues
show
Bug Best Practice introduced by
The property total_vat does not exist on Dolibarr\Code\Compta\Classes\Facture. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property total_vat does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
602
            $array_key . '_total_localtax1_locale' => price($object->total_localtax1, 0, $outputlangs),
603
            $array_key . '_total_localtax2_locale' => price($object->total_localtax2, 0, $outputlangs),
604
            $array_key . '_total_ttc_locale' => price($object->total_ttc, 0, $outputlangs),
605
606
            $array_key . '_total_ht' => price2num($object->total_ht),
607
            $array_key . '_total_vat' => (!empty($object->total_vat) ? price2num($object->total_vat) : price2num($object->total_tva)),
608
            $array_key . '_total_localtax1' => price2num($object->total_localtax1),
609
            $array_key . '_total_localtax2' => price2num($object->total_localtax2),
610
            $array_key . '_total_ttc' => price2num($object->total_ttc),
611
612
            $array_key . '_multicurrency_code' => $object->multicurrency_code,
613
            $array_key . '_multicurrency_tx' => price2num($object->multicurrency_tx),
614
            $array_key . '_multicurrency_total_ht' => price2num($object->multicurrency_total_ht),
615
            $array_key . '_multicurrency_total_tva' => price2num($object->multicurrency_total_tva),
616
            $array_key . '_multicurrency_total_ttc' => price2num($object->multicurrency_total_ttc),
617
            $array_key . '_multicurrency_total_ht_locale' => price($object->multicurrency_total_ht, 0, $outputlangs),
618
            $array_key . '_multicurrency_total_tva_locale' => price($object->multicurrency_total_tva, 0, $outputlangs),
619
            $array_key . '_multicurrency_total_ttc_locale' => price($object->multicurrency_total_ttc, 0, $outputlangs),
620
621
            $array_key . '_note_private' => $object->note_private,
622
            $array_key . '_note_public' => $object->note_public,
623
            $array_key . '_note' => $object->note_public, // For backward compatibility
624
625
            // Payments
626
            $array_key . '_already_payed_locale' => price($sumpayed, 0, $outputlangs),
627
            $array_key . '_already_payed' => price2num($sumpayed),
628
            $array_key . '_already_deposit_locale' => price($sumdeposit, 0, $outputlangs),
629
            $array_key . '_already_deposit' => price2num($sumdeposit),
630
            $array_key . '_already_creditnote_locale' => price($sumcreditnote, 0, $outputlangs),
631
            $array_key . '_already_creditnote' => price2num($sumcreditnote),
632
633
            $array_key . '_already_payed_all_locale' => price(price2num($already_payed_all, 'MT'), 0, $outputlangs),
634
            $array_key . '_already_payed_all' => price2num($already_payed_all, 'MT'),
635
636
            // Remain to pay with all known information (except open direct debit requests)
637
            $array_key . '_remain_to_pay_locale' => price(price2num($object->total_ttc - $already_payed_all, 'MT'), 0, $outputlangs),
638
            $array_key . '_remain_to_pay' => price2num($object->total_ttc - $already_payed_all, 'MT')
639
        );
640
641
        if (in_array($object->element, array('facture', 'invoice', 'supplier_invoice', 'facture_fournisseur'))) {
642
            $bank_account = null;
643
644
            if (property_exists($object, 'fk_account') && $object->fk_account > 0) {
645
                $bank_account = new Account($this->db);
646
                $bank_account->fetch($object->fk_account);
647
            }
648
649
            $resarray[$array_key . '_bank_iban'] = (empty($bank_account) ? '' : $bank_account->iban);
650
            $resarray[$array_key . '_bank_bic'] = (empty($bank_account) ? '' : $bank_account->bic);
651
            $resarray[$array_key . '_bank_label'] = (empty($bank_account) ? '' : $bank_account->label);
652
            $resarray[$array_key . '_bank_number'] = (empty($bank_account) ? '' : $bank_account->number);
653
            $resarray[$array_key . '_bank_proprio'] = (empty($bank_account) ? '' : $bank_account->proprio);
0 ignored issues
show
Bug Best Practice introduced by
The property $proprio is declared private in Dolibarr\Code\Compta\Classes\Account. Since you implement __get, consider adding a @property or @property-read.
Loading history...
654
            $resarray[$array_key . '_bank_address'] = (empty($bank_account) ? '' : $bank_account->address);
655
            $resarray[$array_key . '_bank_state'] = (empty($bank_account) ? '' : $bank_account->state);
656
            $resarray[$array_key . '_bank_country'] = (empty($bank_account) ? '' : $bank_account->country);
657
        }
658
659
        if (method_exists($object, 'getTotalDiscount') && in_array(get_only_class($object), array('Propal', 'Proposal', 'Commande', 'Facture', 'SupplierProposal', 'CommandeFournisseur', 'FactureFournisseur'))) {
660
            $resarray[$array_key . '_total_discount_ht_locale'] = price($object->getTotalDiscount(), 0, $outputlangs);
661
            $resarray[$array_key . '_total_discount_ht'] = price2num($object->getTotalDiscount());
662
        } else {
663
            $resarray[$array_key . '_total_discount_ht_locale'] = '';
664
            $resarray[$array_key . '_total_discount_ht'] = '';
665
        }
666
667
        // Fetch project information if there is a project assigned to this object
668
        if ($object->element != "project" && !empty($object->fk_project) && $object->fk_project > 0) {
669
            if (!is_object($object->project)) {
670
                $object->fetch_projet();
671
            }
672
673
            $resarray[$array_key . '_project_ref'] = $object->project->ref;
674
            $resarray[$array_key . '_project_title'] = $object->project->title;
675
            $resarray[$array_key . '_project_description'] = $object->project->description;
676
            $resarray[$array_key . '_project_date_start'] = dol_print_date($object->project->date_start, 'day');
677
            $resarray[$array_key . '_project_date_end'] = dol_print_date($object->project->date_end, 'day');
678
        } else { // empty replacement
679
            $resarray[$array_key . '_project_ref'] = '';
680
            $resarray[$array_key . '_project_title'] = '';
681
            $resarray[$array_key . '_project_description'] = '';
682
            $resarray[$array_key . '_project_date_start'] = '';
683
            $resarray[$array_key . '_project_date_end'] = '';
684
        }
685
686
        // Add vat by rates
687
        if (is_array($object->lines) && count($object->lines) > 0) {
688
            $totalUp = 0;
689
            // Set substitution keys for different VAT rates
690
            foreach ($object->lines as $line) {
691
                // $line->tva_tx format depends on database field accuracy, no reliable. This is kept for backward compatibility
692
                if (empty($resarray[$array_key . '_total_vat_' . $line->tva_tx])) {
693
                    $resarray[$array_key . '_total_vat_' . $line->tva_tx] = 0;
694
                }
695
                $resarray[$array_key . '_total_vat_' . $line->tva_tx] += $line->total_tva;
696
                $resarray[$array_key . '_total_vat_locale_' . $line->tva_tx] = price($resarray[$array_key . '_total_vat_' . $line->tva_tx]);
697
                // $vatformated is vat without not expected chars (so 20, or 8.5 or 5.99 for example)
698
                $vatformated = vatrate($line->tva_tx);
699
                if (empty($resarray[$array_key . '_total_vat_' . $vatformated])) {
700
                    $resarray[$array_key . '_total_vat_' . $vatformated] = 0;
701
                }
702
                $resarray[$array_key . '_total_vat_' . $vatformated] += $line->total_tva;
703
                $resarray[$array_key . '_total_vat_locale_' . $vatformated] = price($resarray[$array_key . '_total_vat_' . $vatformated]);
704
705
                $totalUp += $line->subprice * $line->qty;
706
            }
707
708
            // Calculate total up and total discount percentage
709
            // Note that this added fields does not match a field into database in Dolibarr (Dolibarr manage discount on lines not as a global property of object)
710
            $resarray['object_total_up'] = $totalUp;
711
            $resarray['object_total_up_locale'] = price($resarray['object_total_up'], 0, $outputlangs);
712
            if (method_exists($object, 'getTotalDiscount') && in_array(get_only_class($object), array('Propal', 'Proposal', 'Commande', 'Facture', 'SupplierProposal', 'CommandeFournisseur', 'FactureFournisseur'))) {
713
                $totalDiscount = $object->getTotalDiscount();
714
            } else {
715
                $totalDiscount = 0;
716
            }
717
            if (!empty($totalUp) && !empty($totalDiscount)) {
718
                $resarray['object_total_discount'] = round(100 / $totalUp * $totalDiscount, 2);
719
                $resarray['object_total_discount_locale'] = price($resarray['object_total_discount'], 0, $outputlangs);
720
            } else {
721
                $resarray['object_total_discount'] = '';
722
                $resarray['object_total_discount_locale'] = '';
723
            }
724
        }
725
726
        // Retrieve extrafields
727
        if (is_array($object->array_options) && count($object->array_options)) {
728
            $object->fetch_optionals();
729
730
            $resarray = $this->fill_substitutionarray_with_extrafields($object, $resarray, $extrafields, $array_key, $outputlangs);
731
        }
732
733
        return $resarray;
734
    }
735
736
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
737
    /**
738
     *  Define array with couple substitution key => substitution value
739
     *  Note that vars into substitutions array are formatted.
740
     *
741
     *  @param  CommonObjectLine    $line           Object line
742
     *  @param  Translate           $outputlangs    Translate object to use for output
743
     *  @param  int                 $linenumber     The number of the line for the substitution of "object_line_pos"
744
     *  @return array                               Return a substitution array
745
     */
746
    public function get_substitutionarray_lines($line, $outputlangs, $linenumber = 0)
747
    {
748
		// phpcs:enable
749
        $resarray = array(
750
            'line_pos' => $linenumber,
751
            'line_fulldesc' => doc_getlinedesc($line, $outputlangs),
752
753
            'line_product_ref' => (empty($line->product_ref) ? '' : $line->product_ref),
754
            'line_product_ref_fourn' => (empty($line->ref_fourn) ? '' : $line->ref_fourn), // for supplier doc lines
0 ignored issues
show
Bug Best Practice introduced by
The property ref_fourn does not exist on Dolibarr\Core\Base\CommonObjectLine. Since you implemented __get, consider adding a @property annotation.
Loading history...
755
            'line_product_label' => (empty($line->product_label) ? '' : $line->product_label),
756
            'line_product_type' => (empty($line->product_type) ? '' : $line->product_type),
757
            'line_product_barcode' => (empty($line->product_barcode) ? '' : $line->product_barcode),
758
            'line_product_desc' => (empty($line->product_desc) ? '' : $line->product_desc),
759
760
            'line_desc' => $line->desc,
761
            'line_vatrate' => vatrate($line->tva_tx, true, $line->info_bits),
762
            'line_localtax1_rate' => vatrate($line->localtax1_tx),
0 ignored issues
show
Bug Best Practice introduced by
The property localtax1_tx does not exist on Dolibarr\Core\Base\CommonObjectLine. Since you implemented __get, consider adding a @property annotation.
Loading history...
763
            'line_localtax2_rate' => vatrate($line->localtax1_tx),
764
            'line_up' => price2num($line->subprice),
765
            'line_up_locale' => price($line->subprice, 0, $outputlangs),
766
            'line_total_up' => price2num($line->subprice * (float) $line->qty),
767
            'line_total_up_locale' => price($line->subprice * (float) $line->qty, 0, $outputlangs),
768
            'line_qty' => $line->qty,
769
            'line_discount_percent' => ($line->remise_percent ? $line->remise_percent . '%' : ''),
770
            'line_price_ht' => price2num($line->total_ht),
771
            'line_price_ttc' => price2num($line->total_ttc),
772
            'line_price_vat' => price2num($line->total_tva),
773
            'line_price_ht_locale' => price($line->total_ht, 0, $outputlangs),
774
            'line_price_ttc_locale' => price($line->total_ttc, 0, $outputlangs),
775
            'line_price_vat_locale' => price($line->total_tva, 0, $outputlangs),
776
            // Dates
777
            'line_date_start' => dol_print_date($line->date_start, 'day'),
0 ignored issues
show
Bug Best Practice introduced by
The property date_start does not exist on Dolibarr\Core\Base\CommonObjectLine. Since you implemented __get, consider adding a @property annotation.
Loading history...
778
            'line_date_start_locale' => dol_print_date($line->date_start, 'day', 'tzserver', $outputlangs),
779
            'line_date_start_rfc' => dol_print_date($line->date_start, 'dayrfc'),
780
            'line_date_end' => dol_print_date($line->date_end, 'day'),
0 ignored issues
show
Bug Best Practice introduced by
The property date_end does not exist on Dolibarr\Core\Base\CommonObjectLine. Since you implemented __get, consider adding a @property annotation.
Loading history...
781
            'line_date_end_locale' => dol_print_date($line->date_end, 'day', 'tzserver', $outputlangs),
782
            'line_date_end_rfc' => dol_print_date($line->date_end, 'dayrfc'),
783
784
            'line_multicurrency_code' => price2num($line->multicurrency_code),
785
            'line_multicurrency_subprice' => price2num($line->multicurrency_subprice),
786
            'line_multicurrency_total_ht' => price2num($line->multicurrency_total_ht),
787
            'line_multicurrency_total_tva' => price2num($line->multicurrency_total_tva),
788
            'line_multicurrency_total_ttc' => price2num($line->multicurrency_total_ttc),
789
            'line_multicurrency_subprice_locale' => price($line->multicurrency_subprice, 0, $outputlangs),
790
            'line_multicurrency_total_ht_locale' => price($line->multicurrency_total_ht, 0, $outputlangs),
791
            'line_multicurrency_total_tva_locale' => price($line->multicurrency_total_tva, 0, $outputlangs),
792
            'line_multicurrency_total_ttc_locale' => price($line->multicurrency_total_ttc, 0, $outputlangs),
793
        );
794
795
        // Units
796
        if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
797
            $resarray['line_unit'] = $outputlangs->trans($line->getLabelOfUnit('long'));
798
            $resarray['line_unit_short'] = $outputlangs->trans($line->getLabelOfUnit('short'));
799
        }
800
801
        // Retrieve extrafields
802
        $extrafieldkey = $line->table_element;
803
        $array_key = "line";
804
        $extrafields = new ExtraFields($this->db);
805
        $extrafields->fetch_name_optionals_label($extrafieldkey, true);
806
        $line->fetch_optionals();
807
808
        $resarray = $this->fill_substitutionarray_with_extrafields($line, $resarray, $extrafields, $array_key, $outputlangs);
809
810
        // Check if the current line belongs to a supplier order
811
        if (get_only_class($line) == 'CommandeFournisseurLigne') {
812
            // Add the product supplier extrafields to the substitutions
813
            $extrafields->fetch_name_optionals_label("product_fournisseur_price");
814
            $extralabels = $extrafields->attributes["product_fournisseur_price"]['label'];
815
816
            if (!empty($extralabels) && is_array($extralabels)) {
817
                $columns = "";
818
819
                foreach ($extralabels as $key => $label) {
820
                    $columns .= "$key, ";
821
                }
822
823
                if ($columns != "") {
824
                    $columns = substr($columns, 0, strlen($columns) - 2);
825
                    $resql = $this->db->query("SELECT " . $columns . " FROM " . $this->db->prefix() . "product_fournisseur_price_extrafields AS ex INNER JOIN " . $this->db->prefix() . "product_fournisseur_price AS f ON ex.fk_object = f.rowid WHERE f.ref_fourn = '" . $this->db->escape($line->ref_supplier) . "'");
0 ignored issues
show
Bug Best Practice introduced by
The property ref_supplier does not exist on Dolibarr\Core\Base\CommonObjectLine. Since you implemented __get, consider adding a @property annotation.
Loading history...
826
827
                    if ($this->db->num_rows($resql) > 0) {
828
                        $resql = $this->db->fetch_object($resql);
829
830
                        foreach ($extralabels as $key => $label) {
831
                            $resarray['line_product_supplier_' . $key] = $resql->$key;
832
                        }
833
                    }
834
                }
835
            }
836
        }
837
838
        // Load product data optional fields to the line -> enables to use "line_options_{extrafield}"
839
        if (isset($line->fk_product) && $line->fk_product > 0) {
840
            $tmpproduct = new Product($this->db);
841
            $result = $tmpproduct->fetch($line->fk_product);
842
            if (!empty($tmpproduct->array_options) && is_array($tmpproduct->array_options)) {
843
                foreach ($tmpproduct->array_options as $key => $label) {
844
                    $resarray["line_product_" . $key] = $label;
845
                }
846
            }
847
        } else {
848
            // Set unused placeholders as blank
849
            $extrafields->fetch_name_optionals_label("product");
850
            if ($extrafields->attributes["product"]['count'] > 0) {
851
                $extralabels = $extrafields->attributes["product"]['label'];
852
853
                foreach ($extralabels as $key => $label) {
854
                    $resarray['line_product_options_' . $key] = '';
855
                }
856
            }
857
        }
858
859
        return $resarray;
860
    }
861
862
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
863
    /**
864
     * Define array with couple substitution key => substitution value
865
     * Note that vars into substitutions array are formatted.
866
     *
867
     * @param   Expedition      $object             Main object to use as data source
868
     * @param   Translate       $outputlangs        Lang object to use for output
869
     * @param   string          $array_key          Name of the key for return array
870
     * @return  array                               Array of substitution
871
     */
872
    public function get_substitutionarray_shipment($object, $outputlangs, $array_key = 'object')
873
    {
874
		// phpcs:enable
875
        global $extrafields;
876
877
        include_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
878
879
        $object->list_delivery_methods($object->shipping_method_id);
880
        $calculatedVolume = ((float) $object->trueWidth * (float) $object->trueHeight * (float) $object->trueDepth);
881
882
        $array_shipment = array(
883
            $array_key . '_id' => $object->id,
884
            $array_key . '_ref' => $object->ref,
885
            $array_key . '_ref_ext' => $object->ref_ext,
886
            $array_key . '_ref_customer' => $object->ref_customer,
887
            $array_key . '_date_delivery' => dol_print_date($object->date_delivery, 'day'),
888
            $array_key . '_hour_delivery' => dol_print_date($object->date_delivery, 'hour'),
889
            $array_key . '_date_creation' => dol_print_date($object->date_creation, 'day'),
890
            $array_key . '_total_ht' => price($object->total_ht),
891
            $array_key . '_total_vat' => price($object->total_tva),
892
            $array_key . '_total_ttc' => price($object->total_ttc),
893
            $array_key . '_total_discount_ht' => price($object->getTotalDiscount()),
894
            $array_key . '_note_private' => $object->note_private,
895
            $array_key . '_note' => $object->note_public,
896
            $array_key . '_tracking_number' => $object->tracking_number,
897
            $array_key . '_tracking_url' => $object->tracking_url,
898
            $array_key . '_shipping_method' => $object->listmeths[0]['libelle'],
899
            $array_key . '_weight' => $object->trueWeight . ' ' . measuringUnitString(0, 'weight', $object->weight_units),
900
            $array_key . '_width' => $object->trueWidth . ' ' . measuringUnitString(0, 'size', $object->width_units),
901
            $array_key . '_height' => $object->trueHeight . ' ' . measuringUnitString(0, 'size', $object->height_units),
902
            $array_key . '_depth' => $object->trueDepth . ' ' . measuringUnitString(0, 'size', $object->depth_units),
903
            $array_key . '_size' => $calculatedVolume . ' ' . measuringUnitString(0, 'volume'),
904
        );
905
906
        // Add vat by rates
907
        foreach ($object->lines as $line) {
908
            if (empty($array_shipment[$array_key . '_total_vat_' . $line->tva_tx])) {
909
                $array_shipment[$array_key . '_total_vat_' . $line->tva_tx] = 0;
910
            }
911
            $array_shipment[$array_key . '_total_vat_' . $line->tva_tx] += $line->total_tva;
912
        }
913
914
        // Retrieve extrafields
915
        if (is_array($object->array_options) && count($object->array_options)) {
916
            $object->fetch_optionals();
917
918
            $array_shipment = $this->fill_substitutionarray_with_extrafields($object, $array_shipment, $extrafields, $array_key, $outputlangs);
919
        }
920
921
        // Add info from $object->xxx where xxx has been loaded by fetch_origin() of shipment
922
        if (is_object($object->commande) && !empty($object->commande->ref)) {
923
            $array_shipment['order_ref'] = $object->commande->ref;
924
            $array_shipment['order_ref_customer'] = $object->commande->ref_customer;
925
        }
926
927
        return $array_shipment;
928
    }
929
930
931
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
932
    /**
933
     * Define array with couple substitution key => substitution value
934
     *
935
     * @param   Object      $object         Dolibarr Object
936
     * @param   Translate   $outputlangs    Language object for output
937
     * @param   boolean|int $recursive      Want to fetch child array or child object.
938
     * @return  array                       Array of substitution key->code
939
     */
940
    public function get_substitutionarray_each_var_object(&$object, $outputlangs, $recursive = 1)
941
    {
942
		// phpcs:enable
943
        $array_other = array();
944
        if (!empty($object)) {
945
            foreach ($object as $key => $value) {
946
                if (in_array($key, array('db', 'fields', 'lines', 'modelpdf', 'model_pdf'))) {      // discard some properties
947
                    continue;
948
                }
949
                if (!empty($value)) {
950
                    if (!is_array($value) && !is_object($value)) {
951
                        $array_other['object_' . $key] = $value;
952
                    } elseif (is_array($value) && $recursive) {
953
                        $tmparray = $this->get_substitutionarray_each_var_object($value, $outputlangs, 0);
954
                        if (!empty($tmparray) && is_array($tmparray)) {
955
                            foreach ($tmparray as $key2 => $value2) {
956
                                $array_other['object_' . $key . '_' . preg_replace('/^object_/', '', $key2)] = $value2;
957
                            }
958
                        }
959
                    } elseif (is_object($value) && $recursive) {
960
                        $tmparray = $this->get_substitutionarray_each_var_object($value, $outputlangs, 0);
961
                        if (!empty($tmparray) && is_array($tmparray)) {
962
                            foreach ($tmparray as $key2 => $value2) {
963
                                $array_other['object_' . $key . '_' . preg_replace('/^object_/', '', $key2)] = $value2;
964
                            }
965
                        }
966
                    }
967
                }
968
            }
969
        }
970
971
        return $array_other;
972
    }
973
974
975
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
976
    /**
977
     *  Fill array with couple extrafield key => extrafield value
978
     *  Note that vars into substitutions array are formatted.
979
     *
980
     *  @param  Object          $object             Object with extrafields (must have $object->array_options filled)
981
     *  @param  array           $array_to_fill      Substitution array
982
     *  @param  Extrafields     $extrafields        Extrafields object
983
     *  @param  string          $array_key          Prefix for name of the keys into returned array
984
     *  @param  Translate       $outputlangs        Lang object to use for output
985
     *  @return array                               Substitution array
986
     */
987
    public function fill_substitutionarray_with_extrafields($object, $array_to_fill, $extrafields, $array_key, $outputlangs)
988
    {
989
		// phpcs:enable
990
        global $conf;
991
992
        if ($extrafields->attributes[$object->table_element]['count'] > 0) {
993
            foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
994
                $formatedarrayoption = $object->array_options;
995
996
                if ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
997
                    $formatedarrayoption['options_' . $key] = price2num($formatedarrayoption['options_' . $key]);
998
                    $formatedarrayoption['options_' . $key . '_currency'] = price($formatedarrayoption['options_' . $key], 0, $outputlangs, 0, 0, -1, $conf->currency);
999
                    //Add value to store price with currency
1000
                    $array_to_fill = array_merge($array_to_fill, array($array_key . '_options_' . $key . '_currency' => $formatedarrayoption['options_' . $key . '_currency']));
1001
                } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'select') {
1002
                    $valueofselectkey = $formatedarrayoption['options_' . $key];
1003
                    if (array_key_exists($valueofselectkey, $extrafields->attributes[$object->table_element]['param'][$key]['options'])) {
1004
                        $formatedarrayoption['options_' . $key] = $extrafields->attributes[$object->table_element]['param'][$key]['options'][$valueofselectkey];
1005
                    } else {
1006
                        $formatedarrayoption['options_' . $key] = '';
1007
                    }
1008
                } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'checkbox') {
1009
                    $valArray = explode(',', $formatedarrayoption['options_' . $key]);
1010
                    $output = array();
1011
                    foreach ($extrafields->attributes[$object->table_element]['param'][$key]['options'] as $keyopt => $valopt) {
1012
                        if (in_array($keyopt, $valArray)) {
1013
                            $output[] = $valopt;
1014
                        }
1015
                    }
1016
                    $formatedarrayoption['options_' . $key] = implode(', ', $output);
1017
                } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'date') {
1018
                    if (strlen($formatedarrayoption['options_' . $key]) > 0) {
1019
                        $date = $formatedarrayoption['options_' . $key];
1020
                        $formatedarrayoption['options_' . $key] = dol_print_date($date, 'day'); // using company output language
1021
                        $formatedarrayoption['options_' . $key . '_locale'] = dol_print_date($date, 'day', 'tzserver', $outputlangs); // using output language format
1022
                        $formatedarrayoption['options_' . $key . '_rfc'] = dol_print_date($date, 'dayrfc'); // international format
1023
                    } else {
1024
                        $formatedarrayoption['options_' . $key] = '';
1025
                        $formatedarrayoption['options_' . $key . '_locale'] = '';
1026
                        $formatedarrayoption['options_' . $key . '_rfc'] = '';
1027
                    }
1028
                    $array_to_fill = array_merge($array_to_fill, array($array_key . '_options_' . $key . '_locale' => $formatedarrayoption['options_' . $key . '_locale']));
1029
                    $array_to_fill = array_merge($array_to_fill, array($array_key . '_options_' . $key . '_rfc' => $formatedarrayoption['options_' . $key . '_rfc']));
1030
                } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'datetime') {
1031
                    $datetime = $formatedarrayoption['options_' . $key];
1032
                    $formatedarrayoption['options_' . $key] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour') : ''); // using company output language
1033
                    $formatedarrayoption['options_' . $key . '_locale'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour', 'tzserver', $outputlangs) : ''); // using output language format
1034
                    $formatedarrayoption['options_' . $key . '_rfc'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhourrfc') : ''); // international format
1035
                    $array_to_fill = array_merge($array_to_fill, array($array_key . '_options_' . $key . '_locale' => $formatedarrayoption['options_' . $key . '_locale']));
1036
                    $array_to_fill = array_merge($array_to_fill, array($array_key . '_options_' . $key . '_rfc' => $formatedarrayoption['options_' . $key . '_rfc']));
1037
                } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'link') {
1038
                    $id = $formatedarrayoption['options_' . $key];
1039
                    if ($id != "") {
1040
                        $param = $extrafields->attributes[$object->table_element]['param'][$key];
1041
                        $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
1042
                        $InfoFieldList = explode(":", $param_list[0]);
1043
                        $classname = $InfoFieldList[0];
1044
                        $classpath = $InfoFieldList[1];
1045
                        if (!empty($classpath)) {
1046
                            dol_include_once($InfoFieldList[1]);
1047
                            if ($classname && class_exists($classname)) {
1048
                                $tmpobject = new $classname($this->db);
1049
                                $tmpobject->fetch($id);
1050
                                // completely replace the id with the linked object name
1051
                                $formatedarrayoption['options_' . $key] = $tmpobject->name;
1052
                            }
1053
                        }
1054
                    }
1055
                }
1056
1057
                if (array_key_exists('options_' . $key, $formatedarrayoption)) {
1058
                    $array_to_fill = array_merge($array_to_fill, array($array_key . '_options_' . $key => $formatedarrayoption['options_' . $key]));
1059
                } else {
1060
                    $array_to_fill = array_merge($array_to_fill, array($array_key . '_options_' . $key => ''));
1061
                }
1062
            }
1063
        }
1064
1065
        return $array_to_fill;
1066
    }
1067
1068
1069
    /**
1070
     * Rect pdf
1071
     *
1072
     * @param   TCPDI|TCPDF $pdf            Pdf object
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Core\Classes\TCPDF was not found. Did you mean TCPDF? If so, make sure to prefix the type with \.
Loading history...
Bug introduced by
The type Dolibarr\Code\Core\Classes\TCPDI was not found. Did you mean TCPDI? If so, make sure to prefix the type with \.
Loading history...
1073
     * @param   float       $x              Abscissa of first point
1074
     * @param   float       $y              Ordinate of first point
1075
     * @param   float       $l              ??
1076
     * @param   float       $h              ??
1077
     * @param   int         $hidetop        1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title
1078
     * @param   int         $hidebottom     Hide bottom
1079
     * @return  void
1080
     */
1081
    public function printRect($pdf, $x, $y, $l, $h, $hidetop = 0, $hidebottom = 0)
1082
    {
1083
        if (empty($hidetop) || $hidetop == -1) {
1084
            $pdf->line($x, $y, $x + $l, $y);
1085
        }
1086
        $pdf->line($x + $l, $y, $x + $l, $y + $h);
1087
        if (empty($hidebottom)) {
1088
            $pdf->line($x + $l, $y + $h, $x, $y + $h);
1089
        }
1090
        $pdf->line($x, $y + $h, $x, $y);
1091
    }
1092
1093
1094
    /**
1095
     *  uasort callback function to Sort columns fields
1096
     *
1097
     *  @param  array           $a              PDF lines array fields configs
1098
     *  @param  array           $b              PDF lines array fields configs
1099
     *  @return int                             Return compare result
1100
     */
1101
    public function columnSort($a, $b)
1102
    {
1103
        if (empty($a['rank'])) {
1104
            $a['rank'] = 0;
1105
        }
1106
        if (empty($b['rank'])) {
1107
            $b['rank'] = 0;
1108
        }
1109
        if ($a['rank'] == $b['rank']) {
1110
            return 0;
1111
        }
1112
        return ($a['rank'] > $b['rank']) ? -1 : 1;
1113
    }
1114
1115
    /**
1116
     *      Prepare Array Column Field
1117
     *
1118
     *      @param  object          $object             common object
1119
     *      @param  Translate       $outputlangs        langs
1120
     *      @param  int             $hidedetails        Do not show line details
1121
     *      @param  int             $hidedesc           Do not show desc
1122
     *      @param  int             $hideref            Do not show ref
1123
     *      @return void
1124
     */
1125
    public function prepareArrayColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1126
    {
1127
        $this->defineColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref);
1128
1129
1130
        // Sorting
1131
        uasort($this->cols, array($this, 'columnSort'));
1132
1133
        // Positioning
1134
        $curX = $this->page_largeur - $this->marge_droite; // start from right
1135
1136
        // Array width
1137
        $arrayWidth = $this->page_largeur - $this->marge_droite - $this->marge_gauche;
1138
1139
        // Count flexible column
1140
        $totalDefinedColWidth = 0;
1141
        $countFlexCol = 0;
1142
        foreach ($this->cols as $colKey => & $colDef) {
1143
            if (!$this->getColumnStatus($colKey)) {
1144
                continue; // continue if disabled
1145
            }
1146
1147
            if (!empty($colDef['scale'])) {
1148
                // In case of column width is defined by percentage
1149
                $colDef['width'] = abs($arrayWidth * $colDef['scale'] / 100);
1150
            }
1151
1152
            if (empty($colDef['width'])) {
1153
                $countFlexCol++;
1154
            } else {
1155
                $totalDefinedColWidth += $colDef['width'];
1156
            }
1157
        }
1158
1159
        foreach ($this->cols as $colKey => & $colDef) {
1160
            // setting empty conf with default
1161
            if (!empty($colDef['title'])) {
1162
                $colDef['title'] = array_replace($this->defaultTitlesFieldsStyle, $colDef['title']);
1163
            } else {
1164
                $colDef['title'] = $this->defaultTitlesFieldsStyle;
1165
            }
1166
1167
            // setting empty conf with default
1168
            if (!empty($colDef['content'])) {
1169
                $colDef['content'] = array_replace($this->defaultContentsFieldsStyle, $colDef['content']);
1170
            } else {
1171
                $colDef['content'] = $this->defaultContentsFieldsStyle;
1172
            }
1173
1174
            if ($this->getColumnStatus($colKey)) {
1175
                // In case of flexible column
1176
                if (empty($colDef['width'])) {
1177
                    $colDef['width'] = abs(($arrayWidth - $totalDefinedColWidth)) / $countFlexCol;
1178
                }
1179
1180
                // Set positions
1181
                $lastX = $curX;
1182
                $curX = $lastX - $colDef['width'];
1183
                $colDef['xStartPos'] = $curX;
1184
                $colDef['xEndPos']   = $lastX;
1185
            }
1186
        }
1187
    }
1188
1189
    /**
1190
     *  get column content width from column key
1191
     *
1192
     *  @param  string      $colKey     the column key
1193
     *  @return float                   width in mm
1194
     */
1195
    public function getColumnContentWidth($colKey)
1196
    {
1197
        $colDef = $this->cols[$colKey];
1198
        return  $colDef['width'] - $colDef['content']['padding'][3] - $colDef['content']['padding'][1];
1199
    }
1200
1201
1202
    /**
1203
     *  get column content X (abscissa) left position from column key
1204
     *
1205
     *  @param  string    $colKey           the column key
1206
     *  @return float      X position in mm
1207
     */
1208
    public function getColumnContentXStart($colKey)
1209
    {
1210
        $colDef = (isset($this->cols[$colKey]) ? $this->cols[$colKey] : null);
1211
        return (is_array($colDef) ? ((isset($colDef['xStartPos']) ? $colDef['xStartPos'] : 0) + $colDef['content']['padding'][3]) : 0);
1212
    }
1213
1214
    /**
1215
     *  get column position rank from column key
1216
     *
1217
     *  @param  string      $colKey         the column key
1218
     *  @return int         rank on success and -1 on error
1219
     */
1220
    public function getColumnRank($colKey)
1221
    {
1222
        if (!isset($this->cols[$colKey]['rank'])) {
1223
            return -1;
1224
        }
1225
        return  $this->cols[$colKey]['rank'];
1226
    }
1227
1228
    /**
1229
     *  get column position rank from column key
1230
     *
1231
     *  @param  string      $newColKey          the new column key
1232
     *  @param  array       $defArray           a single column definition array
1233
     *  @param  string      $targetCol          target column used to place the new column beside
1234
     *  @param  bool        $insertAfterTarget  insert before or after target column ?
1235
     *  @return int                             new rank on success and -1 on error
1236
     */
1237
    public function insertNewColumnDef($newColKey, $defArray, $targetCol = '', $insertAfterTarget = false)
1238
    {
1239
        // prepare wanted rank
1240
        $rank = -1;
1241
1242
        // try to get rank from target column
1243
        if (!empty($targetCol)) {
1244
            $rank = $this->getColumnRank($targetCol);
1245
            if ($rank >= 0 && $insertAfterTarget) {
1246
                $rank++;
1247
            }
1248
        }
1249
1250
        // get rank from new column definition
1251
        if ($rank < 0 && !empty($defArray['rank'])) {
1252
            $rank = $defArray['rank'];
1253
        }
1254
1255
        // error: no rank
1256
        if ($rank < 0) {
1257
            return -1;
1258
        }
1259
1260
        foreach ($this->cols as $colKey => & $colDef) {
1261
            if ($rank <= $colDef['rank']) {
1262
                $colDef['rank'] = $colDef['rank'] + 1;
1263
            }
1264
        }
1265
1266
        $defArray['rank'] = $rank;
1267
        $this->cols[$newColKey] = $defArray; // array_replace is used to preserve keys
1268
1269
        return $rank;
1270
    }
1271
1272
1273
    /**
1274
     *  print standard column content
1275
     *
1276
     *  @param  TCPDI|TCPDF $pdf            Pdf object
1277
     *  @param  float       $curY           current Y position
1278
     *  @param  string      $colKey         the column key
1279
     *  @param  string      $columnText     column text
1280
     *  @return int                         Return integer <0 if KO, >= if OK
1281
     */
1282
    public function printStdColumnContent($pdf, &$curY, $colKey, $columnText = '')
1283
    {
1284
        global $hookmanager;
1285
1286
        $parameters = array(
1287
            'curY' => &$curY,
1288
            'columnText' => $columnText,
1289
            'colKey' => $colKey,
1290
            'pdf' => &$pdf,
1291
        );
1292
        $reshook = $hookmanager->executeHooks('printStdColumnContent', $parameters, $this); // Note that $action and $object may have been modified by hook
1293
        if ($reshook < 0) {
1294
            setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1295
        }
1296
        if (!$reshook) {
1297
            if (empty($columnText)) {
1298
                return 0;
1299
            }
1300
            $pdf->SetXY($this->getColumnContentXStart($colKey), $curY); // Set current position
1301
            $colDef = $this->cols[$colKey];
1302
            // save current cell padding
1303
            $curentCellPaddinds = $pdf->getCellPaddings();
1304
            // set cell padding with column content definition
1305
            $pdf->setCellPaddings(isset($colDef['content']['padding'][3]) ? $colDef['content']['padding'][3] : 0, isset($colDef['content']['padding'][0]) ? $colDef['content']['padding'][0] : 0, isset($colDef['content']['padding'][1]) ? $colDef['content']['padding'][1] : 0, isset($colDef['content']['padding'][2]) ? $colDef['content']['padding'][2] : 0);
1306
            $pdf->writeHTMLCell($colDef['width'], 2, isset($colDef['xStartPos']) ? $colDef['xStartPos'] : 0, $curY, $columnText, 0, 1, 0, true, $colDef['content']['align']);
1307
1308
            // restore cell padding
1309
            $pdf->setCellPaddings($curentCellPaddinds['L'], $curentCellPaddinds['T'], $curentCellPaddinds['R'], $curentCellPaddinds['B']);
1310
        }
1311
1312
        return 0;
1313
    }
1314
1315
1316
    /**
1317
     *  print description column content
1318
     *
1319
     *  @param  TCPDI|TCPDF $pdf            Pdf object
1320
     *  @param  float       $curY           current Y position
1321
     *  @param  string      $colKey         the column key
1322
     *  @param  object      $object         CommonObject
1323
     *  @param  int         $i              the $object->lines array key
1324
     *  @param  Translate   $outputlangs    Output language
1325
     *  @param  int         $hideref        hide ref
1326
     *  @param  int         $hidedesc       hide desc
1327
     *  @param  int         $issupplierline if object need supplier product
1328
     *  @return void
1329
     */
1330
    public function printColDescContent($pdf, &$curY, $colKey, $object, $i, $outputlangs, $hideref = 0, $hidedesc = 0, $issupplierline = 0)
1331
    {
1332
        // load desc col params
1333
        $colDef = $this->cols[$colKey];
1334
        // save current cell padding
1335
        $curentCellPaddinds = $pdf->getCellPaddings();
1336
        // set cell padding with column content definition
1337
        $pdf->setCellPaddings($colDef['content']['padding'][3], $colDef['content']['padding'][0], $colDef['content']['padding'][1], $colDef['content']['padding'][2]);
1338
1339
        // line description
1340
        pdf_writelinedesc($pdf, $object, $i, $outputlangs, $colDef['width'], 3, $colDef['xStartPos'], $curY, $hideref, $hidedesc, $issupplierline, empty($colDef['content']['align']) ? 'J' : $colDef['content']['align']);
1341
        $posYAfterDescription = $pdf->GetY() - $colDef['content']['padding'][0];
1342
1343
        // restore cell padding
1344
        $pdf->setCellPaddings($curentCellPaddinds['L'], $curentCellPaddinds['T'], $curentCellPaddinds['R'], $curentCellPaddinds['B']);
1345
1346
        // Display extrafield if needed
1347
        $params = array(
1348
            'display'         => 'list',
1349
            'printableEnable' => array(3),
1350
            'printableEnableNotEmpty' => array(4)
1351
        );
1352
        $extrafieldDesc = $this->getExtrafieldsInHtml($object->lines[$i], $outputlangs, $params);
1353
        if (!empty($extrafieldDesc)) {
1354
            $this->printStdColumnContent($pdf, $posYAfterDescription, $colKey, $extrafieldDesc);
1355
        }
1356
    }
1357
1358
    /**
1359
     *  get extrafield content for pdf writeHtmlCell compatibility
1360
     *  usage for PDF line columns and object note block
1361
     *
1362
     *  @param  CommonObject    $object             Common object
1363
     *  @param  string          $extrafieldKey      The extrafield key
1364
     *  @param  Translate       $outputlangs        The output langs (if value is __(XXX)__ we use it to translate it).
1365
     *  @return string
1366
     */
1367
    public function getExtrafieldContent($object, $extrafieldKey, $outputlangs = null)
1368
    {
1369
        global $hookmanager;
1370
1371
        if (empty($object->table_element)) {
1372
            return '';
1373
        }
1374
1375
        $extrafieldsKeyPrefix = "options_";
1376
1377
        // Cleanup extrafield key to remove prefix if present
1378
        $pos = strpos($extrafieldKey, $extrafieldsKeyPrefix);
1379
        if ($pos === 0) {
1380
            $extrafieldKey = substr($extrafieldKey, strlen($extrafieldsKeyPrefix));
1381
        }
1382
1383
        $extrafieldOptionsKey = $extrafieldsKeyPrefix . $extrafieldKey;
1384
1385
1386
        // Load extra fields if they haven't been loaded already.
1387
        if (is_null($this->extrafieldsCache)) {
1388
            $this->extrafieldsCache = new ExtraFields($this->db);
1389
        }
1390
        if (empty($this->extrafieldsCache->attributes[$object->table_element])) {
1391
            $this->extrafieldsCache->fetch_name_optionals_label($object->table_element);
1392
        }
1393
        $extrafields = $this->extrafieldsCache;
1394
1395
        $extrafieldOutputContent = '';
1396
        if (isset($object->array_options[$extrafieldOptionsKey])) {
1397
            $extrafieldOutputContent = $extrafields->showOutputField($extrafieldKey, $object->array_options[$extrafieldOptionsKey], '', $object->table_element, $outputlangs);
1398
        }
1399
1400
        // TODO : allow showOutputField to be pdf public friendly, ex: in a link to object, clean getNomUrl to remove link and images... like a getName methode ...
1401
        if ($extrafields->attributes[$object->table_element]['type'][$extrafieldKey] == 'link') {
1402
            // for lack of anything better we cleanup all html tags
1403
            $extrafieldOutputContent = dol_string_nohtmltag($extrafieldOutputContent);
1404
        }
1405
1406
        $parameters = array(
1407
            'object' => $object,
1408
            'extrafields' => $extrafields,
1409
            'extrafieldKey' => $extrafieldKey,
1410
            'extrafieldOutputContent' => & $extrafieldOutputContent
1411
        );
1412
        $reshook = $hookmanager->executeHooks('getPDFExtrafieldContent', $parameters, $this); // Note that $action and $object may have been modified by hook
1413
        if ($reshook < 0) {
1414
            setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1415
        }
1416
        if ($reshook) {
1417
            $extrafieldOutputContent = $hookmanager->resPrint;
1418
        }
1419
1420
        return $extrafieldOutputContent;
1421
    }
1422
1423
    /**
1424
     *  display extrafields columns content
1425
     *
1426
     *  @param  CommonObjectLine    $object         line of common object
1427
     *  @param  Translate           $outputlangs    Output language
1428
     *  @param  array               $params         array of additional parameters
1429
     *  @return string                              Html string
1430
     */
1431
    public function getExtrafieldsInHtml($object, $outputlangs, $params = array())
1432
    {
1433
        global $hookmanager;
1434
1435
        if (empty($object->table_element)) {
1436
            return "";
1437
        }
1438
1439
        // Load extrafields if not already done
1440
        if (is_null($this->extrafieldsCache)) {
1441
            $this->extrafieldsCache = new ExtraFields($this->db);
1442
        }
1443
        if (empty($this->extrafieldsCache->attributes[$object->table_element])) {
1444
            $this->extrafieldsCache->fetch_name_optionals_label($object->table_element);
1445
        }
1446
        $extrafields = $this->extrafieldsCache;
1447
1448
        $defaultParams = array(
1449
            'style'         => '',
1450
            'display'         => 'auto', // auto, table, list
1451
            'printableEnable' => array(1),
1452
            'printableEnableNotEmpty' => array(2),
1453
1454
            'table'         => array(
1455
                'maxItemsInRow' => 2,
1456
                'cellspacing'   => 0,
1457
                'cellpadding'   => 0,
1458
                'border'        => 0,
1459
                'labelcolwidth' => '25%',
1460
                'arrayOfLineBreakType' => array('text', 'html')
1461
            ),
1462
1463
            'list'         => array(
1464
                'separator' => '<br>'
1465
            ),
1466
1467
            'auto'         => array(
1468
                'list' => 0, // 0 for default
1469
                'table' => 4 // if there more than x extrafield to display
1470
            ),
1471
        );
1472
1473
        $params = $params + $defaultParams;
1474
1475
        /**
1476
         * @var ExtraFields $extrafields
1477
         */
1478
1479
        $html = '';
1480
        $fields = array();
1481
1482
        if (!empty($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label'])) {
1483
            foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
1484
                // Enable extrafield ?
1485
                $enabled = 0;
1486
                $disableOnEmpty = 0;
1487
                if (!empty($extrafields->attributes[$object->table_element]['printable'][$key])) {
1488
                    $printable = intval($extrafields->attributes[$object->table_element]['printable'][$key]);
1489
                    if (in_array($printable, $params['printableEnable']) || in_array($printable, $params['printableEnableNotEmpty'])) {
1490
                        $enabled = 1;
1491
                    }
1492
1493
                    if (in_array($printable, $params['printableEnableNotEmpty'])) {
1494
                        $disableOnEmpty = 1;
1495
                    }
1496
                }
1497
1498
                if (empty($enabled)) {
1499
                    continue;
1500
                }
1501
1502
                // Load language if required
1503
                if (!empty($extrafields->attributes[$object->table_element]['langfile'][$key])) {
1504
                    $outputlangs->load($extrafields->attributes[$object->table_element]['langfile'][$key]);
1505
                }
1506
1507
                $field = new stdClass();
1508
                $field->rank = intval($extrafields->attributes[$object->table_element]['pos'][$key]);
1509
                $field->content = $this->getExtrafieldContent($object, $key, $outputlangs);
1510
                $field->label = $outputlangs->transnoentities($label);
1511
                $field->type = $extrafields->attributes[$object->table_element]['type'][$key];
1512
1513
                // don't display if empty
1514
                if ($disableOnEmpty && empty($field->content)) {
1515
                    continue;
1516
                }
1517
1518
                $fields[] = $field;
1519
            }
1520
        }
1521
1522
        if (!empty($fields)) {
1523
            // Sort extrafields by rank
1524
            uasort(
1525
                $fields,
1526
                /**
1527
                 * @param stdClass $a
1528
                 * @param stdClass $b
1529
                 * @return int<-1,1>
1530
                 */
1531
                static function ($a, $b) {
1532
                    return  ($a->rank > $b->rank) ? 1 : -1;
1533
                }
1534
            );
1535
1536
            // define some HTML content with style
1537
            $html .= !empty($params['style']) ? '<style>' . $params['style'] . '</style>' : '';
1538
1539
            // auto select display format
1540
            if ($params['display'] == 'auto') {
1541
                $lastNnumbItems = 0;
1542
                foreach ($params['auto'] as $display => $numbItems) {
1543
                    if ($lastNnumbItems <= $numbItems && count($fields) > $numbItems) {
1544
                        $lastNnumbItems = $numbItems;
1545
                        $params['display'] = $display;
1546
                    }
1547
                }
1548
            }
1549
1550
            if ($params['display'] == 'list') {
1551
                // Display in list format
1552
                $i = 0;
1553
                foreach ($fields as $field) {
1554
                    $html .= !empty($i) ? $params['list']['separator'] : '';
1555
                    $html .= '<strong>' . $field->label . ' : </strong>';
1556
                    $html .= $field->content;
1557
                    $i++;
1558
                }
1559
            } elseif ($params['display'] == 'table') {
1560
                // Display in table format
1561
                $html .= '<table class="extrafield-table" cellspacing="' . $params['table']['cellspacing'] . '" cellpadding="' . $params['table']['cellpadding'] . '" border="' . $params['table']['border'] . '">';
1562
1563
                $html .= "<tr>";
1564
                $itemsInRow = 0;
1565
                $maxItemsInRow = $params['table']['maxItemsInRow'];
1566
                foreach ($fields as $field) {
1567
                    //$html.= !empty($html)?'<br>':'';
1568
                    if ($itemsInRow >= $maxItemsInRow) {
1569
                        // start a new line
1570
                        $html .= "</tr><tr>";
1571
                        $itemsInRow = 0;
1572
                    }
1573
1574
                    // for some type we need line break
1575
                    if (in_array($field->type, $params['table']['arrayOfLineBreakType'])) {
1576
                        if ($itemsInRow > 0) {
1577
                            // close table row and empty cols
1578
                            for ($i = $itemsInRow; $i <= $maxItemsInRow; $i++) {
1579
                                $html .= "<td></td><td></td>";
1580
                            }
1581
                            $html .= "</tr>";
1582
1583
                            // start a new line
1584
                            $html .= "<tr>";
1585
                        }
1586
1587
                        $itemsInRow = $maxItemsInRow;
1588
                        $html .= '<td colspan="' . ($maxItemsInRow * 2 - 1) . '">';
1589
                        $html .= '<strong>' . $field->label . ' :</strong> ';
1590
                        $html .= $field->content;
1591
                        $html .= "</td>";
1592
                    } else {
1593
                        $itemsInRow++;
1594
                        $html .= '<td width="' . $params['table']['labelcolwidth'] . '" class="extrafield-label">';
1595
                        $html .= '<strong>' . $field->label . ' :</strong>';
1596
                        $html .= "</td>";
1597
1598
1599
                        $html .= '<td  class="extrafield-content">';
1600
                        $html .= $field->content;
1601
                        $html .= "</td>";
1602
                    }
1603
                }
1604
                $html .= "</tr>";
1605
1606
                $html .= '</table>';
1607
            }
1608
        }
1609
1610
        return $html;
1611
    }
1612
1613
1614
    /**
1615
     *  get column status from column key
1616
     *
1617
     *  @param  string      $colKey         the column key
1618
     *  @return boolean                     true if column on
1619
     */
1620
    public function getColumnStatus($colKey)
1621
    {
1622
        if (!empty($this->cols[$colKey]['status'])) {
1623
            return true;
1624
        } else {
1625
            return  false;
1626
        }
1627
    }
1628
1629
    /**
1630
     * Print standard column content
1631
     *
1632
     * @param TCPDI|TCPDF   $pdf            Pdf object
1633
     * @param float         $tab_top        Tab top position
1634
     * @param float         $tab_height     Default tab height
1635
     * @param Translate     $outputlangs    Output language
1636
     * @param int           $hidetop        Hide top
1637
     * @return float                        Height of col tab titles
1638
     */
1639
    public function pdfTabTitles(&$pdf, $tab_top, $tab_height, $outputlangs, $hidetop = 0)
1640
    {
1641
        global $hookmanager, $conf;
1642
1643
        foreach ($this->cols as $colKey => $colDef) {
1644
            $parameters = array(
1645
                'colKey' => $colKey,
1646
                'pdf' => $pdf,
1647
                'outputlangs' => $outputlangs,
1648
                'tab_top' => $tab_top,
1649
                'tab_height' => $tab_height,
1650
                'hidetop' => $hidetop
1651
            );
1652
1653
            $reshook = $hookmanager->executeHooks('pdfTabTitles', $parameters, $this); // Note that $object may have been modified by hook
1654
            if ($reshook < 0) {
1655
                setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1656
            } elseif (empty($reshook)) {
1657
                if (!$this->getColumnStatus($colKey)) {
1658
                    continue;
1659
                }
1660
1661
                // get title label
1662
                $colDef['title']['label'] = !empty($colDef['title']['label']) ? $colDef['title']['label'] : $outputlangs->transnoentities($colDef['title']['textkey']);
1663
1664
                // Add column separator
1665
                if (!empty($colDef['border-left']) && isset($colDef['xStartPos'])) {
1666
                    $pdf->line($colDef['xStartPos'], $tab_top, $colDef['xStartPos'], $tab_top + $tab_height);
1667
                }
1668
1669
                if (empty($hidetop)) {
1670
                    // save current cell padding
1671
                    $curentCellPaddinds = $pdf->getCellPaddings();
1672
1673
                    // Add space for lines (more if we need to show a second alternative language)
1674
                    global $outputlangsbis;
1675
                    if (is_object($outputlangsbis)) {
1676
                        // set cell padding with column title definition
1677
                        $pdf->setCellPaddings($colDef['title']['padding'][3], $colDef['title']['padding'][0], $colDef['title']['padding'][1], 0.5);
1678
                    } else {
1679
                        // set cell padding with column title definition
1680
                        $pdf->setCellPaddings($colDef['title']['padding'][3], $colDef['title']['padding'][0], $colDef['title']['padding'][1], $colDef['title']['padding'][2]);
1681
                    }
1682
                    if (isset($colDef['title']['align'])) {
1683
                        $align = $colDef['title']['align'];
1684
                    } else {
1685
                        $align = '';
1686
                    }
1687
                    $pdf->SetXY($colDef['xStartPos'], $tab_top);
1688
                    $textWidth = $colDef['width'];
1689
                    $pdf->MultiCell($textWidth, 2, $colDef['title']['label'], '', $align);
1690
1691
                    // Add variant of translation if $outputlangsbis is an object
1692
                    if (is_object($outputlangsbis) && trim($colDef['title']['label'])) {
1693
                        $pdf->setCellPaddings($colDef['title']['padding'][3], 0, $colDef['title']['padding'][1], $colDef['title']['padding'][2]);
1694
                        $pdf->SetXY($colDef['xStartPos'], $pdf->GetY());
1695
                        $textbis = $outputlangsbis->transnoentities($colDef['title']['textkey']);
1696
                        $pdf->MultiCell($textWidth, 2, $textbis, '', $align);
1697
                    }
1698
1699
                    $this->tabTitleHeight = max($pdf->GetY() - $tab_top, $this->tabTitleHeight);
1700
1701
                    // restore cell padding
1702
                    $pdf->setCellPaddings($curentCellPaddinds['L'], $curentCellPaddinds['T'], $curentCellPaddinds['R'], $curentCellPaddinds['B']);
1703
                }
1704
            }
1705
        }
1706
1707
        return $this->tabTitleHeight;
1708
    }
1709
1710
1711
1712
    /**
1713
     *  Define Array Column Field for extrafields
1714
     *
1715
     *  @param  object          $object         common object det
1716
     *  @param  Translate       $outputlangs    langs
1717
     *  @param  int            $hidedetails     Do not show line details
1718
     *  @return int                             Return integer <0 if KO, >=0 if OK
1719
     */
1720
    public function defineColumnExtrafield($object, $outputlangs, $hidedetails = 0)
1721
    {
1722
        if (!empty($hidedetails)) {
1723
            return 0;
1724
        }
1725
1726
        if (empty($object->table_element)) {
1727
            return 0;
1728
        }
1729
1730
        // Load extra fields if they haven't been loaded already.
1731
        if (is_null($this->extrafieldsCache)) {
1732
            $this->extrafieldsCache = new ExtraFields($this->db);
1733
        }
1734
        if (empty($this->extrafieldsCache->attributes[$object->table_element])) {
1735
            $this->extrafieldsCache->fetch_name_optionals_label($object->table_element);
1736
        }
1737
        $extrafields = $this->extrafieldsCache;
1738
1739
1740
        if (!empty($extrafields->attributes[$object->table_element]) && is_array($extrafields->attributes[$object->table_element]) && array_key_exists('label', $extrafields->attributes[$object->table_element]) && is_array($extrafields->attributes[$object->table_element]['label'])) {
1741
            foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
1742
                // Don't display separator yet even is set to be displayed (not compatible yet)
1743
                if ($extrafields->attributes[$object->table_element]['type'][$key] == 'separate') {
1744
                    continue;
1745
                }
1746
1747
                // Enable extrafield ?
1748
                $enabled = 0;
1749
                if (!empty($extrafields->attributes[$object->table_element]['printable'][$key])) {
1750
                    $printable = intval($extrafields->attributes[$object->table_element]['printable'][$key]);
1751
                    if ($printable === 1 || $printable === 2) {
1752
                        $enabled = 1;
1753
                    }
1754
                    // Note : if $printable === 3 or 4 so, it's displayed after line description not in cols
1755
                }
1756
1757
                if (!$enabled) {
1758
                    continue;
1759
                } // don't waste resources if we don't need them...
1760
1761
                // Load language if required
1762
                if (!empty($extrafields->attributes[$object->table_element]['langfile'][$key])) {
1763
                    $outputlangs->load($extrafields->attributes[$object->table_element]['langfile'][$key]);
1764
                }
1765
1766
                // TODO : add more extrafield customisation capacities for PDF like width, rank...
1767
1768
                // set column definition
1769
                $def = array(
1770
                    'rank' => intval($extrafields->attributes[$object->table_element]['pos'][$key]),
1771
                    'width' => 25, // in mm
1772
                    'status' => (bool) $enabled,
1773
                    'title' => array(
1774
                        'label' => $outputlangs->transnoentities($label)
1775
                    ),
1776
                    'content' => array(
1777
                        'align' => 'C'
1778
                    ),
1779
                    'border-left' => true, // add left line separator
1780
                );
1781
1782
                $alignTypeRight = array('double', 'int', 'price');
1783
                if (in_array($extrafields->attributes[$object->table_element]['type'][$key], $alignTypeRight)) {
1784
                    $def['content']['align'] = 'R';
1785
                }
1786
1787
                $alignTypeLeft = array('text', 'html');
1788
                if (in_array($extrafields->attributes[$object->table_element]['type'][$key], $alignTypeLeft)) {
1789
                    $def['content']['align'] = 'L';
1790
                }
1791
1792
1793
                // for extrafields we use rank of extrafield to place it on PDF
1794
                $this->insertNewColumnDef("options_" . $key, $def);
1795
            }
1796
        }
1797
1798
        return 1;
1799
    }
1800
1801
    /**
1802
     *   Define Array Column Field into $this->cols
1803
     *   This method must be implemented by the module that generate the document with its own columns.
1804
     *
1805
     *   @param     Object          $object         Common object
1806
     *   @param     Translate       $outputlangs    Langs
1807
     *   @param     int             $hidedetails    Do not show line details
1808
     *   @param     int             $hidedesc       Do not show desc
1809
     *   @param     int             $hideref        Do not show ref
1810
     *   @return    void
1811
     */
1812
    public function defineColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1813
    {
1814
        // Default field style for content
1815
        $this->defaultContentsFieldsStyle = array(
1816
            'align' => 'R', // R,C,L
1817
            'padding' => array(1, 0.5, 1, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1818
        );
1819
1820
        // Default field style for content
1821
        $this->defaultTitlesFieldsStyle = array(
1822
            'align' => 'C', // R,C,L
1823
            'padding' => array(0.5, 0, 0.5, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1824
        );
1825
1826
        // Example
1827
        /*
1828
        $rank = 0; // do not use negative rank
1829
        $this->cols['desc'] = array(
1830
            'rank' => $rank,
1831
            'width' => false, // only for desc
1832
            'status' => true,
1833
            'title' => array(
1834
                'textkey' => 'Designation', // use lang key is useful in somme case with module
1835
                'align' => 'L',
1836
                // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
1837
                // 'label' => ' ', // the final label
1838
                'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1839
            ),
1840
            'content' => array(
1841
                'align' => 'L',
1842
                'padding' => array(1, 0.5, 1, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1843
            ),
1844
        );
1845
        */
1846
    }
1847
}
1848