Passed
Push — main ( f1540e...02d90d )
by Rafael
45:15
created

pdf_bank()   F

Complexity

Conditions 29
Paths 4608

Size

Total Lines 157
Code Lines 97

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 29
eloc 97
nc 4608
nop 7
dl 0
loc 157
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/* Copyright (C) 2006-2017  Laurent Destailleur     <[email protected]>
4
 * Copyright (C) 2006		Rodolphe Quiedeville	<[email protected]>
5
 * Copyright (C) 2007		Patrick Raguin      	<[email protected]>
6
 * Copyright (C) 2010-2012	Regis Houssin       	<[email protected]>
7
 * Copyright (C) 2010-2017	Juanjo Menent       	<[email protected]>
8
 * Copyright (C) 2012		Christophe Battarel		<[email protected]>
9
 * Copyright (C) 2012       Cédric Salvador         <[email protected]>
10
 * Copyright (C) 2012-2015  Raphaël Doursenaud      <[email protected]>
11
 * Copyright (C) 2014		Cedric GROSS			<[email protected]>
12
 * Copyright (C) 2014		Teddy Andreotti			<[email protected]>
13
 * Copyright (C) 2015-2016  Marcos García           <[email protected]>
14
 * Copyright (C) 2019       Lenin Rivas           	<[email protected]>
15
 * Copyright (C) 2020       Nicolas ZABOURI         <[email protected]>
16
 * Copyright (C) 2021-2022	Anthony Berton       	<[email protected]>
17
 * Copyright (C) 2023       Frédéric France         <[email protected]>
18
 * Copyright (C) 2024		MDW						<[email protected]>
19
 * Copyright (C) 2024       Rafael San José         <[email protected]>
20
 *
21
 * This program is free software; you can redistribute it and/or modify
22
 * it under the terms of the GNU General Public License as published by
23
 * the Free Software Foundation; either version 3 of the License, or
24
 * (at your option) any later version.
25
 *
26
 * This program is distributed in the hope that it will be useful,
27
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29
 * GNU General Public License for more details.
30
 *
31
 * You should have received a copy of the GNU General Public License
32
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
33
 * or see https://www.gnu.org/
34
 */
35
36
/**
37
 *  \file       htdocs/core/lib/pdf.lib.php
38
 *  \brief      Set of functions used for PDF generation
39
 *  \ingroup    core
40
 */
41
42
include_once BASE_PATH . '/../Dolibarr/Lib/Signature.php';
43
44
45
/**
46
 *  Return array head with list of tabs to view object information.
47
 *
48
 *  @return array               head array with tabs
49
 */
50
function pdf_admin_prepare_head()
51
{
52
    global $langs, $conf;
53
54
    $h = 0;
55
    $head = array();
56
57
    $head[$h][0] = DOL_URL_ROOT . '/admin/pdf.php';
58
    $head[$h][1] = $langs->trans("Parameters");
59
    $head[$h][2] = 'general';
60
    $h++;
61
62
    // Show more tabs from modules
63
    // Entries must be declared in modules descriptor with line
64
    // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__');   to add new tab
65
    // $this->tabs = array('entity:-tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__');   to remove a tab
66
    complete_head_from_modules($conf, $langs, null, $head, $h, 'pdf_admin');
67
68
    if (isModEnabled("propal") || isModEnabled('invoice') || isModEnabled('reception')) {
69
        $head[$h][0] = DOL_URL_ROOT . '/admin/pdf_other.php';
70
        $head[$h][1] = $langs->trans("Others");
71
        $head[$h][2] = 'other';
72
        $h++;
73
    }
74
75
    complete_head_from_modules($conf, $langs, null, $head, $h, 'pdf_admin', 'remove');
76
77
    return $head;
78
}
79
80
81
/**
82
 *  Return array with format properties of default PDF format
83
 *
84
 *  @param      Translate|null  $outputlangs        Output lang to use to autodetect output format if we need 'auto' detection
85
 *  @param      string          $mode               'setup' = Use setup, 'auto' = Force autodetection whatever is setup
86
 *  @return     array                               Array('width'=>w,'height'=>h,'unit'=>u);
87
 */
88
function pdf_getFormat(Translate $outputlangs = null, $mode = 'setup')
89
{
90
    global $conf, $db, $langs;
91
92
    dol_syslog("pdf_getFormat Get paper format with mode=" . $mode . " MAIN_PDF_FORMAT=" . (!getDolGlobalString('MAIN_PDF_FORMAT') ? 'null' : $conf->global->MAIN_PDF_FORMAT) . " outputlangs->defaultlang=" . (is_object($outputlangs) ? $outputlangs->defaultlang : 'null') . " and langs->defaultlang=" . (is_object($langs) ? $langs->defaultlang : 'null'));
93
94
    // Default value if setup was not done and/or entry into c_paper_format not defined
95
    $width = 210;
96
    $height = 297;
97
    $unit = 'mm';
98
99
    if ($mode == 'auto' || !getDolGlobalString('MAIN_PDF_FORMAT') || getDolGlobalString('MAIN_PDF_FORMAT') == 'auto') {
100
        include_once BASE_PATH . '/../Dolibarr/Lib/Functions2.php';
101
        $pdfformat = dol_getDefaultFormat($outputlangs);
102
    } else {
103
        $pdfformat = getDolGlobalString('MAIN_PDF_FORMAT');
104
    }
105
106
    $sql = "SELECT code, label, width, height, unit FROM " . MAIN_DB_PREFIX . "c_paper_format";
107
    $sql .= " WHERE code = '" . $db->escape($pdfformat) . "'";
108
    $resql = $db->query($sql);
109
    if ($resql) {
110
        $obj = $db->fetch_object($resql);
111
        if ($obj) {
112
            $width = (int) $obj->width;
113
            $height = (int) $obj->height;
114
            $unit = $obj->unit;
115
        }
116
    }
117
118
    //print "pdfformat=".$pdfformat." width=".$width." height=".$height." unit=".$unit;
119
    return array('width' => $width, 'height' => $height, 'unit' => $unit);
120
}
121
122
/**
123
 *      Return a PDF instance object. We create a FPDI instance that instantiate TCPDF.
124
 *
125
 *      @param  string      $format         Array(width,height). Keep empty to use default setup.
126
 *      @param  string      $metric         Unit of format ('mm')
127
 *      @param  string      $pagetype       'P' or 'l'
128
 *      @return TCPDF                       PDF object
129
 */
130
function pdf_getInstance($format = '', $metric = 'mm', $pagetype = 'P')
131
{
132
    global $conf;
133
134
    // Define constant for TCPDF
135
    if (!defined('K_TCPDF_EXTERNAL_CONFIG')) {
136
        define('K_TCPDF_EXTERNAL_CONFIG', 1); // this avoid using tcpdf_config file
137
        define('K_PATH_CACHE', DOL_DATA_ROOT . '/admin/temp/');
138
        define('K_PATH_URL_CACHE', DOL_DATA_ROOT . '/admin/temp/');
139
        dol_mkdir(K_PATH_CACHE);
140
        define('K_BLANK_IMAGE', '_blank.png');
141
        define('PDF_PAGE_FORMAT', 'A4');
142
        define('PDF_PAGE_ORIENTATION', 'P');
143
        define('PDF_CREATOR', 'TCPDF');
144
        define('PDF_AUTHOR', 'TCPDF');
145
        define('PDF_HEADER_TITLE', 'TCPDF Example');
146
        define('PDF_HEADER_STRING', "by Dolibarr ERP CRM");
147
        define('PDF_UNIT', 'mm');
148
        define('PDF_MARGIN_HEADER', 5);
149
        define('PDF_MARGIN_FOOTER', 10);
150
        define('PDF_MARGIN_TOP', 27);
151
        define('PDF_MARGIN_BOTTOM', 25);
152
        define('PDF_MARGIN_LEFT', 15);
153
        define('PDF_MARGIN_RIGHT', 15);
154
        define('PDF_FONT_NAME_MAIN', 'helvetica');
155
        define('PDF_FONT_SIZE_MAIN', 10);
156
        define('PDF_FONT_NAME_DATA', 'helvetica');
157
        define('PDF_FONT_SIZE_DATA', 8);
158
        define('PDF_FONT_MONOSPACED', 'courier');
159
        define('PDF_IMAGE_SCALE_RATIO', 1.25);
160
        define('HEAD_MAGNIFICATION', 1.1);
161
        define('K_CELL_HEIGHT_RATIO', 1.25);
162
        define('K_TITLE_MAGNIFICATION', 1.3);
163
        define('K_SMALL_RATIO', 2 / 3);
164
        define('K_THAI_TOPCHARS', true);
165
        define('K_TCPDF_CALLS_IN_HTML', true);
166
        if (getDolGlobalString('TCPDF_THROW_ERRORS_INSTEAD_OF_DIE')) {
167
            define('K_TCPDF_THROW_EXCEPTION_ERROR', true);
168
        } else {
169
            define('K_TCPDF_THROW_EXCEPTION_ERROR', false);
170
        }
171
    }
172
173
    // Load TCPDF
174
    // require_once TCPDF_PATH . 'tcpdf.php';
175
176
    // We need to instantiate tcpdi object (instead of tcpdf) to use merging features. But we can disable it (this will break all merge features).
177
//    if (!getDolGlobalString('MAIN_DISABLE_TCPDI')) {
178
//        require_once TCPDI_PATH . 'tcpdi.php';
179
//    }
180
181
    //$arrayformat=pdf_getFormat();
182
    //$format=array($arrayformat['width'],$arrayformat['height']);
183
    //$metric=$arrayformat['unit'];
184
185
    $pdfa = false; // PDF-1.3
186
    if (getDolGlobalString('PDF_USE_A')) {
187
        $pdfa = getDolGlobalString('PDF_USE_A');    // PDF/A-1 ou PDF/A-3
188
    }
189
190
    if (!getDolGlobalString('MAIN_DISABLE_TCPDI') && class_exists('TCPDI')) {
191
        $pdf = new TCPDI($pagetype, $metric, $format, true, 'UTF-8', false, $pdfa);
192
    } else {
193
        $pdf = new TCPDF($pagetype, $metric, $format, true, 'UTF-8', false, $pdfa);
194
    }
195
196
    // Protection and encryption of pdf
197
    if (getDolGlobalString('PDF_SECURITY_ENCRYPTION')) {
198
        /* Permission supported by TCPDF
199
        - print : Print the document;
200
        - modify : Modify the contents of the document by operations other than those controlled by 'fill-forms', 'extract' and 'assemble';
201
        - copy : Copy or otherwise extract text and graphics from the document;
202
        - annot-forms : Add or modify text annotations, fill in interactive form fields, and, if 'modify' is also set, create or modify interactive form fields (including signature fields);
203
        - fill-forms : Fill in existing interactive form fields (including signature fields), even if 'annot-forms' is not specified;
204
        - extract : Extract text and graphics (in support of accessibility to users with disabilities or for other purposes);
205
        - assemble : Assemble the document (insert, rotate, or delete pages and create bookmarks or thumbnail images), even if 'modify' is not set;
206
        - print-high : Print the document to a representation from which a faithful digital copy of the PDF content could be generated. When this is not set, printing is limited to a low-level representation of the appearance, possibly of degraded quality.
207
        - owner : (inverted logic - only for public-key) when set permits change of encryption and enables all other permissions.
208
        */
209
210
        // For TCPDF, we specify permission we want to block
211
        $pdfrights = (getDolGlobalString('PDF_SECURITY_ENCRYPTION_RIGHTS') ? json_decode($conf->global->PDF_SECURITY_ENCRYPTION_RIGHTS, true) : array('modify', 'copy')); // Json format in llx_const
212
213
        // Password for the end user
214
        $pdfuserpass = (getDolGlobalString('PDF_SECURITY_ENCRYPTION_USERPASS') ? $conf->global->PDF_SECURITY_ENCRYPTION_USERPASS : '');
215
216
        // Password of the owner, created randomly if not defined
217
        $pdfownerpass = (getDolGlobalString('PDF_SECURITY_ENCRYPTION_OWNERPASS') ? $conf->global->PDF_SECURITY_ENCRYPTION_OWNERPASS : null);
218
219
        // For encryption strength: 0 = RC4 40 bit; 1 = RC4 128 bit; 2 = AES 128 bit; 3 = AES 256 bit
220
        $encstrength = (getDolGlobalString('PDF_SECURITY_ENCRYPTION_STRENGTH') ? $conf->global->PDF_SECURITY_ENCRYPTION_STRENGTH : 0);
221
222
        // Array of recipients containing public-key certificates ('c') and permissions ('p').
223
        // For example: array(array('c' => 'file://../examples/data/cert/tcpdf.crt', 'p' => array('print')))
224
        $pubkeys = (getDolGlobalString('PDF_SECURITY_ENCRYPTION_PUBKEYS') ? json_decode($conf->global->PDF_SECURITY_ENCRYPTION_PUBKEYS, true) : null); // Json format in llx_const
225
226
        $pdf->SetProtection($pdfrights, $pdfuserpass, $pdfownerpass, $encstrength, $pubkeys);
227
    }
228
229
    return $pdf;
230
}
231
232
/**
233
 * Return if pdf file is protected/encrypted
234
 *
235
 * @param   string      $pathoffile     Path of file
236
 * @return  boolean                     True or false
237
 */
238
function pdf_getEncryption($pathoffile)
239
{
240
    // require_once TCPDF_PATH . 'tcpdf_parser.php';
241
242
    $isencrypted = false;
243
244
    $content = file_get_contents($pathoffile);
245
246
    //ob_start();
247
    @($parser = new TCPDF_PARSER(ltrim($content)));
248
    [$xref, $data] = $parser->getParsedData();
249
    unset($parser);
250
    //ob_end_clean();
251
252
    if (isset($xref['trailer']['encrypt'])) {
253
        $isencrypted = true; // Secured pdf file are currently not supported
254
    }
255
256
    if (empty($data)) {
257
        $isencrypted = true; // Object list not found. Possible secured file
258
    }
259
260
    return $isencrypted;
261
}
262
263
/**
264
 *      Return font name to use for PDF generation
265
 *
266
 *      @param  Translate   $outputlangs    Output langs object
267
 *      @return string                      Name of font to use
268
 */
269
function pdf_getPDFFont($outputlangs)
270
{
271
    global $conf;
272
273
    if (getDolGlobalString('MAIN_PDF_FORCE_FONT')) {
274
        return $conf->global->MAIN_PDF_FORCE_FONT;
275
    }
276
277
    $font = 'Helvetica'; // By default, for FPDI, or ISO language on TCPDF
278
    if (class_exists('TCPDF')) {  // If TCPDF on, we can use an UTF8 one like DejaVuSans if required (slower)
279
        if ($outputlangs->trans('FONTFORPDF') != 'FONTFORPDF') {
280
            $font = $outputlangs->trans('FONTFORPDF');
281
        }
282
    }
283
    return $font;
284
}
285
286
/**
287
 *      Return font size to use for PDF generation
288
 *
289
 *      @param  Translate   $outputlangs     Output langs object
290
 *      @return int                          Size of font to use
291
 */
292
function pdf_getPDFFontSize($outputlangs)
293
{
294
    global $conf;
295
296
    $size = 10; // By default, for FPDI or ISO language on TCPDF
297
    if (class_exists('TCPDF')) {  // If TCPDF on, we can use an UTF8 font like DejaVuSans if required (slower)
298
        if ($outputlangs->trans('FONTSIZEFORPDF') != 'FONTSIZEFORPDF') {
299
            $size = (int) $outputlangs->trans('FONTSIZEFORPDF');
300
        }
301
    }
302
    if (getDolGlobalString('MAIN_PDF_FORCE_FONT_SIZE')) {
303
        $size = getDolGlobalString('MAIN_PDF_FORCE_FONT_SIZE');
304
    }
305
306
    return $size;
307
}
308
309
310
/**
311
 * Return height to use for Logo onto PDF
312
 *
313
 * @param   string      $logo       Full path to logo file to use
314
 * @param   bool        $url        Image with url (true or false)
315
 * @return  int|float
316
 */
317
function pdf_getHeightForLogo($logo, $url = false)
318
{
319
    global $conf;
320
    $height = (!getDolGlobalString('MAIN_DOCUMENTS_LOGO_HEIGHT') ? 20 : $conf->global->MAIN_DOCUMENTS_LOGO_HEIGHT);
321
    $maxwidth = 130;
322
    include_once BASE_PATH . '/../Dolibarr/Lib/Images.php';
323
    $tmp = dol_getImageSize($logo, $url);
324
    if ($tmp['height']) {
325
        $width = round($height * $tmp['width'] / $tmp['height']);
326
        if ($width > $maxwidth) {
327
            $height = $height * $maxwidth / $width;
328
        }
329
    }
330
    //print $tmp['width'].' '.$tmp['height'].' '.$width; exit;
331
    return $height;
332
}
333
334
/**
335
 * Function to try to calculate height of a HTML Content
336
 *
337
 * @param   TCPDF     $pdf              PDF initialized object
338
 * @param   string    $htmlcontent      HTML Content
339
 * @return  int                         Height
340
 * @see getStringHeight()
341
 */
342
function pdfGetHeightForHtmlContent(&$pdf, $htmlcontent)
343
{
344
    // store current object
345
    $pdf->startTransaction();
346
    // store starting values
347
    $start_y = $pdf->GetY();
348
    //var_dump($start_y);
349
    $start_page = $pdf->getPage();
350
    // call printing functions with content
351
    $pdf->writeHTMLCell(0, 0, 0, $start_y, $htmlcontent, 0, 1, false, true, 'J', true);
352
    // get the new Y
353
    $end_y = $pdf->GetY();
354
    $end_page = $pdf->getPage();
355
    // calculate height
356
    $height = 0;
357
    if ($end_page == $start_page) {
358
        $height = $end_y - $start_y;
359
    } else {
360
        for ($page = $start_page; $page <= $end_page; ++$page) {
361
            $pdf->setPage($page);
362
            $tmpm = $pdf->getMargins();
363
            $tMargin = $tmpm['top'];
364
            if ($page == $start_page) {
365
                // first page
366
                $height = $pdf->getPageHeight() - $start_y - $pdf->getBreakMargin();
367
            } elseif ($page == $end_page) {
368
                // last page
369
                $height = $end_y - $tMargin;
370
            } else {
371
                $height = $pdf->getPageHeight() - $tMargin - $pdf->getBreakMargin();
372
            }
373
        }
374
    }
375
    // restore previous object
376
    $pdf = $pdf->rollbackTransaction();
377
378
    return $height;
379
}
380
381
382
/**
383
 * Returns the name of the thirdparty
384
 *
385
 * @param   Societe|Contact     $thirdparty     Contact or thirdparty
386
 * @param   Translate           $outputlangs    Output language
387
 * @param   int                 $includealias   1=Include alias name after name
388
 * @return  string                              String with name of thirdparty (+ alias if requested)
389
 */
390
function pdfBuildThirdpartyName($thirdparty, Translate $outputlangs, $includealias = 0)
391
{
392
    global $conf;
393
394
    // Recipient name
395
    $socname = '';
396
397
    if ($thirdparty instanceof Societe) {
398
        $socname = $thirdparty->name;
399
        if (($includealias || getDolGlobalInt('PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME')) && !empty($thirdparty->name_alias)) {
400
            if (getDolGlobalInt('PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME') == 2) {
401
                $socname = $thirdparty->name_alias . " - " . $thirdparty->name;
402
            } else {
403
                $socname = $thirdparty->name . " - " . $thirdparty->name_alias;
404
            }
405
        }
406
    } elseif ($thirdparty instanceof Contact) {
407
        if ($thirdparty->socid > 0) {
408
            $thirdparty->fetch_thirdparty();
409
            $socname = $thirdparty->thirdparty->name;
410
            if (($includealias || getDolGlobalInt('PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME')) && !empty($thirdparty->thirdparty->name_alias)) {
411
                if (getDolGlobalInt('PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME') == 2) {
412
                    $socname = $thirdparty->thirdparty->name_alias . " - " . $thirdparty->thirdparty->name;
413
                } else {
414
                    $socname = $thirdparty->thirdparty->name . " - " . $thirdparty->thirdparty->name_alias;
415
                }
416
            }
417
        }
418
    } else {
419
        throw new InvalidArgumentException('Parameter 1 $thirdparty is not a Societe nor Contact');
420
    }
421
422
    return $outputlangs->convToOutputCharset($socname);
423
}
424
425
426
/**
427
 *      Return a string with full address formatted for output on documents
428
 *
429
 *      @param  Translate             $outputlangs          Output langs object
430
 *      @param  Societe               $sourcecompany        Source company object
431
 *      @param  Societe|string|null   $targetcompany        Target company object
432
 *      @param  Contact|string|null   $targetcontact        Target contact object
433
 *      @param  int                   $usecontact           Use contact instead of company
434
 *      @param  string                $mode                 Address type ('source', 'target', 'targetwithdetails', 'targetwithdetails_xxx': target but include also phone/fax/email/url)
435
 *      @param  Object|null           $object               Object we want to build document for
436
 *      @return string|int                                  String with full address or -1 if KO
437
 */
438
function pdf_build_address($outputlangs, $sourcecompany, $targetcompany = '', $targetcontact = '', $usecontact = 0, $mode = 'source', $object = null)
439
{
440
    global $conf, $hookmanager;
441
442
    if ($mode == 'source' && !is_object($sourcecompany)) {
443
        return -1;
444
    }
445
    if ($mode == 'target' && !is_object($targetcompany)) {
446
        return -1;
447
    }
448
449
    if (!empty($sourcecompany->state_id) && empty($sourcecompany->state)) {
450
        $sourcecompany->state = getState($sourcecompany->state_id);
451
    }
452
    if (!empty($targetcompany->state_id) && empty($targetcompany->state)) {
453
        $targetcompany->state = getState($targetcompany->state_id);
454
    }
455
456
    $reshook = 0;
457
    $stringaddress = '';
458
    if (is_object($hookmanager)) {
459
        $parameters = array('sourcecompany' => &$sourcecompany, 'targetcompany' => &$targetcompany, 'targetcontact' => &$targetcontact, 'outputlangs' => $outputlangs, 'mode' => $mode, 'usecontact' => $usecontact);
460
        $action = '';
461
        $reshook = $hookmanager->executeHooks('pdf_build_address', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
462
        $stringaddress .= $hookmanager->resPrint;
463
    }
464
    if (empty($reshook)) {
465
        if ($mode == 'source') {
466
            $withCountry = 0;
467
            if (isset($targetcompany->country_code) && !empty($sourcecompany->country_code) && ($targetcompany->country_code != $sourcecompany->country_code)) {
468
                $withCountry = 1;
469
            }
470
471
            $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->convToOutputCharset(dol_format_address($sourcecompany, $withCountry, "\n", $outputlangs)) . "\n";
472
473
            if (!getDolGlobalString('MAIN_PDF_DISABLESOURCEDETAILS')) {
474
                // Phone
475
                if ($sourcecompany->phone) {
476
                    $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("PhoneShort") . ": " . $outputlangs->convToOutputCharset($sourcecompany->phone);
477
                }
478
                // Fax
479
                if ($sourcecompany->fax) {
480
                    $stringaddress .= ($stringaddress ? ($sourcecompany->phone ? " - " : "\n") : '') . $outputlangs->transnoentities("Fax") . ": " . $outputlangs->convToOutputCharset($sourcecompany->fax);
481
                }
482
                // EMail
483
                if ($sourcecompany->email) {
484
                    $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("Email") . ": " . $outputlangs->convToOutputCharset($sourcecompany->email);
485
                }
486
                // Web
487
                if ($sourcecompany->url) {
488
                    $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("Web") . ": " . $outputlangs->convToOutputCharset($sourcecompany->url);
489
                }
490
            }
491
            // Intra VAT
492
            if (getDolGlobalString('MAIN_TVAINTRA_IN_SOURCE_ADDRESS')) {
493
                if ($sourcecompany->tva_intra) {
494
                    $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("VATIntraShort") . ': ' . $outputlangs->convToOutputCharset($sourcecompany->tva_intra);
495
                }
496
            }
497
            // Professional Ids
498
            $reg = array();
499
            if (getDolGlobalString('MAIN_PROFID1_IN_SOURCE_ADDRESS') && !empty($sourcecompany->idprof1)) {
500
                $tmp = $outputlangs->transcountrynoentities("ProfId1", $sourcecompany->country_code);
501
                if (preg_match('/\((.+)\)/', $tmp, $reg)) {
502
                    $tmp = $reg[1];
503
                }
504
                $stringaddress .= ($stringaddress ? "\n" : '') . $tmp . ': ' . $outputlangs->convToOutputCharset($sourcecompany->idprof1);
505
            }
506
            if (getDolGlobalString('MAIN_PROFID2_IN_SOURCE_ADDRESS') && !empty($sourcecompany->idprof2)) {
507
                $tmp = $outputlangs->transcountrynoentities("ProfId2", $sourcecompany->country_code);
508
                if (preg_match('/\((.+)\)/', $tmp, $reg)) {
509
                    $tmp = $reg[1];
510
                }
511
                $stringaddress .= ($stringaddress ? "\n" : '') . $tmp . ': ' . $outputlangs->convToOutputCharset($sourcecompany->idprof2);
512
            }
513
            if (getDolGlobalString('MAIN_PROFID3_IN_SOURCE_ADDRESS') && !empty($sourcecompany->idprof3)) {
514
                $tmp = $outputlangs->transcountrynoentities("ProfId3", $sourcecompany->country_code);
515
                if (preg_match('/\((.+)\)/', $tmp, $reg)) {
516
                    $tmp = $reg[1];
517
                }
518
                $stringaddress .= ($stringaddress ? "\n" : '') . $tmp . ': ' . $outputlangs->convToOutputCharset($sourcecompany->idprof3);
519
            }
520
            if (getDolGlobalString('MAIN_PROFID4_IN_SOURCE_ADDRESS') && !empty($sourcecompany->idprof4)) {
521
                $tmp = $outputlangs->transcountrynoentities("ProfId4", $sourcecompany->country_code);
522
                if (preg_match('/\((.+)\)/', $tmp, $reg)) {
523
                    $tmp = $reg[1];
524
                }
525
                $stringaddress .= ($stringaddress ? "\n" : '') . $tmp . ': ' . $outputlangs->convToOutputCharset($sourcecompany->idprof4);
526
            }
527
            if (getDolGlobalString('MAIN_PROFID5_IN_SOURCE_ADDRESS') && !empty($sourcecompany->idprof5)) {
528
                $tmp = $outputlangs->transcountrynoentities("ProfId5", $sourcecompany->country_code);
529
                if (preg_match('/\((.+)\)/', $tmp, $reg)) {
530
                    $tmp = $reg[1];
531
                }
532
                $stringaddress .= ($stringaddress ? "\n" : '') . $tmp . ': ' . $outputlangs->convToOutputCharset($sourcecompany->idprof5);
533
            }
534
            if (getDolGlobalString('MAIN_PROFID6_IN_SOURCE_ADDRESS') && !empty($sourcecompany->idprof6)) {
535
                $tmp = $outputlangs->transcountrynoentities("ProfId6", $sourcecompany->country_code);
536
                if (preg_match('/\((.+)\)/', $tmp, $reg)) {
537
                    $tmp = $reg[1];
538
                }
539
                $stringaddress .= ($stringaddress ? "\n" : '') . $tmp . ': ' . $outputlangs->convToOutputCharset($sourcecompany->idprof6);
540
            }
541
            if (getDolGlobalString('PDF_ADD_MORE_AFTER_SOURCE_ADDRESS')) {
542
                $stringaddress .= ($stringaddress ? "\n" : '') . getDolGlobalString('PDF_ADD_MORE_AFTER_SOURCE_ADDRESS');
543
            }
544
        }
545
546
        if ($mode == 'target' || preg_match('/targetwithdetails/', $mode)) {
547
            if ($usecontact) {
548
                if (is_object($targetcontact)) {
549
                    $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->convToOutputCharset($targetcontact->getFullName($outputlangs, 1));
550
551
                    if (!empty($targetcontact->address)) {
552
                        $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->convToOutputCharset(dol_format_address($targetcontact)) . "\n";
553
                    } else {
554
                        $companytouseforaddress = $targetcompany;
555
556
                        // Contact on a thirdparty that is a different thirdparty than the thirdparty of object
557
                        if ($targetcontact->socid > 0 && $targetcontact->socid != $targetcompany->id) {
558
                            $targetcontact->fetch_thirdparty();
559
                            $companytouseforaddress = $targetcontact->thirdparty;
560
                        }
561
562
                        $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->convToOutputCharset(dol_format_address($companytouseforaddress)) . "\n";
563
                    }
564
                    // Country
565
                    if (!empty($targetcontact->country_code) && $targetcontact->country_code != $sourcecompany->country_code) {
566
                        $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country" . $targetcontact->country_code));
567
                    } elseif (empty($targetcontact->country_code) && !empty($targetcompany->country_code) && ($targetcompany->country_code != $sourcecompany->country_code)) {
568
                        $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country" . $targetcompany->country_code));
569
                    }
570
571
                    if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || preg_match('/targetwithdetails/', $mode)) {
572
                        // Phone
573
                        if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_phone/', $mode)) {
574
                            if (!empty($targetcontact->phone_pro) || !empty($targetcontact->phone_mobile)) {
575
                                $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("Phone") . ": ";
576
                            }
577
                            if (!empty($targetcontact->phone_pro)) {
578
                                $stringaddress .= $outputlangs->convToOutputCharset($targetcontact->phone_pro);
579
                            }
580
                            if (!empty($targetcontact->phone_pro) && !empty($targetcontact->phone_mobile)) {
581
                                $stringaddress .= " / ";
582
                            }
583
                            if (!empty($targetcontact->phone_mobile)) {
584
                                $stringaddress .= $outputlangs->convToOutputCharset($targetcontact->phone_mobile);
585
                            }
586
                        }
587
                        // Fax
588
                        if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_fax/', $mode)) {
589
                            if ($targetcontact->fax) {
590
                                $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("Fax") . ": " . $outputlangs->convToOutputCharset($targetcontact->fax);
591
                            }
592
                        }
593
                        // EMail
594
                        if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_email/', $mode)) {
595
                            if ($targetcontact->email) {
596
                                $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("Email") . ": " . $outputlangs->convToOutputCharset($targetcontact->email);
597
                            }
598
                        }
599
                        // Web
600
                        if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_url/', $mode)) {
601
                            if ($targetcontact->url) {
602
                                $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("Web") . ": " . $outputlangs->convToOutputCharset($targetcontact->url);
603
                            }
604
                        }
605
                    }
606
                }
607
            } else {
608
                if (is_object($targetcompany)) {
609
                    $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->convToOutputCharset(dol_format_address($targetcompany));
610
                    // Country
611
                    if (!empty($targetcompany->country_code) && $targetcompany->country_code != $sourcecompany->country_code) {
612
                        $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country" . $targetcompany->country_code));
613
                    } else {
614
                        $stringaddress .= ($stringaddress ? "\n" : '');
615
                    }
616
617
                    if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || preg_match('/targetwithdetails/', $mode)) {
618
                        // Phone
619
                        if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_phone/', $mode)) {
620
                            if (!empty($targetcompany->phone)) {
621
                                $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("Phone") . ": ";
622
                            }
623
                            if (!empty($targetcompany->phone)) {
624
                                $stringaddress .= $outputlangs->convToOutputCharset($targetcompany->phone);
625
                            }
626
                        }
627
                        // Fax
628
                        if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_fax/', $mode)) {
629
                            if ($targetcompany->fax) {
630
                                $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("Fax") . ": " . $outputlangs->convToOutputCharset($targetcompany->fax);
631
                            }
632
                        }
633
                        // EMail
634
                        if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_email/', $mode)) {
635
                            if ($targetcompany->email) {
636
                                $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("Email") . ": " . $outputlangs->convToOutputCharset($targetcompany->email);
637
                            }
638
                        }
639
                        // Web
640
                        if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_url/', $mode)) {
641
                            if ($targetcompany->url) {
642
                                $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("Web") . ": " . $outputlangs->convToOutputCharset($targetcompany->url);
643
                            }
644
                        }
645
                    }
646
                }
647
            }
648
649
            // Intra VAT
650
            if (!getDolGlobalString('MAIN_TVAINTRA_NOT_IN_ADDRESS')) {
651
                if ($usecontact && is_object($targetcontact) && getDolGlobalInt('MAIN_USE_COMPANY_NAME_OF_CONTACT')) {
652
                    $targetcontact->fetch_thirdparty();
653
                    if (!empty($targetcontact->thirdparty->id) && $targetcontact->thirdparty->tva_intra) {
654
                        $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("VATIntraShort") . ': ' . $outputlangs->convToOutputCharset($targetcontact->thirdparty->tva_intra);
655
                    }
656
                } elseif ($targetcompany->tva_intra) {
657
                    $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("VATIntraShort") . ': ' . $outputlangs->convToOutputCharset($targetcompany->tva_intra);
658
                }
659
            }
660
661
            // Professional Ids
662
            if (getDolGlobalString('MAIN_PROFID1_IN_ADDRESS') && !empty($targetcompany->idprof1)) {
663
                $tmp = $outputlangs->transcountrynoentities("ProfId1", $targetcompany->country_code);
664
                if (preg_match('/\((.+)\)/', $tmp, $reg)) {
665
                    $tmp = $reg[1];
666
                }
667
                $stringaddress .= ($stringaddress ? "\n" : '') . $tmp . ': ' . $outputlangs->convToOutputCharset($targetcompany->idprof1);
668
            }
669
            if (getDolGlobalString('MAIN_PROFID2_IN_ADDRESS') && !empty($targetcompany->idprof2)) {
670
                $tmp = $outputlangs->transcountrynoentities("ProfId2", $targetcompany->country_code);
671
                if (preg_match('/\((.+)\)/', $tmp, $reg)) {
672
                    $tmp = $reg[1];
673
                }
674
                $stringaddress .= ($stringaddress ? "\n" : '') . $tmp . ': ' . $outputlangs->convToOutputCharset($targetcompany->idprof2);
675
            }
676
            if (getDolGlobalString('MAIN_PROFID3_IN_ADDRESS') && !empty($targetcompany->idprof3)) {
677
                $tmp = $outputlangs->transcountrynoentities("ProfId3", $targetcompany->country_code);
678
                if (preg_match('/\((.+)\)/', $tmp, $reg)) {
679
                    $tmp = $reg[1];
680
                }
681
                $stringaddress .= ($stringaddress ? "\n" : '') . $tmp . ': ' . $outputlangs->convToOutputCharset($targetcompany->idprof3);
682
            }
683
            if (getDolGlobalString('MAIN_PROFID4_IN_ADDRESS') && !empty($targetcompany->idprof4)) {
684
                $tmp = $outputlangs->transcountrynoentities("ProfId4", $targetcompany->country_code);
685
                if (preg_match('/\((.+)\)/', $tmp, $reg)) {
686
                    $tmp = $reg[1];
687
                }
688
                $stringaddress .= ($stringaddress ? "\n" : '') . $tmp . ': ' . $outputlangs->convToOutputCharset($targetcompany->idprof4);
689
            }
690
            if (getDolGlobalString('MAIN_PROFID5_IN_ADDRESS') && !empty($targetcompany->idprof5)) {
691
                $tmp = $outputlangs->transcountrynoentities("ProfId5", $targetcompany->country_code);
692
                if (preg_match('/\((.+)\)/', $tmp, $reg)) {
693
                    $tmp = $reg[1];
694
                }
695
                $stringaddress .= ($stringaddress ? "\n" : '') . $tmp . ': ' . $outputlangs->convToOutputCharset($targetcompany->idprof5);
696
            }
697
            if (getDolGlobalString('MAIN_PROFID6_IN_ADDRESS') && !empty($targetcompany->idprof6)) {
698
                $tmp = $outputlangs->transcountrynoentities("ProfId6", $targetcompany->country_code);
699
                if (preg_match('/\((.+)\)/', $tmp, $reg)) {
700
                    $tmp = $reg[1];
701
                }
702
                $stringaddress .= ($stringaddress ? "\n" : '') . $tmp . ': ' . $outputlangs->convToOutputCharset($targetcompany->idprof6);
703
            }
704
705
            // Public note
706
            if (getDolGlobalString('MAIN_PUBLIC_NOTE_IN_ADDRESS')) {
707
                if ($mode == 'source' && !empty($sourcecompany->note_public)) {
708
                    $stringaddress .= ($stringaddress ? "\n" : '') . dol_string_nohtmltag($sourcecompany->note_public);
709
                }
710
                if (($mode == 'target' || preg_match('/targetwithdetails/', $mode)) && !empty($targetcompany->note_public)) {
711
                    $stringaddress .= ($stringaddress ? "\n" : '') . dol_string_nohtmltag($targetcompany->note_public);
712
                }
713
            }
714
        }
715
    }
716
717
    return $stringaddress;
718
}
719
720
721
/**
722
 *      Show header of page for PDF generation
723
 *
724
 *      @param      TCPDF       $pdf            Object PDF
725
 *      @param      Translate   $outputlangs    Object lang for output
726
 *      @param      int         $page_height    Height of page
727
 *      @return void
728
 */
729
function pdf_pagehead(&$pdf, $outputlangs, $page_height)
730
{
731
    global $conf;
732
733
    // Add a background image on document only if good setup of const
734
    if (getDolGlobalString('MAIN_USE_BACKGROUND_ON_PDF') && (getDolGlobalString('MAIN_USE_BACKGROUND_ON_PDF') != '-1')) {       // Warning, this option make TCPDF generation being crazy and some content disappeared behind the image
735
        $filepath = $conf->mycompany->dir_output . '/logos/' . getDolGlobalString('MAIN_USE_BACKGROUND_ON_PDF');
736
        if (file_exists($filepath)) {
737
            $pdf->SetAutoPageBreak(0, 0); // Disable auto pagebreak before adding image
738
            if (getDolGlobalString('MAIN_USE_BACKGROUND_ON_PDF_ALPHA')) {
739
                $pdf->SetAlpha($conf->global->MAIN_USE_BACKGROUND_ON_PDF_ALPHA);
740
            } // Option for change opacity of background
741
            $pdf->Image($filepath, (isset($conf->global->MAIN_USE_BACKGROUND_ON_PDF_X) ? $conf->global->MAIN_USE_BACKGROUND_ON_PDF_X : 0), (isset($conf->global->MAIN_USE_BACKGROUND_ON_PDF_Y) ? $conf->global->MAIN_USE_BACKGROUND_ON_PDF_Y : 0), 0, $page_height);
742
            if (getDolGlobalString('MAIN_USE_BACKGROUND_ON_PDF_ALPHA')) {
743
                $pdf->SetAlpha(1);
744
            }
745
            $pdf->SetPageMark(); // This option avoid to have the images missing on some pages
746
            $pdf->SetAutoPageBreak(1, 0); // Restore pagebreak
747
        }
748
    }
749
    if (getDolGlobalString('MAIN_ADD_PDF_BACKGROUND') && getDolGlobalString('MAIN_ADD_PDF_BACKGROUND') != '-1') {
750
        $pdf->SetPageMark(); // This option avoid to have the images missing on some pages
751
    }
752
}
753
754
755
/**
756
 *  Return array of possible substitutions for PDF content (without external module substitutions).
757
 *
758
 *  @param  Translate       $outputlangs    Output language
759
 *  @param  array|null      $exclude        Array of family keys we want to exclude. For example array('mycompany', 'object', 'date', 'user', ...)
760
 *  @param  Object|null     $object         Object
761
 *  @param  int             $onlykey        1=Do not calculate some heavy values of keys (performance enhancement when we need only the keys), 2=Values are truncated and html sanitized (to use for help tooltip)
762
 *  @param  array|null      $include        Array of family keys we want to include. For example array('system', 'mycompany', 'object', 'objectamount', 'date', 'user', ...)
763
 *  @return array                       Array of substitutions
764
 */
765
function pdf_getSubstitutionArray($outputlangs, $exclude = null, $object = null, $onlykey = 0, $include = null)
766
{
767
    $substitutionarray = getCommonSubstitutionArray($outputlangs, $onlykey, $exclude, $object, $include);
768
    $substitutionarray['__FROM_NAME__'] = '__FROM_NAME__';
769
    $substitutionarray['__FROM_EMAIL__'] = '__FROM_EMAIL__';
770
    return $substitutionarray;
771
}
772
773
774
/**
775
 *      Add a draft watermark on PDF files
776
 *
777
 *      @param  TCPDF       $pdf            Object PDF
778
 *      @param  Translate   $outputlangs    Object lang
779
 *      @param  int         $h              Height of PDF
780
 *      @param  int         $w              Width of PDF
781
 *      @param  string      $unit           Unit of height (mm, pt, ...)
782
 *      @param  string      $text           Text to show
783
 *      @return void
784
 */
785
function pdf_watermark(&$pdf, $outputlangs, $h, $w, $unit, $text)
786
{
787
    // Print Draft Watermark
788
    if ($unit == 'pt') {
789
        $k = 1;
790
    } elseif ($unit == 'mm') {
791
        $k = 72 / 25.4;
792
    } elseif ($unit == 'cm') {
793
        $k = 72 / 2.54;
794
    } elseif ($unit == 'in') {
795
        $k = 72;
796
    }
797
798
    // Make substitution
799
    $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, null);
800
    complete_substitutions_array($substitutionarray, $outputlangs, null);
801
    $text = make_substitutions($text, $substitutionarray, $outputlangs);
802
    $text = $outputlangs->convToOutputCharset($text);
803
804
    $savx = $pdf->getX();
805
    $savy = $pdf->getY();
806
807
    $watermark_angle = atan($h / $w) / 2;
808
    $watermark_x_pos = 0;
809
    $watermark_y_pos = $h / 3;
810
    $watermark_x = $w / 2;
811
    $watermark_y = $h / 3;
812
    $pdf->SetFont('', 'B', 40);
813
    $pdf->SetTextColor(255, 192, 203);
814
815
    //rotate
816
    $pdf->_out(sprintf('q %.5F %.5F %.5F %.5F %.2F %.2F cm 1 0 0 1 %.2F %.2F cm', cos($watermark_angle), sin($watermark_angle), -sin($watermark_angle), cos($watermark_angle), $watermark_x * $k, ($h - $watermark_y) * $k, -$watermark_x * $k, -($h - $watermark_y) * $k));
817
    //print watermark
818
    $pdf->SetXY($watermark_x_pos, $watermark_y_pos);
819
    $pdf->Cell($w - 20, 25, $outputlangs->convToOutputCharset($text), "", 2, "C", 0);
820
    //antirotate
821
    $pdf->_out('Q');
822
823
    $pdf->SetXY($savx, $savy);
824
}
825
826
827
/**
828
 *  Show bank information for PDF generation
829
 *
830
 *  @param  TCPDF           $pdf                    Object PDF
831
 *  @param  Translate   $outputlangs            Object lang
832
 *  @param  int         $curx                   X
833
 *  @param  int         $cury                   Y
834
 *  @param  Account     $account                Bank account object
835
 *  @param  int         $onlynumber             Output only number (bank+desk+key+number according to country, but without name of bank and address)
836
 *  @param  int         $default_font_size      Default font size
837
 *  @return float                               The Y PDF position
838
 */
839
function pdf_bank(&$pdf, $outputlangs, $curx, $cury, $account, $onlynumber = 0, $default_font_size = 10)
840
{
841
    global $mysoc, $conf;
842
843
844
    $diffsizetitle = (!getDolGlobalString('PDF_DIFFSIZE_TITLE') ? 3 : $conf->global->PDF_DIFFSIZE_TITLE);
845
    $diffsizecontent = (!getDolGlobalString('PDF_DIFFSIZE_CONTENT') ? 4 : $conf->global->PDF_DIFFSIZE_CONTENT);
846
    $pdf->SetXY($curx, $cury);
847
848
    if (empty($onlynumber)) {
849
        $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
850
        $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByTransferOnThisBankAccount') . ':', 0, 'L', 0);
851
        $cury += 4;
852
    }
853
854
    $outputlangs->load("banks");
855
856
    // Use correct name of bank id according to country
857
    $bickey = "BICNumber";
858
    if ($account->getCountryCode() == 'IN') {
859
        $bickey = "SWIFT";
860
    }
861
862
    // Get format of bank account according to its country
863
    $usedetailedbban = $account->useDetailedBBAN();
864
865
    //$onlynumber=0; $usedetailedbban=1; // For tests
866
    if ($usedetailedbban) {
867
        $savcurx = $curx;
868
869
        if (empty($onlynumber)) {
870
            $pdf->SetFont('', '', $default_font_size - $diffsizecontent);
871
            $pdf->SetXY($curx, $cury);
872
            $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Bank") . ': ' . $outputlangs->convToOutputCharset($account->bank), 0, 'L', 0);
873
            $cury += 3;
874
        }
875
876
        if (!getDolGlobalString('PDF_BANK_HIDE_NUMBER_SHOW_ONLY_BICIBAN')) {    // Note that some countries still need bank number, BIC/IBAN not enough for them
877
            // Note:
878
            // bank = code_banque (FR), sort code (GB, IR. Example: 12-34-56)
879
            // desk = code guichet (FR), used only when $usedetailedbban = 1
880
            // number = account number
881
            // key = check control key used only when $usedetailedbban = 1
882
            if (empty($onlynumber)) {
883
                $pdf->line($curx + 1, $cury + 1, $curx + 1, $cury + 6);
884
            }
885
886
887
            foreach ($account->getFieldsToShow() as $val) {
888
                $pdf->SetXY($curx, $cury + 4);
889
                $pdf->SetFont('', '', $default_font_size - 3);
890
891
                if ($val == 'BankCode') {
892
                    // Bank code
893
                    $tmplength = 18;
894
                    $content = $account->code_banque;
895
                } elseif ($val == 'DeskCode') {
896
                    // Desk
897
                    $tmplength = 18;
898
                    $content = $account->code_guichet;
899
                } elseif ($val == 'BankAccountNumber') {
900
                    // Number
901
                    $tmplength = 24;
902
                    $content = $account->number;
903
                } elseif ($val == 'BankAccountNumberKey') {
904
                    // Key
905
                    $tmplength = 15;
906
                    $content = $account->cle_rib;
907
                } elseif ($val == 'IBAN' || $val == 'BIC') {
908
                    // Key
909
                    $tmplength = 0;
910
                    $content = '';
911
                } else {
912
                    dol_print_error($account->db, 'Unexpected value for getFieldsToShow: ' . $val);
913
                    break;
914
                }
915
916
                $pdf->MultiCell($tmplength, 3, $outputlangs->convToOutputCharset($content), 0, 'C', 0);
917
                $pdf->SetXY($curx, $cury + 1);
918
                $curx += $tmplength;
919
                $pdf->SetFont('', 'B', $default_font_size - $diffsizecontent);
920
                $pdf->MultiCell($tmplength, 3, $outputlangs->transnoentities($val), 0, 'C', 0);
921
                if (empty($onlynumber)) {
922
                    $pdf->line($curx, $cury + 1, $curx, $cury + 7);
923
                }
924
            }
925
926
            $curx = $savcurx;
927
            $cury += 8;
928
        }
929
    } else {
930
        $pdf->SetFont('', 'B', $default_font_size - $diffsizecontent);
931
        $pdf->SetXY($curx, $cury);
932
        $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Bank") . ': ' . $outputlangs->convToOutputCharset($account->bank), 0, 'L', 0);
933
        $cury += 3;
934
935
        $pdf->SetFont('', 'B', $default_font_size - $diffsizecontent);
936
        $pdf->SetXY($curx, $cury);
937
        $pdf->MultiCell(100, 3, $outputlangs->transnoentities("BankAccountNumber") . ': ' . $outputlangs->convToOutputCharset($account->number), 0, 'L', 0);
938
        $cury += 3;
939
940
        if ($diffsizecontent <= 2) {
941
            $cury += 1;
942
        }
943
    }
944
945
    $pdf->SetFont('', '', $default_font_size - $diffsizecontent);
946
947
    if (empty($onlynumber) && (!empty($account->domiciliation) || !empty($account->address))) {
948
        $pdf->SetXY($curx, $cury);
949
        $val = $outputlangs->transnoentities("Residence") . ': ' . $outputlangs->convToOutputCharset(empty($account->address) ? $account->domiciliation : $account->address);
950
        $pdf->MultiCell(100, 3, $val, 0, 'L', 0);
951
        //$nboflines=dol_nboflines_bis($val,120);
952
        //$cury+=($nboflines*3)+2;
953
        $tmpy = $pdf->getStringHeight(100, $val);
954
        $cury += $tmpy;
955
    }
956
957
    if (!empty($account->proprio)) {
958
        $pdf->SetXY($curx, $cury);
959
        $val = $outputlangs->transnoentities("BankAccountOwner") . ': ' . $outputlangs->convToOutputCharset($account->proprio);
960
        $pdf->MultiCell(100, 3, $val, 0, 'L', 0);
961
        $tmpy = $pdf->getStringHeight(100, $val);
962
        $cury += $tmpy;
963
    } elseif (!$usedetailedbban) {
964
        $cury += 1;
965
    }
966
967
    // Use correct name of bank id according to country
968
    $ibankey = FormBank::getIBANLabel($account);
969
970
    if (!empty($account->iban)) {
971
        //Remove whitespaces to ensure we are dealing with the format we expect
972
        $ibanDisplay_temp = str_replace(' ', '', $outputlangs->convToOutputCharset($account->iban));
973
        $ibanDisplay = "";
974
975
        $nbIbanDisplay_temp = dol_strlen($ibanDisplay_temp);
976
        for ($i = 0; $i < $nbIbanDisplay_temp; $i++) {
977
            $ibanDisplay .= $ibanDisplay_temp[$i];
978
            if ($i % 4 == 3 && $i > 0) {
979
                $ibanDisplay .= " ";
980
            }
981
        }
982
983
        $pdf->SetFont('', 'B', $default_font_size - 3);
984
        $pdf->SetXY($curx, $cury);
985
        $pdf->MultiCell(100, 3, $outputlangs->transnoentities($ibankey) . ': ' . $ibanDisplay, 0, 'L', 0);
986
        $cury += 3;
987
    }
988
989
    if (!empty($account->bic)) {
990
        $pdf->SetFont('', 'B', $default_font_size - 3);
991
        $pdf->SetXY($curx, $cury);
992
        $pdf->MultiCell(100, 3, $outputlangs->transnoentities($bickey) . ': ' . $outputlangs->convToOutputCharset($account->bic), 0, 'L', 0);
993
    }
994
995
    return $pdf->getY();
996
}
997
998
/**
999
 *  Show footer of page for PDF generation
1000
 *
1001
 *  @param  TCPDF       $pdf            The PDF factory
1002
 *  @param  Translate   $outputlangs    Object lang for output
1003
 *  @param  string      $paramfreetext  Constant name of free text
1004
 *  @param  Societe     $fromcompany    Object company
1005
 *  @param  int         $marge_basse    Margin bottom we use for the autobreak
1006
 *  @param  int         $marge_gauche   Margin left (no more used)
1007
 *  @param  int         $page_hauteur   Page height
1008
 *  @param  Object      $object         Object shown in PDF
1009
 *  @param  int         $showdetails    Show company address details into footer (0=Nothing, 1=Show address, 2=Show managers, 3=Both)
1010
 *  @param  int         $hidefreetext   1=Hide free text, 0=Show free text
1011
 *  @param  int         $page_largeur   Page width
1012
 *  @param  string      $watermark      Watermark text to print on page
1013
 *  @return int                         Return height of bottom margin including footer text
1014
 */
1015
function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_basse, $marge_gauche, $page_hauteur, $object, $showdetails = 0, $hidefreetext = 0, $page_largeur = 0, $watermark = '')
1016
{
1017
    global $conf, $hookmanager;
1018
1019
    $outputlangs->load("dict");
1020
    $line = '';
1021
    $reg = array();
1022
1023
    $dims = $pdf->getPageDimensions();
1024
1025
    // Line of free text
1026
    if (empty($hidefreetext) && !empty($conf->global->$paramfreetext)) {
1027
        $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
1028
        // More substitution keys
1029
        $substitutionarray['__FROM_NAME__'] = $fromcompany->name;
1030
        $substitutionarray['__FROM_EMAIL__'] = $fromcompany->email;
1031
        complete_substitutions_array($substitutionarray, $outputlangs, $object);
1032
        $newfreetext = make_substitutions(getDolGlobalString($paramfreetext), $substitutionarray, $outputlangs);
1033
1034
        // Make a change into HTML code to allow to include images from medias directory.
1035
        // <img alt="" src="/dolibarr_dev/htdocs/viewimage.php?modulepart=medias&amp;entity=1&amp;file=image/ldestailleur_166x166.jpg" style="height:166px; width:166px" />
1036
        // become
1037
        // <img alt="" src="'.DOL_DATA_ROOT.'/medias/image/ldestailleur_166x166.jpg" style="height:166px; width:166px" />
1038
        $newfreetext = preg_replace('/(<img.*src=")[^\"]*viewimage\.php[^\"]*modulepart=medias[^\"]*file=([^\"]*)("[^\/]*\/>)/', '\1file:/' . DOL_DATA_ROOT . '/medias/\2\3', $newfreetext);
1039
1040
        $line .= $outputlangs->convToOutputCharset($newfreetext);
1041
    }
1042
1043
    // First line of company infos
1044
    $line1 = "";
1045
    $line2 = "";
1046
    $line3 = "";
1047
    $line4 = "";
1048
1049
    if ($showdetails == 1 || $showdetails == 3) {
1050
        // Company name
1051
        if ($fromcompany->name) {
1052
            $line1 .= ($line1 ? " - " : "") . $outputlangs->transnoentities("RegisteredOffice") . ": " . $fromcompany->name;
1053
        }
1054
        // Address
1055
        if ($fromcompany->address) {
1056
            $line1 .= ($line1 ? " - " : "") . str_replace("\n", ", ", $fromcompany->address);
1057
        }
1058
        // Zip code
1059
        if ($fromcompany->zip) {
1060
            $line1 .= ($line1 ? " - " : "") . $fromcompany->zip;
1061
        }
1062
        // Town
1063
        if ($fromcompany->town) {
1064
            $line1 .= ($line1 ? " " : "") . $fromcompany->town;
1065
        }
1066
        // Country
1067
        if ($fromcompany->country) {
1068
            $line1 .= ($line1 ? ", " : "") . $fromcompany->country;
1069
        }
1070
        // Phone
1071
        if ($fromcompany->phone) {
1072
            $line2 .= ($line2 ? " - " : "") . $outputlangs->transnoentities("Phone") . ": " . $fromcompany->phone;
1073
        }
1074
        // Fax
1075
        if ($fromcompany->fax) {
1076
            $line2 .= ($line2 ? " - " : "") . $outputlangs->transnoentities("Fax") . ": " . $fromcompany->fax;
1077
        }
1078
1079
        // URL
1080
        if ($fromcompany->url) {
1081
            $line2 .= ($line2 ? " - " : "") . $fromcompany->url;
1082
        }
1083
        // Email
1084
        if ($fromcompany->email) {
1085
            $line2 .= ($line2 ? " - " : "") . $fromcompany->email;
1086
        }
1087
    }
1088
    if ($showdetails == 2 || $showdetails == 3 || (!empty($fromcompany->country_code) && $fromcompany->country_code == 'DE')) {
1089
        // Managers
1090
        if ($fromcompany->managers) {
1091
            $line2 .= ($line2 ? " - " : "") . $fromcompany->managers;
1092
        }
1093
    }
1094
1095
    // Line 3 of company infos
1096
    // Juridical status
1097
    if (!empty($fromcompany->forme_juridique_code) && $fromcompany->forme_juridique_code) {
1098
        $line3 .= ($line3 ? " - " : "") . $outputlangs->convToOutputCharset(getFormeJuridiqueLabel($fromcompany->forme_juridique_code));
1099
    }
1100
    // Capital
1101
    if (!empty($fromcompany->capital)) {
1102
        $tmpamounttoshow = price2num($fromcompany->capital); // This field is a free string or a float
1103
        if (is_numeric($tmpamounttoshow) && $tmpamounttoshow > 0) {
1104
            $line3 .= ($line3 ? " - " : "") . $outputlangs->transnoentities("CapitalOf", price($tmpamounttoshow, 0, $outputlangs, 0, 0, 0, $conf->currency));
1105
        } elseif (!empty($fromcompany->capital)) {
1106
            $line3 .= ($line3 ? " - " : "") . $outputlangs->transnoentities("CapitalOf", $fromcompany->capital, $outputlangs);
1107
        }
1108
    }
1109
    // Prof Id 1
1110
    if (!empty($fromcompany->idprof1) && $fromcompany->idprof1 && ($fromcompany->country_code != 'FR' || !$fromcompany->idprof2)) {
1111
        $field = $outputlangs->transcountrynoentities("ProfId1", $fromcompany->country_code);
1112
        if (preg_match('/\((.*)\)/i', $field, $reg)) {
1113
            $field = $reg[1];
1114
        }
1115
        $line3 .= ($line3 ? " - " : "") . $field . ": " . $outputlangs->convToOutputCharset($fromcompany->idprof1);
1116
    }
1117
    // Prof Id 2
1118
    if (!empty($fromcompany->idprof2) && $fromcompany->idprof2) {
1119
        $field = $outputlangs->transcountrynoentities("ProfId2", $fromcompany->country_code);
1120
        if (preg_match('/\((.*)\)/i', $field, $reg)) {
1121
            $field = $reg[1];
1122
        }
1123
        $line3 .= ($line3 ? " - " : "") . $field . ": " . $outputlangs->convToOutputCharset($fromcompany->idprof2);
1124
    }
1125
1126
    // Line 4 of company infos
1127
    // Prof Id 3
1128
    if (!empty($fromcompany->idprof3) && $fromcompany->idprof3) {
1129
        $field = $outputlangs->transcountrynoentities("ProfId3", $fromcompany->country_code);
1130
        if (preg_match('/\((.*)\)/i', $field, $reg)) {
1131
            $field = $reg[1];
1132
        }
1133
        $line4 .= ($line4 ? " - " : "") . $field . ": " . $outputlangs->convToOutputCharset($fromcompany->idprof3);
1134
    }
1135
    // Prof Id 4
1136
    if (!empty($fromcompany->idprof4) && $fromcompany->idprof4) {
1137
        $field = $outputlangs->transcountrynoentities("ProfId4", $fromcompany->country_code);
1138
        if (preg_match('/\((.*)\)/i', $field, $reg)) {
1139
            $field = $reg[1];
1140
        }
1141
        $line4 .= ($line4 ? " - " : "") . $field . ": " . $outputlangs->convToOutputCharset($fromcompany->idprof4);
1142
    }
1143
    // Prof Id 5
1144
    if (!empty($fromcompany->idprof5) && $fromcompany->idprof5) {
1145
        $field = $outputlangs->transcountrynoentities("ProfId5", $fromcompany->country_code);
1146
        if (preg_match('/\((.*)\)/i', $field, $reg)) {
1147
            $field = $reg[1];
1148
        }
1149
        $line4 .= ($line4 ? " - " : "") . $field . ": " . $outputlangs->convToOutputCharset($fromcompany->idprof5);
1150
    }
1151
    // Prof Id 6
1152
    if (!empty($fromcompany->idprof6) &&  $fromcompany->idprof6) {
1153
        $field = $outputlangs->transcountrynoentities("ProfId6", $fromcompany->country_code);
1154
        if (preg_match('/\((.*)\)/i', $field, $reg)) {
1155
            $field = $reg[1];
1156
        }
1157
        $line4 .= ($line4 ? " - " : "") . $field . ": " . $outputlangs->convToOutputCharset($fromcompany->idprof6);
1158
    }
1159
    // Prof Id 7
1160
    if (!empty($fromcompany->idprof7) &&  $fromcompany->idprof7) {
1161
        $field = $outputlangs->transcountrynoentities("ProfId7", $fromcompany->country_code);
1162
        if (preg_match('/\((.*)\)/i', $field, $reg)) {
1163
            $field = $reg[1];
1164
        }
1165
        $line4 .= ($line4 ? " - " : "") . $field . ": " . $outputlangs->convToOutputCharset($fromcompany->idprof7);
1166
    }
1167
    // Prof Id 8
1168
    if (!empty($fromcompany->idprof8) &&  $fromcompany->idprof8) {
1169
        $field = $outputlangs->transcountrynoentities("ProfId8", $fromcompany->country_code);
1170
        if (preg_match('/\((.*)\)/i', $field, $reg)) {
1171
            $field = $reg[1];
1172
        }
1173
        $line4 .= ($line4 ? " - " : "") . $field . ": " . $outputlangs->convToOutputCharset($fromcompany->idprof8);
1174
    }
1175
    // Prof Id 9
1176
    if (!empty($fromcompany->idprof9) &&  $fromcompany->idprof9) {
1177
        $field = $outputlangs->transcountrynoentities("ProfId9", $fromcompany->country_code);
1178
        if (preg_match('/\((.*)\)/i', $field, $reg)) {
1179
            $field = $reg[1];
1180
        }
1181
        $line4 .= ($line4 ? " - " : "") . $field . ": " . $outputlangs->convToOutputCharset($fromcompany->idprof9);
1182
    }
1183
    // Prof Id 10
1184
    if (!empty($fromcompany->idprof10) &&  $fromcompany->idprof10) {
1185
        $field = $outputlangs->transcountrynoentities("ProfId10", $fromcompany->country_code);
1186
        if (preg_match('/\((.*)\)/i', $field, $reg)) {
1187
            $field = $reg[1];
1188
        }
1189
        $line4 .= ($line4 ? " - " : "") . $field . ": " . $outputlangs->convToOutputCharset($fromcompany->idprof10);
1190
    }
1191
    // IntraCommunautary VAT
1192
    if (!empty($fromcompany->tva_intra)  && $fromcompany->tva_intra != '') {
1193
        $line4 .= ($line4 ? " - " : "") . $outputlangs->transnoentities("VATIntraShort") . ": " . $outputlangs->convToOutputCharset($fromcompany->tva_intra);
1194
    }
1195
1196
    $pdf->SetFont('', '', 7);
1197
    $pdf->SetDrawColor(224, 224, 224);
1198
    // Option for footer text color
1199
    if (getDolGlobalString('PDF_FOOTER_TEXT_COLOR')) {
1200
        [$r, $g, $b] = sscanf($conf->global->PDF_FOOTER_TEXT_COLOR, '%d, %d, %d');
1201
        $pdf->SetTextColor($r, $g, $b);
1202
    }
1203
1204
    // The start of the bottom of this page footer is positioned according to # of lines
1205
    $freetextheight = 0;
1206
    if ($line) {    // Free text
1207
        //$line="sample text<br>\nfd<strong>sf</strong>sdf<br>\nghfghg<br>";
1208
        if (!getDolGlobalString('PDF_ALLOW_HTML_FOR_FREE_TEXT')) {
1209
            $width = 20000;
1210
            $align = 'L'; // By default, ask a manual break: We use a large value 20000, to not have automatic wrap. This make user understand, he need to add CR on its text.
1211
            if (getDolGlobalString('MAIN_USE_AUTOWRAP_ON_FREETEXT')) {
1212
                $width = 200;
1213
                $align = 'C';
1214
            }
1215
            $freetextheight = $pdf->getStringHeight($width, $line);
1216
        } else {
1217
            $freetextheight = pdfGetHeightForHtmlContent($pdf, dol_htmlentitiesbr($line, 1, 'UTF-8', 0)); // New method (works for HTML content)
1218
            //print '<br>'.$freetextheight;exit;
1219
        }
1220
    }
1221
1222
    // For customize footer
1223
    if (is_object($hookmanager)) {
1224
        $parameters = array('line1' => $line1, 'line2' => $line2, 'line3' => $line3, 'line4' => $line4, 'outputlangs' => $outputlangs);
1225
        $action = '';
1226
        $hookmanager->executeHooks('pdf_pagefoot', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
1227
        if (!empty($hookmanager->resPrint) && $hidefreetext == 0) {
1228
            $mycustomfooter = $hookmanager->resPrint;
1229
            $mycustomfooterheight = pdfGetHeightForHtmlContent($pdf, dol_htmlentitiesbr($mycustomfooter, 1, 'UTF-8', 0));
1230
1231
            $marginwithfooter = $marge_basse + $freetextheight + $mycustomfooterheight;
1232
            $posy = (float) $marginwithfooter;
1233
1234
            // Option for footer background color (without freetext zone)
1235
            if (getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR')) {
1236
                [$r, $g, $b] = sscanf($conf->global->PDF_FOOTER_BACKGROUND_COLOR, '%d, %d, %d');
1237
                $pdf->SetAutoPageBreak(0, 0); // Disable auto pagebreak
1238
                $pdf->Rect(0, $dims['hk'] - $posy + $freetextheight, $dims['wk'] + 1, $marginwithfooter + 1, 'F', '', $fill_color = array($r, $g, $b));
1239
                $pdf->SetAutoPageBreak(1, 0); // Restore pagebreak
1240
            }
1241
1242
            if (getDolGlobalInt('PDF_FREETEXT_DISABLE_PAGEBREAK') === 1) {
1243
                $pdf->SetAutoPageBreak(0, 0);
1244
            } // Option for disable auto pagebreak
1245
            if ($line) {    // Free text
1246
                $pdf->SetXY($dims['lm'], -$posy);
1247
                if (!getDolGlobalString('PDF_ALLOW_HTML_FOR_FREE_TEXT')) {   // by default
1248
                    $pdf->MultiCell(0, 3, $line, 0, $align, 0);
1249
                } else {
1250
                    $pdf->writeHTMLCell($dims['wk'] - $dims['lm'] - $dims['rm'], $freetextheight, $dims['lm'], $dims['hk'] - $marginwithfooter, dol_htmlentitiesbr($line, 1, 'UTF-8', 0));
1251
                }
1252
                $posy -= $freetextheight;
1253
            }
1254
            if (getDolGlobalInt('PDF_FREETEXT_DISABLE_PAGEBREAK') === 1) {
1255
                $pdf->SetAutoPageBreak(1, 0);
1256
            } // Restore pagebreak
1257
1258
            $pdf->SetY(-$posy);
1259
1260
            // Hide footer line if footer background color is set
1261
            if (!getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR')) {
1262
                $pdf->line($dims['lm'], $dims['hk'] - $posy, $dims['wk'] - $dims['rm'], $dims['hk'] - $posy);
1263
            }
1264
1265
            // Option for set top margin height of footer after freetext
1266
            if (getDolGlobalString('PDF_FOOTER_TOP_MARGIN') || getDolGlobalInt('PDF_FOOTER_TOP_MARGIN') === 0) {
1267
                $posy -= (float) getDolGlobalString('PDF_FOOTER_TOP_MARGIN');
1268
            } else {
1269
                $posy--;
1270
            }
1271
1272
            if (getDolGlobalInt('PDF_FOOTER_DISABLE_PAGEBREAK') === 1) {
1273
                $pdf->SetAutoPageBreak(0, 0);
1274
            } // Option for disable auto pagebreak
1275
            $pdf->writeHTMLCell($dims['wk'] - $dims['lm'] - $dims['rm'], $mycustomfooterheight, $dims['lm'], $dims['hk'] - $posy, dol_htmlentitiesbr($mycustomfooter, 1, 'UTF-8', 0));
1276
            if (getDolGlobalInt('PDF_FOOTER_DISABLE_PAGEBREAK') === 1) {
1277
                $pdf->SetAutoPageBreak(1, 0);
1278
            } // Restore pagebreak
1279
1280
            $posy -= $mycustomfooterheight - 3;
1281
        } else {
1282
            // Else default footer
1283
            $marginwithfooter = $marge_basse + $freetextheight + (!empty($line1) ? 3 : 0) + (!empty($line2) ? 3 : 0) + (!empty($line3) ? 3 : 0) + (!empty($line4) ? 3 : 0);
1284
            $posy = (float) $marginwithfooter;
1285
1286
            // Option for footer background color (without freetext zone)
1287
            if (getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR')) {
1288
                [$r, $g, $b] = sscanf($conf->global->PDF_FOOTER_BACKGROUND_COLOR, '%d, %d, %d');
1289
                $pdf->SetAutoPageBreak(0, 0); // Disable auto pagebreak
1290
                $pdf->Rect(0, $dims['hk'] - $posy + $freetextheight, $dims['wk'] + 1, $marginwithfooter + 1, 'F', '', $fill_color = array($r, $g, $b));
1291
                $pdf->SetAutoPageBreak(1, 0); // Restore pagebreak
1292
            }
1293
1294
            if (getDolGlobalInt('PDF_FREETEXT_DISABLE_PAGEBREAK') === 1) {
1295
                $pdf->SetAutoPageBreak(0, 0);
1296
            } // Option for disable auto pagebreak
1297
            if ($line) {    // Free text
1298
                $pdf->SetXY($dims['lm'], -$posy);
1299
                if (!getDolGlobalString('PDF_ALLOW_HTML_FOR_FREE_TEXT')) {   // by default
1300
                    $pdf->MultiCell(0, 3, $line, 0, $align, 0);
1301
                } else {
1302
                    $pdf->writeHTMLCell($dims['wk'] - $dims['lm'] - $dims['rm'], $freetextheight, $dims['lm'], $dims['hk'] - $marginwithfooter, dol_htmlentitiesbr($line, 1, 'UTF-8', 0));
1303
                }
1304
                $posy -= $freetextheight;
1305
            }
1306
            if (getDolGlobalInt('PDF_FREETEXT_DISABLE_PAGEBREAK') === 1) {
1307
                $pdf->SetAutoPageBreak(1, 0);
1308
            } // Restore pagebreak
1309
1310
            $pdf->SetY(-$posy);
1311
1312
            // Option for hide all footer (page number will no hidden)
1313
            if (!getDolGlobalInt('PDF_FOOTER_HIDDEN')) {
1314
                // Hide footer line if footer background color is set
1315
                if (!getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR')) {
1316
                    $pdf->line($dims['lm'], $dims['hk'] - $posy, $dims['wk'] - $dims['rm'], $dims['hk'] - $posy);
1317
                }
1318
1319
                // Option for set top margin height of footer after freetext
1320
                if (getDolGlobalString('PDF_FOOTER_TOP_MARGIN') || getDolGlobalInt('PDF_FOOTER_TOP_MARGIN') === 0) {
1321
                    $posy -= (float) getDolGlobalString('PDF_FOOTER_TOP_MARGIN');
1322
                } else {
1323
                    $posy--;
1324
                }
1325
1326
                if (!empty($line1)) {
1327
                    $pdf->SetFont('', 'B', 7);
1328
                    $pdf->SetXY($dims['lm'], -$posy);
1329
                    $pdf->MultiCell($dims['wk'] - $dims['rm'] - $dims['lm'], 2, $line1, 0, 'C', 0);
1330
                    $posy -= 3;
1331
                    $pdf->SetFont('', '', 7);
1332
                }
1333
1334
                if (!empty($line2)) {
1335
                    $pdf->SetFont('', 'B', 7);
1336
                    $pdf->SetXY($dims['lm'], -$posy);
1337
                    $pdf->MultiCell($dims['wk'] - $dims['rm'] - $dims['lm'], 2, $line2, 0, 'C', 0);
1338
                    $posy -= 3;
1339
                    $pdf->SetFont('', '', 7);
1340
                }
1341
1342
                if (!empty($line3)) {
1343
                    $pdf->SetXY($dims['lm'], -$posy);
1344
                    $pdf->MultiCell($dims['wk'] - $dims['rm'] - $dims['lm'], 2, $line3, 0, 'C', 0);
1345
                }
1346
1347
                if (!empty($line4)) {
1348
                    $posy -= 3;
1349
                    $pdf->SetXY($dims['lm'], -$posy);
1350
                    $pdf->MultiCell($dims['wk'] - $dims['rm'] - $dims['lm'], 2, $line4, 0, 'C', 0);
1351
                }
1352
            }
1353
        }
1354
    }
1355
    // Show page nb only on iso languages (so default Helvetica font)
1356
    $pdf->SetXY($dims['wk'] - $dims['rm'] - 18 - getDolGlobalInt('PDF_FOOTER_PAGE_NUMBER_X', 0), -$posy - getDolGlobalInt('PDF_FOOTER_PAGE_NUMBER_Y', 0));
1357
1358
    if (getDolGlobalString('PDF_USE_GETALIASNBPAGE_FOR_TOTAL')) {
1359
        // $pagination = $pdf->getAliasNumPage().' / '.$pdf->getAliasNbPages();     // works with $pdf->Cell
1360
        $pagination = $pdf->PageNo() . ' / ' . $pdf->getAliasNbPages(); // seems to not works with all fonts like ru_UK
1361
    } else {
1362
        $pagination = $pdf->PageNo() . ' / ' . $pdf->getNumPages();     // seems to always work even with $pdf->Cell. But some users has reported wrong nb (no way to reproduce)
1363
    }
1364
1365
    $pdf->MultiCell(18, 2, $pagination, 0, 'R', 0);
1366
1367
    //  Show Draft Watermark
1368
    if (!empty($watermark)) {
1369
        pdf_watermark($pdf, $outputlangs, $page_hauteur, $page_largeur, 'mm', $watermark);
1370
    }
1371
1372
    return $marginwithfooter;
1373
}
1374
1375
/**
1376
 *  Show linked objects for PDF generation
1377
 *
1378
 *  @param  TCPDF           $pdf                Object PDF
1379
 *  @param  object      $object             Object
1380
 *  @param  Translate   $outputlangs        Object lang
1381
 *  @param  int         $posx               X
1382
 *  @param  int         $posy               Y
1383
 *  @param  float       $w                  Width of cells. If 0, they extend up to the right margin of the page.
1384
 *  @param  float       $h                  Cell minimum height. The cell extends automatically if needed.
1385
 *  @param  int         $align              Align
1386
 *  @param  string      $default_font_size  Font size
1387
 *  @return float                           The Y PDF position
1388
 */
1389
function pdf_writeLinkedObjects(&$pdf, $object, $outputlangs, $posx, $posy, $w, $h, $align, $default_font_size)
1390
{
1391
    $linkedobjects = pdf_getLinkedObjects($object, $outputlangs);
1392
    if (!empty($linkedobjects)) {
1393
        foreach ($linkedobjects as $linkedobject) {
1394
            $reftoshow = $linkedobject["ref_title"] . ' : ' . $linkedobject["ref_value"];
1395
            if (!empty($linkedobject["date_value"])) {
1396
                $reftoshow .= ' / ' . $linkedobject["date_value"];
1397
            }
1398
1399
            $posy += 3;
1400
            $pdf->SetXY($posx, $posy);
1401
            $pdf->SetFont('', '', $default_font_size - 2);
1402
            $pdf->MultiCell($w, $h, $reftoshow, '', $align);
1403
        }
1404
    }
1405
1406
    return $pdf->getY();
1407
}
1408
1409
/**
1410
 *  Output line description into PDF
1411
 *
1412
 *  @param  TCPDF           $pdf                PDF object
1413
 *  @param  Object          $object             Object
1414
 *  @param  int             $i                  Current line number
1415
 *  @param  Translate       $outputlangs        Object lang for output
1416
 *  @param  int             $w                  Width
1417
 *  @param  int             $h                  Height
1418
 *  @param  int             $posx               Pos x
1419
 *  @param  int             $posy               Pos y
1420
 *  @param  int             $hideref            Hide reference
1421
 *  @param  int             $hidedesc           Hide description
1422
 *  @param  int             $issupplierline     Is it a line for a supplier object ?
1423
 *  @param  string          $align              text alignment ('L', 'C', 'R', 'J' (default))
1424
 *  @return string
1425
 */
1426
function pdf_writelinedesc(&$pdf, $object, $i, $outputlangs, $w, $h, $posx, $posy, $hideref = 0, $hidedesc = 0, $issupplierline = 0, $align = 'J')
1427
{
1428
    global $db, $conf, $langs, $hookmanager;
1429
1430
    $reshook = 0;
1431
    $result = '';
1432
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
1433
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1434
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
1435
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
1436
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1437
        }
1438
        $parameters = array('pdf' => $pdf, 'i' => $i, 'outputlangs' => $outputlangs, 'w' => $w, 'h' => $h, 'posx' => $posx, 'posy' => $posy, 'hideref' => $hideref, 'hidedesc' => $hidedesc, 'issupplierline' => $issupplierline, 'special_code' => $special_code);
1439
        $action = '';
1440
        $reshook = $hookmanager->executeHooks('pdf_writelinedesc', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
1441
1442
        if (!empty($hookmanager->resPrint)) {
1443
            $result .= $hookmanager->resPrint;
1444
        }
1445
    }
1446
    if (empty($reshook)) {
1447
        $labelproductservice = pdf_getlinedesc($object, $i, $outputlangs, $hideref, $hidedesc, $issupplierline);
1448
        $labelproductservice = preg_replace('/(<img[^>]*src=")[^\"]*viewimage\.php[^\"]*modulepart=medias[^\"]*file=([^\"]*)/', '\1file:/' . DOL_DATA_ROOT . '/medias/\2\3', $labelproductservice, -1, $nbrep);
1449
1450
        //var_dump($labelproductservice);exit;
1451
1452
        // Fix bug of some HTML editors that replace links <img src="http://localhostgit/viewimage.php?modulepart=medias&file=image/efd.png" into <img src="http://localhostgit/viewimage.php?modulepart=medias&amp;file=image/efd.png"
1453
        // We make the reverse, so PDF generation has the real URL.
1454
        $nbrep = 0;
1455
        $labelproductservice = preg_replace('/(<img[^>]*src=")([^"]*)(&amp;)([^"]*")/', '\1\2&\4', $labelproductservice, -1, $nbrep);
1456
1457
        //var_dump($labelproductservice);exit;
1458
1459
        // Description
1460
        $pdf->writeHTMLCell($w, $h, $posx, $posy, $outputlangs->convToOutputCharset($labelproductservice), 0, 1, false, true, $align, true);
1461
        $result .= $labelproductservice;
1462
    }
1463
    return $result;
1464
}
1465
1466
/**
1467
 *  Return line description translated in outputlangs and encoded into htmlentities and with <br>
1468
 *
1469
 *  @param  Object      $object              Object
1470
 *  @param  int         $i                   Current line number (0 = first line, 1 = second line, ...)
1471
 *  @param  Translate   $outputlangs         Object langs for output
1472
 *  @param  int         $hideref             Hide reference
1473
 *  @param  int         $hidedesc            Hide description
1474
 *  @param  int         $issupplierline      Is it a line for a supplier object ?
1475
 *  @return string                           String with line
1476
 */
1477
function pdf_getlinedesc($object, $i, $outputlangs, $hideref = 0, $hidedesc = 0, $issupplierline = 0)
1478
{
1479
    global $db, $conf, $langs;
1480
1481
    $idprod = (!empty($object->lines[$i]->fk_product) ? $object->lines[$i]->fk_product : false);
1482
    $label = (!empty($object->lines[$i]->label) ? $object->lines[$i]->label : (!empty($object->lines[$i]->product_label) ? $object->lines[$i]->product_label : ''));
1483
    $product_barcode = (!empty($object->lines[$i]->product_barcode) ? $object->lines[$i]->product_barcode : "");
1484
    $desc = (!empty($object->lines[$i]->desc) ? $object->lines[$i]->desc : (!empty($object->lines[$i]->description) ? $object->lines[$i]->description : ''));
1485
    $ref_supplier = (!empty($object->lines[$i]->ref_supplier) ? $object->lines[$i]->ref_supplier : (!empty($object->lines[$i]->ref_fourn) ? $object->lines[$i]->ref_fourn : '')); // TODO Not yet saved for supplier invoices, only supplier orders
1486
    $note = (!empty($object->lines[$i]->note) ? $object->lines[$i]->note : '');
1487
    $dbatch = (!empty($object->lines[$i]->detail_batch) ? $object->lines[$i]->detail_batch : false);
1488
1489
    if ($issupplierline) {
1490
        include_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php';
1491
        $prodser = new ProductFournisseur($db);
1492
    } else {
1493
        $prodser = new Product($db);
1494
1495
        if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
1496
            include_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php';
1497
        }
1498
    }
1499
1500
    if ($idprod) {
1501
        $prodser->fetch($idprod);
1502
        // If a predefined product and multilang and on other lang, we renamed label with label translated
1503
        if (getDolGlobalInt('MAIN_MULTILANGS') && ($outputlangs->defaultlang != $langs->defaultlang)) {
1504
            $translatealsoifmodified = (getDolGlobalString('MAIN_MULTILANG_TRANSLATE_EVEN_IF_MODIFIED')); // By default if value was modified manually, we keep it (no translation because we don't have it)
1505
1506
            // TODO Instead of making a compare to see if param was modified, check that content contains reference translation. If yes, add the added part to the new translation
1507
            // ($textwasnotmodified is replaced with $textwasmodifiedorcompleted and we add completion).
1508
1509
            // Set label
1510
            // If we want another language, and if label is same than default language (we did not force it to a specific value), we can use translation.
1511
            //var_dump($outputlangs->defaultlang.' - '.$langs->defaultlang.' - '.$label.' - '.$prodser->label);exit;
1512
            $textwasnotmodified = ($label == $prodser->label);
1513
            if (!empty($prodser->multilangs[$outputlangs->defaultlang]["label"]) && ($textwasnotmodified || $translatealsoifmodified)) {
1514
                $label = $prodser->multilangs[$outputlangs->defaultlang]["label"];
1515
            }
1516
1517
            // Set desc
1518
            // Manage HTML entities description test because $prodser->description is store with htmlentities but $desc no
1519
            $textwasnotmodified = false;
1520
            if (!empty($desc) && dol_textishtml($desc) && !empty($prodser->description) && dol_textishtml($prodser->description)) {
1521
                $textwasnotmodified = (strpos(dol_html_entity_decode($desc, ENT_QUOTES | ENT_HTML5), dol_html_entity_decode($prodser->description, ENT_QUOTES | ENT_HTML5)) !== false);
1522
            } else {
1523
                $textwasnotmodified = ($desc == $prodser->description);
1524
            }
1525
            if (!empty($prodser->multilangs[$outputlangs->defaultlang]["description"])) {
1526
                if ($textwasnotmodified) {
1527
                    $desc = str_replace($prodser->description, $prodser->multilangs[$outputlangs->defaultlang]["description"], $desc);
1528
                } elseif ($translatealsoifmodified) {
1529
                    $desc = $prodser->multilangs[$outputlangs->defaultlang]["description"];
1530
                }
1531
            }
1532
1533
            // Set note
1534
            $textwasnotmodified = ($note == $prodser->note_public);
1535
            if (!empty($prodser->multilangs[$outputlangs->defaultlang]["other"]) && ($textwasnotmodified || $translatealsoifmodified)) {
1536
                $note = $prodser->multilangs[$outputlangs->defaultlang]["other"];
1537
            }
1538
        }
1539
    } elseif (($object->element == 'facture' || $object->element == 'facturefourn') && preg_match('/^\(DEPOSIT\).+/', $desc)) { // We must not replace '(DEPOSIT)' when it is alone, it will be translated and detailed later
1540
        $desc = str_replace('(DEPOSIT)', $outputlangs->trans('Deposit'), $desc);
1541
    }
1542
1543
    if (!getDolGlobalString('PDF_HIDE_PRODUCT_LABEL_IN_SUPPLIER_LINES')) {
1544
        // Description short of product line
1545
        $libelleproduitservice = $label;
1546
        if (!empty($libelleproduitservice) && getDolGlobalString('PDF_BOLD_PRODUCT_LABEL')) {
1547
            // Adding <b> may convert the original string into a HTML string. So we have to first
1548
            // convert \n into <br> we text is not already HTML.
1549
            if (!dol_textishtml($libelleproduitservice)) {
1550
                $libelleproduitservice = str_replace("\n", '<br>', $libelleproduitservice);
1551
            }
1552
            $libelleproduitservice = '<b>' . $libelleproduitservice . '</b>';
1553
        }
1554
    }
1555
1556
1557
    // Add ref of subproducts
1558
    if (getDolGlobalString('SHOW_SUBPRODUCT_REF_IN_PDF')) {
1559
        $prodser->get_sousproduits_arbo();
1560
        if (!empty($prodser->sousprods) && is_array($prodser->sousprods) && count($prodser->sousprods)) {
1561
            $outputlangs->load('mrp');
1562
            $tmparrayofsubproducts = reset($prodser->sousprods);
1563
1564
            $qtyText = null;
1565
            if (isset($object->lines[$i]->qty) && !empty($object->lines[$i]->qty)) {
1566
                $qtyText = $object->lines[$i]->qty;
1567
            } elseif (isset($object->lines[$i]->qty_shipped) && !empty($object->lines[$i]->qty_shipped)) {
1568
                $qtyText = $object->lines[$i]->qty;
1569
            }
1570
1571
            if (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF')) {
1572
                foreach ($tmparrayofsubproducts as $subprodval) {
1573
                    $libelleproduitservice = dol_concatdesc(
1574
                        dol_concatdesc($libelleproduitservice, " * " . $subprodval[3]),
1575
                        (!empty($qtyText) ?
1576
                            $outputlangs->trans('Qty') . ':' . $qtyText . ' x ' . $outputlangs->trans('AssociatedProducts') . ':' . $subprodval[1] . '= ' . $outputlangs->trans('QtyTot') . ':' . $subprodval[1] * $qtyText :
1577
                            $outputlangs->trans('Qty') . ' ' . $outputlangs->trans('AssociatedProducts') . ':' . $subprodval[1])
1578
                    );
1579
                }
1580
            } else {
1581
                foreach ($tmparrayofsubproducts as $subprodval) {
1582
                    $libelleproduitservice = dol_concatdesc(
1583
                        dol_concatdesc($libelleproduitservice, " * " . $subprodval[5] . (($subprodval[5] && $subprodval[3]) ? ' - ' : '') . $subprodval[3]),
1584
                        (!empty($qtyText) ?
1585
                            $outputlangs->trans('Qty') . ':' . $qtyText . ' x ' . $outputlangs->trans('AssociatedProducts') . ':' . $subprodval[1] . '= ' . $outputlangs->trans('QtyTot') . ':' . $subprodval[1] * $qtyText :
1586
                            $outputlangs->trans('Qty') . ' ' . $outputlangs->trans('AssociatedProducts') . ':' . $subprodval[1])
1587
                    );
1588
                }
1589
            }
1590
        }
1591
    }
1592
1593
    if (isModEnabled('barcode') && getDolGlobalString('MAIN_GENERATE_DOCUMENTS_SHOW_PRODUCT_BARCODE') && !empty($product_barcode)) {
1594
        $libelleproduitservice = dol_concatdesc($libelleproduitservice, $outputlangs->trans("BarCode") . " " . $product_barcode);
1595
    }
1596
1597
    // Description long of product line
1598
    if (!empty($desc) && ($desc != $label)) {
1599
        if ($desc == '(CREDIT_NOTE)' && $object->lines[$i]->fk_remise_except) {
1600
            $discount = new DiscountAbsolute($db);
1601
            $discount->fetch($object->lines[$i]->fk_remise_except);
1602
            $sourceref = !empty($discount->discount_type) ? $discount->ref_invoice_supplier_source : $discount->ref_facture_source;
1603
            $libelleproduitservice = $outputlangs->transnoentitiesnoconv("DiscountFromCreditNote", $sourceref);
1604
        } elseif ($desc == '(DEPOSIT)' && $object->lines[$i]->fk_remise_except) {
1605
            $discount = new DiscountAbsolute($db);
1606
            $discount->fetch($object->lines[$i]->fk_remise_except);
1607
            $sourceref = !empty($discount->discount_type) ? $discount->ref_invoice_supplier_source : $discount->ref_facture_source;
1608
            $libelleproduitservice = $outputlangs->transnoentitiesnoconv("DiscountFromDeposit", $sourceref);
1609
            // Add date of deposit
1610
            if (getDolGlobalString('INVOICE_ADD_DEPOSIT_DATE')) {
1611
                $libelleproduitservice .= ' (' . dol_print_date($discount->datec, 'day', '', $outputlangs) . ')';
1612
            }
1613
        } elseif ($desc == '(EXCESS RECEIVED)' && $object->lines[$i]->fk_remise_except) {
1614
            $discount = new DiscountAbsolute($db);
1615
            $discount->fetch($object->lines[$i]->fk_remise_except);
1616
            $libelleproduitservice = $outputlangs->transnoentitiesnoconv("DiscountFromExcessReceived", $discount->ref_facture_source);
1617
        } elseif ($desc == '(EXCESS PAID)' && $object->lines[$i]->fk_remise_except) {
1618
            $discount = new DiscountAbsolute($db);
1619
            $discount->fetch($object->lines[$i]->fk_remise_except);
1620
            $libelleproduitservice = $outputlangs->transnoentitiesnoconv("DiscountFromExcessPaid", $discount->ref_invoice_supplier_source);
1621
        } else {
1622
            if ($idprod) {
1623
                // Check if description must be output
1624
                if (!empty($object->element)) {
1625
                    $tmpkey = 'MAIN_DOCUMENTS_HIDE_DESCRIPTION_FOR_' . strtoupper($object->element);
1626
                    if (!empty($conf->global->$tmpkey)) {
1627
                        $hidedesc = 1;
1628
                    }
1629
                }
1630
                if (empty($hidedesc)) {
1631
                    if (getDolGlobalString('MAIN_DOCUMENTS_DESCRIPTION_FIRST')) {
1632
                        $libelleproduitservice = dol_concatdesc($desc, $libelleproduitservice);
1633
                    } else {
1634
                        if (getDolGlobalString('HIDE_LABEL_VARIANT_PDF') && $prodser->isVariant()) {
1635
                            $libelleproduitservice = $desc;
1636
                        } else {
1637
                            $libelleproduitservice = dol_concatdesc($libelleproduitservice, $desc);
1638
                        }
1639
                    }
1640
                }
1641
            } else {
1642
                $libelleproduitservice = dol_concatdesc($libelleproduitservice, $desc);
1643
            }
1644
        }
1645
    }
1646
1647
    // We add ref of product (and supplier ref if defined)
1648
    $prefix_prodserv = "";
1649
    $ref_prodserv = "";
1650
    if (getDolGlobalString('PRODUCT_ADD_TYPE_IN_DOCUMENTS')) {   // In standard mode, we do not show this
1651
        if ($prodser->isService()) {
1652
            $prefix_prodserv = $outputlangs->transnoentitiesnoconv("Service") . " ";
1653
        } else {
1654
            $prefix_prodserv = $outputlangs->transnoentitiesnoconv("Product") . " ";
1655
        }
1656
    }
1657
1658
    if (empty($hideref)) {
1659
        if ($issupplierline) {
1660
            if (!getDolGlobalString('PDF_HIDE_PRODUCT_REF_IN_SUPPLIER_LINES')) {  // Common case
1661
                $ref_prodserv = $prodser->ref; // Show local ref
1662
                if ($ref_supplier) {
1663
                    $ref_prodserv .= ($prodser->ref ? ' (' : '') . $outputlangs->transnoentitiesnoconv("SupplierRef") . ' ' . $ref_supplier . ($prodser->ref ? ')' : '');
1664
                }
1665
            } elseif (getDolGlobalInt('PDF_HIDE_PRODUCT_REF_IN_SUPPLIER_LINES') == 1) {
1666
                $ref_prodserv = $ref_supplier;
1667
            } elseif (getDolGlobalInt('PDF_HIDE_PRODUCT_REF_IN_SUPPLIER_LINES') == 2) {
1668
                $ref_prodserv = $ref_supplier . ' (' . $outputlangs->transnoentitiesnoconv("InternalRef") . ' ' . $prodser->ref . ')';
1669
            }
1670
        } else {
1671
            $ref_prodserv = $prodser->ref; // Show local ref only
1672
1673
            if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
1674
                $productCustomerPriceStatic = new ProductCustomerPrice($db);
1675
                $filter = array('fk_product' => $idprod, 'fk_soc' => $object->socid);
1676
1677
                $nbCustomerPrices = $productCustomerPriceStatic->fetchAll('', '', 1, 0, $filter);
1678
1679
                if ($nbCustomerPrices > 0) {
1680
                    $productCustomerPrice = $productCustomerPriceStatic->lines[0];
1681
1682
                    if (!empty($productCustomerPrice->ref_customer)) {
1683
                        switch ($conf->global->PRODUIT_CUSTOMER_PRICES_PDF_REF_MODE) {
1684
                            case 1:
1685
                                $ref_prodserv = $productCustomerPrice->ref_customer;
1686
                                break;
1687
1688
                            case 2:
1689
                                $ref_prodserv = $productCustomerPrice->ref_customer . ' (' . $outputlangs->transnoentitiesnoconv('InternalRef') . ' ' . $ref_prodserv . ')';
1690
                                break;
1691
1692
                            default:
1693
                                $ref_prodserv = $ref_prodserv . ' (' . $outputlangs->transnoentitiesnoconv('RefCustomer') . ' ' . $productCustomerPrice->ref_customer . ')';
1694
                        }
1695
                    }
1696
                }
1697
            }
1698
        }
1699
1700
        if (!empty($libelleproduitservice) && !empty($ref_prodserv)) {
1701
            $ref_prodserv .= " - ";
1702
        }
1703
    }
1704
1705
    if (!empty($ref_prodserv) && getDolGlobalString('PDF_BOLD_PRODUCT_REF_AND_PERIOD')) {
1706
        if (!dol_textishtml($libelleproduitservice)) {
1707
            $libelleproduitservice = str_replace("\n", '<br>', $libelleproduitservice);
1708
        }
1709
        $ref_prodserv = '<b>' . $ref_prodserv . '</b>';
1710
        // $prefix_prodserv and $ref_prodser are not HTML var
1711
    }
1712
    $libelleproduitservice = $prefix_prodserv . $ref_prodserv . $libelleproduitservice;
1713
1714
    // Add an additional description for the category products
1715
    if (getDolGlobalString('CATEGORY_ADD_DESC_INTO_DOC') && $idprod && isModEnabled('category')) {
1716
        $categstatic = new Categorie($db);
1717
        // recovering the list of all the categories linked to product
1718
        $tblcateg = $categstatic->containing($idprod, Categorie::TYPE_PRODUCT);
1719
        foreach ($tblcateg as $cate) {
1720
            // Adding the descriptions if they are filled
1721
            $desccateg = $cate->description;
1722
            if ($desccateg) {
1723
                $libelleproduitservice = dol_concatdesc($libelleproduitservice, $desccateg);
1724
            }
1725
        }
1726
    }
1727
1728
    if (!empty($object->lines[$i]->date_start) || !empty($object->lines[$i]->date_end)) {
1729
        $format = 'day';
1730
        $period = '';
1731
        // Show duration if exists
1732
        if ($object->lines[$i]->date_start && $object->lines[$i]->date_end) {
1733
            $period = '(' . $outputlangs->transnoentitiesnoconv('DateFromTo', dol_print_date($object->lines[$i]->date_start, $format, false, $outputlangs), dol_print_date($object->lines[$i]->date_end, $format, false, $outputlangs)) . ')';
1734
        }
1735
        if ($object->lines[$i]->date_start && !$object->lines[$i]->date_end) {
1736
            $period = '(' . $outputlangs->transnoentitiesnoconv('DateFrom', dol_print_date($object->lines[$i]->date_start, $format, false, $outputlangs)) . ')';
1737
        }
1738
        if (!$object->lines[$i]->date_start && $object->lines[$i]->date_end) {
1739
            $period = '(' . $outputlangs->transnoentitiesnoconv('DateUntil', dol_print_date($object->lines[$i]->date_end, $format, false, $outputlangs)) . ')';
1740
        }
1741
        //print '>'.$outputlangs->charset_output.','.$period;
1742
        if (getDolGlobalString('PDF_BOLD_PRODUCT_REF_AND_PERIOD')) {
1743
            if (!dol_textishtml($libelleproduitservice)) {
1744
                $libelleproduitservice = str_replace("\n", '<br>', $libelleproduitservice);
1745
            }
1746
            $libelleproduitservice .= '<br><b style="color:#333666;" ><em>' . $period . '</em></b>';
1747
        } else {
1748
            $libelleproduitservice = dol_concatdesc($libelleproduitservice, $period);
1749
        }
1750
        //print $libelleproduitservice;
1751
    }
1752
1753
    // Show information for lot
1754
    if (!empty($dbatch)) {
1755
        // $object is a shipment.
1756
        //var_dump($object->lines[$i]->details_entrepot);       // array from llx_expeditiondet (we can have several lines for one fk_origin_line)
1757
        //var_dump($object->lines[$i]->detail_batch);           // array from llx_expeditiondet_batch (each line with a lot is linked to llx_expeditiondet)
1758
1759
        include_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
1760
        include_once DOL_DOCUMENT_ROOT . '/product/class/productbatch.class.php';
1761
        $tmpwarehouse = new Entrepot($db);
1762
        $tmpproductbatch = new Productbatch($db);
1763
1764
        $format = 'day';
1765
        foreach ($dbatch as $detail) {
1766
            $dte = array();
1767
            if ($detail->eatby) {
1768
                $dte[] = $outputlangs->transnoentitiesnoconv('printEatby', dol_print_date($detail->eatby, $format, false, $outputlangs));
1769
            }
1770
            if ($detail->sellby) {
1771
                $dte[] = $outputlangs->transnoentitiesnoconv('printSellby', dol_print_date($detail->sellby, $format, false, $outputlangs));
1772
            }
1773
            if ($detail->batch) {
1774
                $dte[] = $outputlangs->transnoentitiesnoconv('printBatch', $detail->batch);
1775
            }
1776
            $dte[] = $outputlangs->transnoentitiesnoconv('printQty', $detail->qty);
1777
1778
            // Add also info of planned warehouse for lot
1779
            if ($object->element == 'shipping' && $detail->fk_origin_stock > 0 && getDolGlobalInt('PRODUCTBATCH_SHOW_WAREHOUSE_ON_SHIPMENT')) {
1780
                $resproductbatch = $tmpproductbatch->fetch($detail->fk_origin_stock);
1781
                if ($resproductbatch > 0) {
1782
                    $reswarehouse = $tmpwarehouse->fetch($tmpproductbatch->warehouseid);
1783
                    if ($reswarehouse > 0) {
1784
                        $dte[] = $tmpwarehouse->ref;
1785
                    }
1786
                }
1787
            }
1788
1789
            $libelleproduitservice .= "__N__  " . implode(" - ", $dte);
1790
        }
1791
    } else {
1792
        if (getDolGlobalInt('PRODUCTBATCH_SHOW_WAREHOUSE_ON_SHIPMENT')) {
1793
            // TODO Show warehouse for shipment line without batch
1794
        }
1795
    }
1796
1797
    // Now we convert \n into br
1798
    if (dol_textishtml($libelleproduitservice)) {
1799
        $libelleproduitservice = preg_replace('/__N__/', '<br>', $libelleproduitservice);
1800
    } else {
1801
        $libelleproduitservice = preg_replace('/__N__/', "\n", $libelleproduitservice);
1802
    }
1803
    $libelleproduitservice = dol_htmlentitiesbr($libelleproduitservice, 1);
1804
1805
    return $libelleproduitservice;
1806
}
1807
1808
/**
1809
 *  Return line num
1810
 *
1811
 *  @param  Object      $object             Object
1812
 *  @param  int         $i                  Current line number
1813
 *  @param  Translate   $outputlangs        Object langs for output
1814
 *  @param  int         $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
1815
 *  @return string
1816
 */
1817
function pdf_getlinenum($object, $i, $outputlangs, $hidedetails = 0)
1818
{
1819
    global $hookmanager;
1820
1821
    $reshook = 0;
1822
    $result = '';
1823
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
1824
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1825
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
1826
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
1827
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1828
        }
1829
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
1830
        $action = '';
1831
        $reshook = $hookmanager->executeHooks('pdf_getlinenum', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
1832
        $result .= $hookmanager->resPrint;
1833
    }
1834
    if (empty($reshook)) {
1835
        $result .= dol_htmlentitiesbr($object->lines[$i]->num);
1836
    }
1837
    return $result;
1838
}
1839
1840
1841
/**
1842
 *  Return line product ref
1843
 *
1844
 *  @param  Object      $object             Object
1845
 *  @param  int         $i                  Current line number
1846
 *  @param  Translate   $outputlangs        Object langs for output
1847
 *  @param  int         $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
1848
 *  @return string
1849
 */
1850
function pdf_getlineref($object, $i, $outputlangs, $hidedetails = 0)
1851
{
1852
    global $hookmanager;
1853
1854
    $reshook = 0;
1855
    $result = '';
1856
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
1857
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1858
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
1859
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
1860
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1861
        }
1862
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
1863
        $action = '';
1864
        $reshook = $hookmanager->executeHooks('pdf_getlineref', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
1865
        $result .= $hookmanager->resPrint;
1866
    }
1867
    if (empty($reshook)) {
1868
        $result .= dol_htmlentitiesbr($object->lines[$i]->product_ref);
1869
    }
1870
    return $result;
1871
}
1872
1873
/**
1874
 *  Return line ref_supplier
1875
 *
1876
 *  @param  Object      $object             Object
1877
 *  @param  int         $i                  Current line number
1878
 *  @param  Translate   $outputlangs        Object langs for output
1879
 *  @param  int         $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
1880
 *  @return string
1881
 */
1882
function pdf_getlineref_supplier($object, $i, $outputlangs, $hidedetails = 0)
1883
{
1884
    global $hookmanager;
1885
1886
    $reshook = 0;
1887
    $result = '';
1888
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
1889
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1890
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
1891
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
1892
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1893
        }
1894
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
1895
        $action = '';
1896
        $reshook = $hookmanager->executeHooks('pdf_getlineref_supplier', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
1897
        $result .= $hookmanager->resPrint;
1898
    }
1899
    if (empty($reshook)) {
1900
        $result .= dol_htmlentitiesbr($object->lines[$i]->ref_supplier);
1901
    }
1902
    return $result;
1903
}
1904
1905
/**
1906
 *  Return line vat rate
1907
 *
1908
 *  @param  Object      $object             Object
1909
 *  @param  int         $i                  Current line number
1910
 *  @param  Translate   $outputlangs        Object langs for output
1911
 *  @param  int         $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
1912
 *  @return string
1913
 */
1914
function pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails = 0)
1915
{
1916
    global $conf, $hookmanager, $mysoc;
1917
1918
    $result = '';
1919
    $reshook = 0;
1920
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
1921
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduce this test in the pdf_xxx function if you don't want your hook to run
1922
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
1923
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
1924
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1925
        }
1926
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
1927
        $action = '';
1928
        $reshook = $hookmanager->executeHooks('pdf_getlinevatrate', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
1929
1930
        if (!empty($hookmanager->resPrint)) {
1931
            $result .= $hookmanager->resPrint;
1932
        }
1933
    }
1934
    if (empty($reshook)) {
1935
        if (empty($hidedetails) || $hidedetails > 1) {
1936
            $tmpresult = '';
1937
1938
            $tmpresult .= vatrate($object->lines[$i]->tva_tx, 0, $object->lines[$i]->info_bits, -1);
1939
            if (!getDolGlobalString('MAIN_PDF_MAIN_HIDE_SECOND_TAX')) {
1940
                if ($object->lines[$i]->total_localtax1 != 0) {
1941
                    if (preg_replace('/[\s0%]/', '', $tmpresult)) {
1942
                        $tmpresult .= '/';
1943
                    } else {
1944
                        $tmpresult = '';
1945
                    }
1946
                    $tmpresult .= vatrate(abs($object->lines[$i]->localtax1_tx), 0);
1947
                }
1948
            }
1949
            if (!getDolGlobalString('MAIN_PDF_MAIN_HIDE_THIRD_TAX')) {
1950
                if ($object->lines[$i]->total_localtax2 != 0) {
1951
                    if (preg_replace('/[\s0%]/', '', $tmpresult)) {
1952
                        $tmpresult .= '/';
1953
                    } else {
1954
                        $tmpresult = '';
1955
                    }
1956
                    $tmpresult .= vatrate(abs($object->lines[$i]->localtax2_tx), 0);
1957
                }
1958
            }
1959
            $tmpresult .= '%';
1960
1961
            $result .= $tmpresult;
1962
        }
1963
    }
1964
    return $result;
1965
}
1966
1967
/**
1968
 *  Return line unit price excluding tax
1969
 *
1970
 *  @param  Object      $object             Object
1971
 *  @param  int         $i                  Current line number
1972
 *  @param  Translate   $outputlangs        Object langs for output
1973
 *  @param  int         $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
1974
 *  @return string
1975
 */
1976
function pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails = 0)
1977
{
1978
    global $conf, $hookmanager;
1979
1980
    $sign = 1;
1981
    if (isset($object->type) && $object->type == 2 && getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE')) {
1982
        $sign = -1;
1983
    }
1984
1985
    $result = '';
1986
    $reshook = 0;
1987
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
1988
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1989
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
1990
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
1991
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1992
        }
1993
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
1994
        $action = '';
1995
        $reshook = $hookmanager->executeHooks('pdf_getlineupexcltax', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
1996
1997
        if (!empty($hookmanager->resPrint)) {
1998
            $result .= $hookmanager->resPrint;
1999
        }
2000
    }
2001
    if (empty($reshook)) {
2002
        if (empty($hidedetails) || $hidedetails > 1) {
2003
            $subprice = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1 ? $object->lines[$i]->multicurrency_subprice : $object->lines[$i]->subprice);
2004
            $result .= price($sign * $subprice, 0, $outputlangs);
2005
        }
2006
    }
2007
    return $result;
2008
}
2009
2010
/**
2011
 *  Return line unit price including tax
2012
 *
2013
 *  @param  Object      $object             Object
2014
 *  @param  int         $i                  Current line number
2015
 *  @param  Translate   $outputlangs        Object langs for output
2016
 *  @param  int         $hidedetails        Hide value (0 = no, 1 = yes, 2 = just special lines)
2017
 *  @return string
2018
 */
2019
function pdf_getlineupwithtax($object, $i, $outputlangs, $hidedetails = 0)
2020
{
2021
    global $hookmanager, $conf;
2022
2023
    $sign = 1;
2024
    if (isset($object->type) && $object->type == 2 && getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE')) {
2025
        $sign = -1;
2026
    }
2027
2028
    $result = '';
2029
    $reshook = 0;
2030
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
2031
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
2032
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2033
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2034
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2035
        }
2036
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2037
        $action = '';
2038
        $reshook = $hookmanager->executeHooks('pdf_getlineupwithtax', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2039
2040
        if (!empty($hookmanager->resPrint)) {
2041
            $result .= $hookmanager->resPrint;
2042
        }
2043
    }
2044
    if (empty($reshook)) {
2045
        if (empty($hidedetails) || $hidedetails > 1) {
2046
            $result .= price($sign * (($object->lines[$i]->subprice) + ($object->lines[$i]->subprice) * ($object->lines[$i]->tva_tx) / 100), 0, $outputlangs);
2047
        }
2048
    }
2049
    return $result;
2050
}
2051
2052
/**
2053
 *  Return line quantity
2054
 *
2055
 *  @param  Object      $object             Object
2056
 *  @param  int         $i                  Current line number
2057
 *  @param  Translate   $outputlangs        Object langs for output
2058
 *  @param  int         $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
2059
 *  @return string
2060
 */
2061
function pdf_getlineqty($object, $i, $outputlangs, $hidedetails = 0)
2062
{
2063
    global $hookmanager;
2064
2065
    $result = '';
2066
    $reshook = 0;
2067
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
2068
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
2069
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2070
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2071
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2072
        }
2073
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2074
        $action = '';
2075
        $reshook = $hookmanager->executeHooks('pdf_getlineqty', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2076
2077
        if (!empty($hookmanager->resPrint)) {
2078
            $result = $hookmanager->resPrint;
2079
        }
2080
    }
2081
    if (empty($reshook)) {
2082
        if ($object->lines[$i]->special_code == 3) {
2083
            return '';
2084
        }
2085
        if (empty($hidedetails) || $hidedetails > 1) {
2086
            $result .= $object->lines[$i]->qty;
2087
        }
2088
    }
2089
    return $result;
2090
}
2091
2092
/**
2093
 *  Return line quantity asked
2094
 *
2095
 *  @param  Object      $object             Object
2096
 *  @param  int         $i                  Current line number
2097
 *  @param  Translate   $outputlangs        Object langs for output
2098
 *  @param  int         $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
2099
 *  @return string
2100
 */
2101
function pdf_getlineqty_asked($object, $i, $outputlangs, $hidedetails = 0)
2102
{
2103
    global $hookmanager;
2104
2105
    $reshook = 0;
2106
    $result = '';
2107
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
2108
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
2109
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2110
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2111
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2112
        }
2113
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2114
        $action = '';
2115
        $reshook = $hookmanager->executeHooks('pdf_getlineqty_asked', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2116
2117
        if (!empty($hookmanager->resPrint)) {
2118
            $result .= $hookmanager->resPrint;
2119
        }
2120
    }
2121
    if (empty($reshook)) {
2122
        if ($object->lines[$i]->special_code == 3) {
2123
            return '';
2124
        }
2125
        if (empty($hidedetails) || $hidedetails > 1) {
2126
            $result .= $object->lines[$i]->qty_asked;
2127
        }
2128
    }
2129
    return $result;
2130
}
2131
2132
/**
2133
 *  Return line quantity shipped
2134
 *
2135
 *  @param  Object      $object             Object
2136
 *  @param  int         $i                  Current line number
2137
 *  @param  Translate   $outputlangs        Object langs for output
2138
 *  @param  int         $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
2139
 *  @return string
2140
 */
2141
function pdf_getlineqty_shipped($object, $i, $outputlangs, $hidedetails = 0)
2142
{
2143
    global $hookmanager;
2144
2145
    $reshook = 0;
2146
    $result = '';
2147
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
2148
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
2149
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2150
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2151
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2152
        }
2153
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2154
        $action = '';
2155
        $reshook = $hookmanager->executeHooks('pdf_getlineqty_shipped', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2156
2157
        if (!empty($hookmanager->resPrint)) {
2158
            $result .= $hookmanager->resPrint;
2159
        }
2160
    }
2161
    if (empty($reshook)) {
2162
        if ($object->lines[$i]->special_code == 3) {
2163
            return '';
2164
        }
2165
        if (empty($hidedetails) || $hidedetails > 1) {
2166
            $result .= $object->lines[$i]->qty_shipped;
2167
        }
2168
    }
2169
    return $result;
2170
}
2171
2172
/**
2173
 *  Return line keep to ship quantity
2174
 *
2175
 *  @param  Object      $object             Object
2176
 *  @param  int         $i                  Current line number
2177
 *  @param  Translate   $outputlangs        Object langs for output
2178
 *  @param  int         $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
2179
 *  @return string
2180
 */
2181
function pdf_getlineqty_keeptoship($object, $i, $outputlangs, $hidedetails = 0)
2182
{
2183
    global $hookmanager;
2184
2185
    $reshook = 0;
2186
    $result = '';
2187
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
2188
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
2189
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2190
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2191
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2192
        }
2193
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2194
        $action = '';
2195
        $reshook = $hookmanager->executeHooks('pdf_getlineqty_keeptoship', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2196
2197
        if (!empty($hookmanager->resPrint)) {
2198
            $result .= $hookmanager->resPrint;
2199
        }
2200
    }
2201
    if (empty($reshook)) {
2202
        if ($object->lines[$i]->special_code == 3) {
2203
            return '';
2204
        }
2205
        if (empty($hidedetails) || $hidedetails > 1) {
2206
            $result .= ($object->lines[$i]->qty_asked - $object->lines[$i]->qty_shipped);
2207
        }
2208
    }
2209
    return $result;
2210
}
2211
2212
/**
2213
 *  Return line unit
2214
 *
2215
 *  @param  Object      $object             Object
2216
 *  @param  int         $i                  Current line number
2217
 *  @param  Translate   $outputlangs        Object langs for output
2218
 *  @param  int         $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
2219
 *  @return string                          Value for unit cell
2220
 */
2221
function pdf_getlineunit($object, $i, $outputlangs, $hidedetails = 0)
2222
{
2223
    global $hookmanager, $langs;
2224
2225
    $reshook = 0;
2226
    $result = '';
2227
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
2228
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
2229
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2230
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2231
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2232
        }
2233
        $parameters = array(
2234
            'i' => $i,
2235
            'outputlangs' => $outputlangs,
2236
            'hidedetails' => $hidedetails,
2237
            'special_code' => $special_code
2238
        );
2239
        $action = '';
2240
        $reshook = $hookmanager->executeHooks('pdf_getlineunit', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2241
2242
        if (!empty($hookmanager->resPrint)) {
2243
            $result .= $hookmanager->resPrint;
2244
        }
2245
    }
2246
    if (empty($reshook)) {
2247
        if (empty($hidedetails) || $hidedetails > 1) {
2248
            $result .= $langs->transnoentitiesnoconv($object->lines[$i]->getLabelOfUnit('short'));
2249
        }
2250
    }
2251
    return $result;
2252
}
2253
2254
2255
/**
2256
 *  Return line remise percent
2257
 *
2258
 *  @param  Object      $object             Object
2259
 *  @param  int         $i                  Current line number
2260
 *  @param  Translate   $outputlangs        Object langs for output
2261
 *  @param  int         $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
2262
 *  @return string
2263
 */
2264
function pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails = 0)
2265
{
2266
    global $hookmanager;
2267
2268
    include_once BASE_PATH . '/../Dolibarr/Lib/Functions2.php';
2269
2270
    $reshook = 0;
2271
    $result = '';
2272
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
2273
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
2274
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2275
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2276
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2277
        }
2278
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2279
        $action = '';
2280
        $reshook = $hookmanager->executeHooks('pdf_getlineremisepercent', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2281
2282
        if (!empty($hookmanager->resPrint)) {
2283
            $result .= $hookmanager->resPrint;
2284
        }
2285
    }
2286
    if (empty($reshook)) {
2287
        if ($object->lines[$i]->special_code == 3) {
2288
            return '';
2289
        }
2290
        if (empty($hidedetails) || $hidedetails > 1) {
2291
            $result .= dol_print_reduction($object->lines[$i]->remise_percent, $outputlangs);
2292
        }
2293
    }
2294
    return $result;
2295
}
2296
2297
/**
2298
 * Return line percent
2299
 *
2300
 * @param Object                $object             Object
2301
 * @param int                   $i                  Current line number
2302
 * @param Translate             $outputlangs        Object langs for output
2303
 * @param int                   $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
2304
 * @param HookManager|null      $hookmanager        Hook manager instance
2305
 * @return string
2306
 */
2307
function pdf_getlineprogress($object, $i, $outputlangs, $hidedetails = 0, $hookmanager = null)
2308
{
2309
    if (empty($hookmanager)) {
2310
        global $hookmanager;
2311
    }
2312
    global $conf;
2313
2314
    $reshook = 0;
2315
    $result = '';
2316
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
2317
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
2318
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2319
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2320
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2321
        }
2322
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2323
        $action = '';
2324
        $reshook = $hookmanager->executeHooks('pdf_getlineprogress', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2325
2326
        if (!empty($hookmanager->resPrint)) {
2327
            return $hookmanager->resPrint;
2328
        }
2329
    }
2330
    if (empty($reshook)) {
2331
        if ($object->lines[$i]->special_code == 3) {
2332
            return '';
2333
        }
2334
        if (empty($hidedetails) || $hidedetails > 1) {
2335
            if (getDolGlobalString('SITUATION_DISPLAY_DIFF_ON_PDF')) {
2336
                $prev_progress = 0;
2337
                if (method_exists($object->lines[$i], 'get_prev_progress')) {
2338
                    $prev_progress = $object->lines[$i]->get_prev_progress($object->id);
2339
                }
2340
                $result = round($object->lines[$i]->situation_percent - $prev_progress, 1) . '%';
2341
            } else {
2342
                $result = round($object->lines[$i]->situation_percent, 1) . '%';
2343
            }
2344
        }
2345
    }
2346
    return $result;
2347
}
2348
2349
/**
2350
 *  Return line total excluding tax
2351
 *
2352
 *  @param  Object      $object             Object
2353
 *  @param  int         $i                  Current line number
2354
 *  @param  Translate   $outputlangs        Object langs for output
2355
 *  @param  int         $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
2356
 *  @return string                          Return total of line excl tax
2357
 */
2358
function pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails = 0)
2359
{
2360
    global $conf, $hookmanager;
2361
2362
    $sign = 1;
2363
    if (isset($object->type) && $object->type == 2 && getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE')) {
2364
        $sign = -1;
2365
    }
2366
2367
    $reshook = 0;
2368
    $result = '';
2369
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
2370
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
2371
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2372
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2373
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2374
        }
2375
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code, 'sign' => $sign);
2376
        $action = '';
2377
        $reshook = $hookmanager->executeHooks('pdf_getlinetotalexcltax', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2378
2379
        if (!empty($hookmanager->resPrint)) {
2380
            $result .= $hookmanager->resPrint;
2381
        }
2382
    }
2383
    if (empty($reshook)) {
2384
        if (!empty($object->lines[$i]) && $object->lines[$i]->special_code == 3) {
2385
            $result .= $outputlangs->transnoentities("Option");
2386
        } elseif (empty($hidedetails) || $hidedetails > 1) {
2387
            $total_ht = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1 ? $object->lines[$i]->multicurrency_total_ht : $object->lines[$i]->total_ht);
2388
            if (!empty($object->lines[$i]->situation_percent) && $object->lines[$i]->situation_percent > 0) {
2389
                // TODO Remove this. The total should be saved correctly in database instead of being modified here.
2390
                $prev_progress = 0;
2391
                $progress = 1;
2392
                if (method_exists($object->lines[$i], 'get_prev_progress')) {
2393
                    $prev_progress = $object->lines[$i]->get_prev_progress($object->id);
2394
                    $progress = ($object->lines[$i]->situation_percent - $prev_progress) / 100;
2395
                }
2396
                $result .= price($sign * ($total_ht / ($object->lines[$i]->situation_percent / 100)) * $progress, 0, $outputlangs);
2397
            } else {
2398
                $result .= price($sign * $total_ht, 0, $outputlangs);
2399
            }
2400
        }
2401
    }
2402
    return $result;
2403
}
2404
2405
/**
2406
 *  Return line total including tax
2407
 *
2408
 *  @param  Object      $object             Object
2409
 *  @param  int         $i                  Current line number
2410
 *  @param  Translate   $outputlangs        Object langs for output
2411
 *  @param  int         $hidedetails        Hide value (0 = no, 1 = yes, 2 = just special lines)
2412
 *  @return string                          Return total of line incl tax
2413
 */
2414
function pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails = 0)
2415
{
2416
    global $hookmanager, $conf;
2417
2418
    $sign = 1;
2419
    if (isset($object->type) && $object->type == 2 && getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE')) {
2420
        $sign = -1;
2421
    }
2422
2423
    $reshook = 0;
2424
    $result = '';
2425
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )
2426
    if (is_object($hookmanager)) {   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
2427
        $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2428
        if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2429
            $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2430
        }
2431
        $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2432
        $action = '';
2433
        $reshook = $hookmanager->executeHooks('pdf_getlinetotalwithtax', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2434
2435
        if (!empty($hookmanager->resPrint)) {
2436
            $result .= $hookmanager->resPrint;
2437
        }
2438
    }
2439
    if (empty($reshook)) {
2440
        if ($object->lines[$i]->special_code == 3) {
2441
            $result .= $outputlangs->transnoentities("Option");
2442
        } elseif (empty($hidedetails) || $hidedetails > 1) {
2443
            $total_ttc = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1 ? $object->lines[$i]->multicurrency_total_ttc : $object->lines[$i]->total_ttc);
2444
            if ($object->lines[$i]->situation_percent > 0) {
2445
                // TODO Remove this. The total should be saved correctly in database instead of being modified here.
2446
                $prev_progress = 0;
2447
                $progress = 1;
2448
                if (method_exists($object->lines[$i], 'get_prev_progress')) {
2449
                    $prev_progress = $object->lines[$i]->get_prev_progress($object->id);
2450
                    $progress = ($object->lines[$i]->situation_percent - $prev_progress) / 100;
2451
                }
2452
                $result .= price($sign * ($total_ttc / ($object->lines[$i]->situation_percent / 100)) * $progress, 0, $outputlangs);
2453
            } else {
2454
                $result .= price($sign * $total_ttc, 0, $outputlangs);
2455
            }
2456
        }
2457
    }
2458
    return $result;
2459
}
2460
2461
/**
2462
 *  Return linked objects to use for document generation.
2463
 *  Warning: To save space, this function returns only one link per link type (all links are concated on same record string). This function is used by pdf_writeLinkedObjects
2464
 *
2465
 *  @param  CommonObject    $object         Object
2466
 *  @param  Translate       $outputlangs    Object lang for output
2467
 *  @return array                           Linked objects
2468
 */
2469
function pdf_getLinkedObjects(&$object, $outputlangs)
2470
{
2471
    global $db, $hookmanager;
2472
2473
    $linkedobjects = array();
2474
2475
    $object->fetchObjectLinked();
2476
2477
    foreach ($object->linkedObjects as $objecttype => $objects) {
2478
        if ($objecttype == 'facture') {
2479
            // For invoice, we don't want to have a reference line on document. Image we are using recurring invoice, we will have a line longer than document width.
2480
        } elseif ($objecttype == 'propal' || $objecttype == 'supplier_proposal') {
2481
            $outputlangs->load('propal');
2482
2483
            foreach ($objects as $elementobject) {
2484
                $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefProposal");
2485
                $linkedobjects[$objecttype]['ref_value'] = $outputlangs->transnoentities($elementobject->ref);
2486
                $linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("DatePropal");
2487
                $linkedobjects[$objecttype]['date_value'] = dol_print_date($elementobject->date, 'day', '', $outputlangs);
2488
            }
2489
        } elseif ($objecttype == 'commande' || $objecttype == 'supplier_order') {
2490
            $outputlangs->load('orders');
2491
2492
            if (count($objects) > 1 && count($objects) <= (getDolGlobalInt("MAXREFONDOC") ? getDolGlobalInt("MAXREFONDOC") : 10)) {
2493
                $object->note_public = dol_concatdesc($object->note_public, $outputlangs->transnoentities("RefOrder") . ' :');
2494
                foreach ($objects as $elementobject) {
2495
                    $object->note_public = dol_concatdesc($object->note_public, $outputlangs->transnoentities($elementobject->ref) . (empty($elementobject->ref_client) ? '' : ' (' . $elementobject->ref_client . ')') . (empty($elementobject->ref_supplier) ? '' : ' (' . $elementobject->ref_supplier . ')') . ' ');
2496
                    $object->note_public = dol_concatdesc($object->note_public, $outputlangs->transnoentities("OrderDate") . ' : ' . dol_print_date($elementobject->date, 'day', '', $outputlangs));
2497
                }
2498
            } elseif (count($objects) == 1) {
2499
                $elementobject = array_shift($objects);
2500
                $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefOrder");
2501
                $linkedobjects[$objecttype]['ref_value'] = $outputlangs->transnoentities($elementobject->ref) . (!empty($elementobject->ref_client) ? ' (' . $elementobject->ref_client . ')' : '') . (!empty($elementobject->ref_supplier) ? ' (' . $elementobject->ref_supplier . ')' : '');
2502
                $linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("OrderDate");
2503
                $linkedobjects[$objecttype]['date_value'] = dol_print_date($elementobject->date, 'day', '', $outputlangs);
2504
            }
2505
        } elseif ($objecttype == 'contrat') {
2506
            $outputlangs->load('contracts');
2507
            foreach ($objects as $elementobject) {
2508
                $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefContract");
2509
                $linkedobjects[$objecttype]['ref_value'] = $outputlangs->transnoentities($elementobject->ref);
2510
                $linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("DateContract");
2511
                $linkedobjects[$objecttype]['date_value'] = dol_print_date($elementobject->date_contrat, 'day', '', $outputlangs);
2512
            }
2513
        } elseif ($objecttype == 'fichinter') {
2514
            $outputlangs->load('interventions');
2515
            foreach ($objects as $elementobject) {
2516
                $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("InterRef");
2517
                $linkedobjects[$objecttype]['ref_value'] = $outputlangs->transnoentities($elementobject->ref);
2518
                $linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("InterDate");
2519
                $linkedobjects[$objecttype]['date_value'] = dol_print_date($elementobject->datec, 'day', '', $outputlangs);
2520
            }
2521
        } elseif ($objecttype == 'shipping') {
2522
            $outputlangs->loadLangs(array("orders", "sendings"));
2523
2524
            if (count($objects) > 1) {
2525
                $order = null;
2526
                if (empty($object->linkedObjects['commande']) && $object->element != 'commande') {
2527
                    $object->note_public = dol_concatdesc($object->note_public, $outputlangs->transnoentities("RefOrder") . ' / ' . $outputlangs->transnoentities("RefSending") . ' :');
2528
                } else {
2529
                    $object->note_public = dol_concatdesc($object->note_public, $outputlangs->transnoentities("RefSending") . ' :');
2530
                }
2531
                // We concat this record info into fields xxx_value. title is overwrote.
2532
                foreach ($objects as $elementobject) {
2533
                    if (empty($object->linkedObjects['commande']) && $object->element != 'commande') {    // There is not already a link to order and object is not the order, so we show also info with order
2534
                        $elementobject->fetchObjectLinked(null, '', null, '', 'OR', 1, 'sourcetype', 0);
2535
                        if (!empty($elementobject->linkedObjectsIds['commande'])) {
2536
                            $order = new Commande($db);
2537
                            $ret = $order->fetch(reset($elementobject->linkedObjectsIds['commande']));
2538
                            if ($ret < 1) {
2539
                                $order = null;
2540
                            }
2541
                        }
2542
                    }
2543
2544
                    if (! is_object($order)) {
2545
                        $object->note_public = dol_concatdesc($object->note_public, $outputlangs->transnoentities($elementobject->ref));
2546
                    } else {
2547
                        $object->note_public = dol_concatdesc($object->note_public, $outputlangs->convToOutputCharset($order->ref) . ($order->ref_client ? ' (' . $order->ref_client . ')' : ''));
2548
                        $object->note_public = dol_concatdesc($object->note_public, ' / ' . $outputlangs->transnoentities($elementobject->ref));
2549
                    }
2550
                }
2551
            } elseif (count($objects) == 1) {
2552
                $elementobject = array_shift($objects);
2553
                $order = null;
2554
                // We concat this record info into fields xxx_value. title is overwrote.
2555
                if (empty($object->linkedObjects['commande']) && $object->element != 'commande') {    // There is not already a link to order and object is not the order, so we show also info with order
2556
                    $elementobject->fetchObjectLinked(null, '', null, '', 'OR', 1, 'sourcetype', 0);
2557
                    if (!empty($elementobject->linkedObjectsIds['commande'])) {
2558
                        $order = new Commande($db);
2559
                        $ret = $order->fetch(reset($elementobject->linkedObjectsIds['commande']));
2560
                        if ($ret < 1) {
2561
                            $order = null;
2562
                        }
2563
                    }
2564
                }
2565
2566
                if (! is_object($order)) {
2567
                    $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefSending");
2568
                    if (empty($linkedobjects[$objecttype]['ref_value'])) {
2569
                        $linkedobjects[$objecttype]['ref_value'] = '';
2570
                    } else {
2571
                        $linkedobjects[$objecttype]['ref_value'] .= ' / ';
2572
                    }
2573
                    $linkedobjects[$objecttype]['ref_value'] .= $outputlangs->transnoentities($elementobject->ref);
2574
                    $linkedobjects[$objecttype]['date_value'] = dol_print_date(empty($elementobject->date_shipping) ? $elementobject->date_delivery : $elementobject->date_shipping, 'day', '', $outputlangs);
2575
                } else {
2576
                    $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefOrder") . ' / ' . $outputlangs->transnoentities("RefSending");
2577
                    if (empty($linkedobjects[$objecttype]['ref_value'])) {
2578
                        $linkedobjects[$objecttype]['ref_value'] = $outputlangs->convToOutputCharset($order->ref) . ($order->ref_client ? ' (' . $order->ref_client . ')' : '');
2579
                    }
2580
                    $linkedobjects[$objecttype]['ref_value'] .= ' / ' . $outputlangs->transnoentities($elementobject->ref);
2581
                    $linkedobjects[$objecttype]['date_value'] = dol_print_date(empty($elementobject->date_shipping) ? $elementobject->date_delivery : $elementobject->date_shipping, 'day', '', $outputlangs);
2582
                }
2583
            }
2584
        }
2585
    }
2586
2587
    // For add external linked objects
2588
    if (is_object($hookmanager)) {
2589
        $parameters = array('linkedobjects' => $linkedobjects, 'outputlangs' => $outputlangs);
2590
        $action = '';
2591
        $hookmanager->executeHooks('pdf_getLinkedObjects', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2592
        if (!empty($hookmanager->resArray)) {
2593
            $linkedobjects = $hookmanager->resArray;
2594
        }
2595
    }
2596
2597
    return $linkedobjects;
2598
}
2599
2600
/**
2601
 * Return dimensions to use for images onto PDF checking that width and height are not higher than
2602
 * maximum (16x32 by default).
2603
 *
2604
 * @param   string      $realpath       Full path to photo file to use
2605
 * @return  array                       Height and width to use to output image (in pdf user unit, so mm)
2606
 */
2607
function pdf_getSizeForImage($realpath)
2608
{
2609
    global $conf;
2610
2611
    $maxwidth = (!getDolGlobalString('MAIN_DOCUMENTS_WITH_PICTURE_WIDTH') ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH);
2612
    $maxheight = (!getDolGlobalString('MAIN_DOCUMENTS_WITH_PICTURE_HEIGHT') ? 32 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_HEIGHT);
2613
    include_once BASE_PATH . '/../Dolibarr/Lib/Images.php';
2614
    $tmp = dol_getImageSize($realpath);
2615
    $width = 0;
2616
    $height = 0;
2617
    if ($tmp['height']) {
2618
        $width = (int) round($maxheight * $tmp['width'] / $tmp['height']); // I try to use maxheight
2619
        if ($width > $maxwidth) {   // Pb with maxheight, so i use maxwidth
2620
            $width = $maxwidth;
2621
            $height = (int) round($maxwidth * $tmp['height'] / $tmp['width']);
2622
        } else { // No pb with maxheight
2623
            $height = $maxheight;
2624
        }
2625
    }
2626
    return array('width' => $width, 'height' => $height);
2627
}
2628
2629
/**
2630
 *  Return line total amount discount
2631
 *
2632
 *  @param  CommonObject    $object             Object
2633
 *  @param  int             $i                  Current line number
2634
 *  @param  Translate       $outputlangs        Object langs for output
2635
 *  @param  int             $hidedetails        Hide details (0=no, 1=yes, 2=just special lines)
2636
 *  @return float|string                        Return total of line excl tax
2637
 */
2638
function pdfGetLineTotalDiscountAmount($object, $i, $outputlangs, $hidedetails = 0)
2639
{
2640
    global $conf, $hookmanager;
2641
2642
    $sign = 1;
2643
    if (isset($object->type) && $object->type == 2 && getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE')) {
2644
        $sign = -1;
2645
    }
2646
    if ($object->lines[$i]->special_code == 3) {
2647
        return $outputlangs->transnoentities("Option");
2648
    } else {
2649
        if (is_object($hookmanager)) {
2650
            $special_code = $object->lines[$i]->special_code;
2651
            if (!empty($object->lines[$i]->fk_parent_line)) {
2652
                $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2653
            }
2654
2655
            $parameters = array(
2656
                'i' => $i,
2657
                'outputlangs' => $outputlangs,
2658
                'hidedetails' => $hidedetails,
2659
                'special_code' => $special_code
2660
            );
2661
2662
            $action = '';
2663
2664
            if ($hookmanager->executeHooks('getlinetotalremise', $parameters, $object, $action) > 0) {  // Note that $action and $object may have been modified by some hooks
2665
                if (isset($hookmanager->resArray['linetotalremise'])) {
2666
                    return $hookmanager->resArray['linetotalremise'];
2667
                } else {
2668
                    return (float) $hookmanager->resPrint;  // For backward compatibility
2669
                }
2670
            }
2671
        }
2672
2673
        if (empty($hidedetails) || $hidedetails > 1) {
2674
            return $sign * (($object->lines[$i]->subprice * $object->lines[$i]->qty) - $object->lines[$i]->total_ht);
2675
        }
2676
    }
2677
    return 0;
2678
}
2679