dolibarr 23.0.4
pdf.lib.php
Go to the documentation of this file.
1<?php
2
3/* Copyright (C) 2006-2017 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
5 * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
6 * Copyright (C) 2010-2012 Regis Houssin <regis.houssin@inodbox.com>
7 * Copyright (C) 2010-2017 Juanjo Menent <jmenent@2byte.es>
8 * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
9 * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr>
10 * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
11 * Copyright (C) 2014 Cedric GROSS <c.gross@kreiz-it.fr>
12 * Copyright (C) 2014 Teddy Andreotti <125155@supinfo.com>
13 * Copyright (C) 2015-2016 Marcos García <marcosgdf@gmail.com>
14 * Copyright (C) 2019 Lenin Rivas <lenin.rivas@servcom-it.com>
15 * Copyright (C) 2020 Nicolas ZABOURI <info@inovea-conseil.com>
16 * Copyright (C) 2021-2022 Anthony Berton <anthony.berton@bb2a.fr>
17 * Copyright (C) 2023-2025 Frédéric France <frederic.france@free.fr>
18 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 3 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program. If not, see <https://www.gnu.org/licenses/>.
32 * or see https://www.gnu.org/
33 */
34
41include_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
42
43
50{
51 global $langs, $conf;
52
53 $h = 0;
54 $head = array();
55
56 $head[$h][0] = DOL_URL_ROOT.'/admin/pdf.php';
57 $head[$h][1] = $langs->trans("GlobalParameters");
58 $head[$h][2] = 'general';
59 $h++;
60
61 // Show more tabs from modules
62 // Entries must be declared in modules descriptor with line
63 // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab
64 // $this->tabs = array('entity:-tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to remove a tab
65 complete_head_from_modules($conf, $langs, null, $head, $h, 'pdf_admin');
66
67 if (isModEnabled("propal") || isModEnabled('invoice') || isModEnabled('reception')) {
68 $head[$h][0] = DOL_URL_ROOT.'/admin/pdf_other.php';
69 $head[$h][1] = $langs->trans("SpecificParameters");
70 $head[$h][2] = 'other';
71 $h++;
72 }
73
74 complete_head_from_modules($conf, $langs, null, $head, $h, 'pdf_admin', 'remove');
75
76 return $head;
77}
78
79
87function pdf_getFormat($outputlangs = null, $mode = 'setup')
88{
89 global $conf, $db, $langs;
90
91 dol_syslog("pdf_getFormat Get paper format with mode=".$mode." MAIN_PDF_FORMAT=".getDolGlobalString('MAIN_PDF_FORMAT')." outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null')." and langs->defaultlang=".(is_object($langs) ? $langs->defaultlang : 'null'));
92
93 // Default value if setup was not done and/or entry into c_paper_format not defined
94 $width = 210;
95 $height = 297;
96 $unit = 'mm';
97
98 if ($mode == 'auto' || !getDolGlobalString('MAIN_PDF_FORMAT') || getDolGlobalString('MAIN_PDF_FORMAT') == 'auto') {
99 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
100 $pdfformat = dol_getDefaultFormat($outputlangs);
101 } else {
102 $pdfformat = getDolGlobalString('MAIN_PDF_FORMAT');
103 }
104
105 $sql = "SELECT code, label, width, height, unit FROM ".MAIN_DB_PREFIX."c_paper_format";
106 $sql .= " WHERE code = '".$db->escape($pdfformat)."'";
107 $resql = $db->query($sql);
108 if ($resql) {
109 $obj = $db->fetch_object($resql);
110 if ($obj) {
111 $width = (int) $obj->width;
112 $height = (int) $obj->height;
113 $unit = $obj->unit;
114 }
115 }
116
117 //print "pdfformat=".$pdfformat." width=".$width." height=".$height." unit=".$unit;
118 return array('width' => $width, 'height' => $height, 'unit' => $unit);
119}
120
129function pdf_getInstance($format = '', $metric = 'mm', $pagetype = 'P')
130{
131 global $conf;
132
133 // Define constant for TCPDF
134 if (!defined('K_TCPDF_EXTERNAL_CONFIG')) {
135 define('K_TCPDF_EXTERNAL_CONFIG', 1); // this avoid using tcpdf_config file
136 define('K_PATH_CACHE', DOL_DATA_ROOT.'/admin/temp/');
137 define('K_PATH_URL_CACHE', DOL_DATA_ROOT.'/admin/temp/');
138 dol_mkdir(K_PATH_CACHE);
139 define('K_BLANK_IMAGE', '_blank.png');
140 define('PDF_PAGE_FORMAT', 'A4');
141 define('PDF_PAGE_ORIENTATION', 'P');
142 define('PDF_CREATOR', 'TCPDF');
143 define('PDF_AUTHOR', 'TCPDF');
144 define('PDF_HEADER_TITLE', 'TCPDF Example');
145 define('PDF_HEADER_STRING', "by Dolibarr ERP CRM");
146 define('PDF_UNIT', 'mm');
147 define('PDF_MARGIN_HEADER', 5);
148 define('PDF_MARGIN_FOOTER', 10);
149 define('PDF_MARGIN_TOP', 27);
150 define('PDF_MARGIN_BOTTOM', 25);
151 define('PDF_MARGIN_LEFT', 15);
152 define('PDF_MARGIN_RIGHT', 15);
153 define('PDF_FONT_NAME_MAIN', 'helvetica');
154 define('PDF_FONT_SIZE_MAIN', 10);
155 define('PDF_FONT_NAME_DATA', 'helvetica');
156 define('PDF_FONT_SIZE_DATA', 8);
157 define('PDF_FONT_MONOSPACED', 'courier');
158 define('PDF_IMAGE_SCALE_RATIO', 1.25);
159 define('HEAD_MAGNIFICATION', 1.1);
160 define('K_CELL_HEIGHT_RATIO', 1.25);
161 define('K_TITLE_MAGNIFICATION', 1.3);
162 define('K_SMALL_RATIO', 2 / 3);
163 define('K_THAI_TOPCHARS', true);
164 define('K_TCPDF_CALLS_IN_HTML', true);
165 if (getDolGlobalString('TCPDF_THROW_ERRORS_INSTEAD_OF_DIE')) {
166 define('K_TCPDF_THROW_EXCEPTION_ERROR', true);
167 } else {
168 define('K_TCPDF_THROW_EXCEPTION_ERROR', false);
169 }
170 }
171
172 // Load TCPDF
173 require_once TCPDF_PATH.'tcpdf.php';
174
175 // We need to instantiate tcpdi object (instead of tcpdf) to use merging features. But we can disable it (this will break all merge features).
176 if (!getDolGlobalString('MAIN_DISABLE_TCPDI')) {
177 require_once TCPDI_PATH.'tcpdi.php';
178 }
179
180 //$arrayformat=pdf_getFormat();
181 //$format=array($arrayformat['width'],$arrayformat['height']);
182 //$metric=$arrayformat['unit'];
183
184 //$pdfa = false; // PDF default version
185 $pdfa = getDolGlobalInt('PDF_USE_A', 0); // PDF/A-1 ou PDF/A-3
186
187 if (!getDolGlobalString('MAIN_DISABLE_TCPDI') && class_exists('TCPDI')) {
188 $pdf = new TCPDI($pagetype, $metric, $format, true, 'UTF-8', false, $pdfa);
189 } else {
190 $pdf = new TCPDF($pagetype, $metric, $format, true, 'UTF-8', false, $pdfa);
191 }
192
193 // Protection and encryption of pdf
194 if (getDolGlobalString('PDF_SECURITY_ENCRYPTION')) {
195 /* Permission supported by TCPDF
196 - print : Print the document;
197 - modify : Modify the contents of the document by operations other than those controlled by 'fill-forms', 'extract' and 'assemble';
198 - copy : Copy or otherwise extract text and graphics from the document;
199 - 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);
200 - fill-forms : Fill in existing interactive form fields (including signature fields), even if 'annot-forms' is not specified;
201 - extract : Extract text and graphics (in support of accessibility to users with disabilities or for other purposes);
202 - assemble : Assemble the document (insert, rotate, or delete pages and create bookmarks or thumbnail images), even if 'modify' is not set;
203 - 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.
204 - owner : (inverted logic - only for public-key) when set permits change of encryption and enables all other permissions.
205 */
206
207 // For TCPDF, we specify permission we want to block
208 $pdfrights = (getDolGlobalString('PDF_SECURITY_ENCRYPTION_RIGHTS') ? json_decode(getDolGlobalString('PDF_SECURITY_ENCRYPTION_RIGHTS'), true) : array('modify', 'copy')); // Json format in llx_const
209
210 // Password for the end user
211 $pdfuserpass = getDolGlobalString('PDF_SECURITY_ENCRYPTION_USERPASS');
212
213 // Password of the owner, created randomly if not defined
214 $pdfownerpass = (getDolGlobalString('PDF_SECURITY_ENCRYPTION_OWNERPASS') ? getDolGlobalString('PDF_SECURITY_ENCRYPTION_OWNERPASS') : null);
215
216 // For encryption strength: 0 = RC4 40 bit; 1 = RC4 128 bit; 2 = AES 128 bit; 3 = AES 256 bit
217 $encstrength = getDolGlobalInt('PDF_SECURITY_ENCRYPTION_STRENGTH', 0);
218
219 // Array of recipients containing public-key certificates ('c') and permissions ('p').
220 // For example: array(array('c' => 'file://../examples/data/cert/tcpdf.crt', 'p' => array('print')))
221 $pubkeys = (getDolGlobalString('PDF_SECURITY_ENCRYPTION_PUBKEYS') ? json_decode(getDolGlobalString('PDF_SECURITY_ENCRYPTION_PUBKEYS'), true) : null); // Json format in llx_const
222
223 $pdf->SetProtection($pdfrights, $pdfuserpass, $pdfownerpass, $encstrength, $pubkeys);
224 }
225
226 return $pdf;
227}
228
235function pdf_getEncryption($pathoffile)
236{
237 require_once TCPDF_PATH.'tcpdf_parser.php';
238
239 $isencrypted = false;
240
241 $content = file_get_contents($pathoffile);
242
243 //ob_start();
244 @($parser = new TCPDF_PARSER(ltrim($content)));
245 $tmp = $parser->getParsedData();
246 $xref = $tmp[0];
247 $data = $tmp[1] ?? null;
248 unset($parser);
249 //ob_end_clean();
250
251 if (isset($xref['trailer']['encrypt'])) {
252 $isencrypted = true; // Secured pdf file are currently not supported
253 }
254
255 if (empty($data)) {
256 $isencrypted = true; // Object list not found. Possible secured file
257 }
258
259 return $isencrypted;
260}
261
268function pdf_getPDFFont($outputlangs)
269{
270 if (getDolGlobalString('MAIN_PDF_FORCE_FONT')) {
271 return getDolGlobalString('MAIN_PDF_FORCE_FONT');
272 }
273
274 $font = 'Helvetica'; // By default, for FPDI, or ISO language on TCPDF
275 if (class_exists('TCPDF')) { // If TCPDF on, we can use an UTF8 one like DejaVuSans if required (slower)
276 if ($outputlangs->trans('FONTFORPDF') != 'FONTFORPDF') {
277 $font = $outputlangs->trans('FONTFORPDF');
278 }
279 }
280 return $font;
281}
282
289function pdf_getPDFFontSize($outputlangs)
290{
291 $size = 10; // By default, for FPDI or ISO language on TCPDF
292 if (class_exists('TCPDF')) { // If TCPDF on, we can use an UTF8 font like DejaVuSans if required (slower)
293 if ($outputlangs->trans('FONTSIZEFORPDF') != 'FONTSIZEFORPDF') {
294 $size = (int) $outputlangs->trans('FONTSIZEFORPDF');
295 }
296 }
297 if (getDolGlobalString('MAIN_PDF_FORCE_FONT_SIZE')) {
298 $size = getDolGlobalString('MAIN_PDF_FORCE_FONT_SIZE');
299 }
300
301 return $size;
302}
303
304
312function pdf_getHeightForLogo($logo, $url = false)
313{
314 $height = getDolGlobalInt('MAIN_DOCUMENTS_LOGO_HEIGHT', 20);
315 $maxwidth = 130;
316 include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
317 $tmp = dol_getImageSize($logo, $url);
318 if ($tmp['height']) {
319 $width = round($height * $tmp['width'] / $tmp['height']);
320 if ($width > $maxwidth) {
321 $height = $height * $maxwidth / $width;
322 }
323 }
324 //print $tmp['width'].' '.$tmp['height'].' '.$width; exit;
325 return $height;
326}
327
337function pdfGetHeightForHtmlContent(&$pdf, $htmlcontent)
338{
339 // store current object
340 $pdf->startTransaction();
341 // To avoid pagebreak effect or strange behavior of writeHTMLCell when we are out of page, we imagine we are at the begin of page to test the height of the text
342 // Another solution would be to do the test on another PDF instance with samefont, width...
343 $pdf->setY(0);
344 // store starting values
345 $start_y = $pdf->GetY();
346 //var_dump($start_y);
347 $start_page = $pdf->getPage();
348 // call printing functions with content
349 $pdf->writeHTMLCell(0, 0, 0, $start_y, $htmlcontent, 0, 1, false, true, 'J', true);
350 // get the new Y
351 $end_y = $pdf->GetY();
352 $end_page = $pdf->getPage();
353 // calculate height
354 $height = 0;
355 if ($end_page == $start_page) {
356 $height = $end_y - $start_y;
357 } else {
358 for ($page = $start_page; $page <= $end_page; ++$page) {
359 $pdf->setPage($page);
360 $tmpm = $pdf->getMargins();
361 $tMargin = $tmpm['top'];
362 if ($page == $start_page) {
363 // first page
364 $height = $pdf->getPageHeight() - $start_y - $pdf->getBreakMargin();
365 } elseif ($page == $end_page) {
366 // last page
367 $height = $end_y - $tMargin;
368 } else {
369 $height = $pdf->getPageHeight() - $tMargin - $pdf->getBreakMargin();
370 }
371 }
372 }
373 // restore previous object
374 $pdf = $pdf->rollbackTransaction();
375
376 return $height;
377}
378
379
388function pdfBuildThirdpartyName($thirdparty, Translate $outputlangs, $includealias = 0)
389{
390 // Recipient name
391 $socname = '';
392
393 if ($thirdparty instanceof Societe) {
394 $socname = $thirdparty->name;
395 if (($includealias || getDolGlobalInt('PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME')) && !empty($thirdparty->name_alias)) {
396 if (getDolGlobalInt('PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME') == 2) {
397 $socname = $thirdparty->name_alias." - ".$thirdparty->name;
398 } else {
399 $socname = $thirdparty->name." - ".$thirdparty->name_alias;
400 }
401 }
402 } elseif ($thirdparty instanceof Contact) {
403 if ($thirdparty->socid > 0) {
404 $thirdparty->fetch_thirdparty();
405 $socname = $thirdparty->thirdparty->name;
406 if (($includealias || getDolGlobalInt('PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME')) && !empty($thirdparty->thirdparty->name_alias)) {
407 if (getDolGlobalInt('PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME') == 2) {
408 $socname = $thirdparty->thirdparty->name_alias." - ".$thirdparty->thirdparty->name;
409 } else {
410 $socname = $thirdparty->thirdparty->name." - ".$thirdparty->thirdparty->name_alias;
411 }
412 }
413 }
414 } else {
415 throw new InvalidArgumentException('Parameter 1 $thirdparty is not a Societe nor Contact');
416 }
417
418 return $outputlangs->convToOutputCharset((string) $socname);
419}
420
433function pdf_build_address($outputlangs, $sourcecompany, $targetcompany = '', $targetcontact = '', $usecontact = 0, $mode = 'source', $object = null)
434{
435 global $hookmanager;
436
437 if ($mode == 'source' && !is_object($sourcecompany)) {
438 return -1;
439 }
440 if ($mode == 'target' && !is_object($targetcompany)) {
441 return -1;
442 }
443
444 if (!empty($sourcecompany->state_id) && empty($sourcecompany->state)) {
445 $sourcecompany->state = getState($sourcecompany->state_id);
446 }
447 if (!empty($targetcompany->state_id) && empty($targetcompany->state)) {
448 $targetcompany->state = getState($targetcompany->state_id);
449 }
450
451 $reshook = 0;
452 $stringaddress = '';
453 if (is_object($hookmanager)) {
454 $parameters = array('sourcecompany' => &$sourcecompany, 'targetcompany' => &$targetcompany, 'targetcontact' => &$targetcontact, 'outputlangs' => $outputlangs, 'mode' => $mode, 'usecontact' => $usecontact);
455 $action = '';
456 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
457 $reshook = $hookmanager->executeHooks('pdf_build_address', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
458 $stringaddress .= $hookmanager->resPrint;
459 }
460 if (empty($reshook)) {
461 if ($mode == 'source') {
462 $withCountry = 0;
463 if (isset($targetcompany->country_code) && !empty($sourcecompany->country_code) && ($targetcompany->country_code != $sourcecompany->country_code)) {
464 $withCountry = 1;
465 }
466
467 $fulladdress = dol_format_address($sourcecompany, $withCountry, "\n", $outputlangs);
468 if ($fulladdress) {
469 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->convToOutputCharset($fulladdress)."\n";
470 }
471
472 if (!getDolGlobalString('MAIN_PDF_DISABLESOURCEDETAILS')) {
473 // Phone
474 if ($sourcecompany->phone) {
475 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("PhoneShort").": ".$outputlangs->convToOutputCharset($sourcecompany->phone);
476 }
477 // Phone mobile
478 if ($sourcecompany->phone_mobile && getDolGlobalString('MAIN_PDF_SHOW_SOURCE_PHONE_MOBILE')) {
479 $stringaddress .= ($stringaddress ? ($sourcecompany->phone ? " - " : "\n") : '').$outputlangs->transnoentities("PhoneShort").": ".$outputlangs->convToOutputCharset($sourcecompany->phone_mobile);
480 }
481 // Fax
482 if ($sourcecompany->fax) {
483 $stringaddress .= ($stringaddress ? ($sourcecompany->phone ? " - " : "\n") : '').$outputlangs->transnoentities("Fax").": ".$outputlangs->convToOutputCharset($sourcecompany->fax);
484 }
485 // EMail
486 if ($sourcecompany->email) {
487 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("Email").": ".$outputlangs->convToOutputCharset($sourcecompany->email);
488 }
489 // Web
490 if ($sourcecompany->url) {
491 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("Web").": ".$outputlangs->convToOutputCharset($sourcecompany->url);
492 }
493 }
494 // Intra VAT
495 if (getDolGlobalString('MAIN_TVAINTRA_IN_SOURCE_ADDRESS')) {
496 if ($sourcecompany->tva_intra) {
497 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("VATIntraShort").': '.$outputlangs->convToOutputCharset($sourcecompany->tva_intra);
498 }
499 }
500 // Professional Ids
501 $reg = array();
502 if (getDolGlobalString('MAIN_PROFID1_IN_SOURCE_ADDRESS') && !empty($sourcecompany->idprof1)) {
503 $tmp = $outputlangs->transcountrynoentities("ProfId1", $sourcecompany->country_code);
504 if (preg_match('/\‍((.+)\‍)/', $tmp, $reg)) {
505 $tmp = $reg[1];
506 }
507 $stringaddress .= ($stringaddress ? "\n" : '').$tmp.': '.$outputlangs->convToOutputCharset($sourcecompany->idprof1);
508 }
509 if (getDolGlobalString('MAIN_PROFID2_IN_SOURCE_ADDRESS') && !empty($sourcecompany->idprof2)) {
510 $tmp = $outputlangs->transcountrynoentities("ProfId2", $sourcecompany->country_code);
511 if (preg_match('/\‍((.+)\‍)/', $tmp, $reg)) {
512 $tmp = $reg[1];
513 }
514 $stringaddress .= ($stringaddress ? "\n" : '').$tmp.': '.$outputlangs->convToOutputCharset($sourcecompany->idprof2);
515 }
516 if (getDolGlobalString('MAIN_PROFID3_IN_SOURCE_ADDRESS') && !empty($sourcecompany->idprof3)) {
517 $tmp = $outputlangs->transcountrynoentities("ProfId3", $sourcecompany->country_code);
518 if (preg_match('/\‍((.+)\‍)/', $tmp, $reg)) {
519 $tmp = $reg[1];
520 }
521 $stringaddress .= ($stringaddress ? "\n" : '').$tmp.': '.$outputlangs->convToOutputCharset($sourcecompany->idprof3);
522 }
523 if (getDolGlobalString('MAIN_PROFID4_IN_SOURCE_ADDRESS') && !empty($sourcecompany->idprof4)) {
524 $tmp = $outputlangs->transcountrynoentities("ProfId4", $sourcecompany->country_code);
525 if (preg_match('/\‍((.+)\‍)/', $tmp, $reg)) {
526 $tmp = $reg[1];
527 }
528 $stringaddress .= ($stringaddress ? "\n" : '').$tmp.': '.$outputlangs->convToOutputCharset($sourcecompany->idprof4);
529 }
530 if (getDolGlobalString('MAIN_PROFID5_IN_SOURCE_ADDRESS') && !empty($sourcecompany->idprof5)) {
531 $tmp = $outputlangs->transcountrynoentities("ProfId5", $sourcecompany->country_code);
532 if (preg_match('/\‍((.+)\‍)/', $tmp, $reg)) {
533 $tmp = $reg[1];
534 }
535 $stringaddress .= ($stringaddress ? "\n" : '').$tmp.': '.$outputlangs->convToOutputCharset($sourcecompany->idprof5);
536 }
537 if (getDolGlobalString('MAIN_PROFID6_IN_SOURCE_ADDRESS') && !empty($sourcecompany->idprof6)) {
538 $tmp = $outputlangs->transcountrynoentities("ProfId6", $sourcecompany->country_code);
539 if (preg_match('/\‍((.+)\‍)/', $tmp, $reg)) {
540 $tmp = $reg[1];
541 }
542 $stringaddress .= ($stringaddress ? "\n" : '').$tmp.': '.$outputlangs->convToOutputCharset($sourcecompany->idprof6);
543 }
544 if (getDolGlobalString('PDF_ADD_MORE_AFTER_SOURCE_ADDRESS')) {
545 $stringaddress .= ($stringaddress ? "\n" : '') . getDolGlobalString('PDF_ADD_MORE_AFTER_SOURCE_ADDRESS');
546 }
547 }
548
549 if ($mode == 'target' || preg_match('/targetwithdetails/', $mode)) {
550 if ($usecontact && (is_object($targetcontact))) {
551 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->convToOutputCharset($targetcontact->getFullName($outputlangs, 1));
552
553 if (!empty($targetcontact->address)) {
554 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->convToOutputCharset(dol_format_address($targetcontact))."\n";
555 } elseif (is_object($targetcompany)) {
556 $companytouseforaddress = $targetcompany;
557
558 // Contact on a thirdparty that is a different thirdparty than the thirdparty of object
559 if ($targetcontact->socid > 0 && $targetcontact->socid != $targetcompany->id) {
560 $targetcontact->fetch_thirdparty();
561 $companytouseforaddress = $targetcontact->thirdparty;
562 }
563
564 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->convToOutputCharset(dol_format_address($companytouseforaddress))."\n";
565 }
566 // Country
567 if (!empty($targetcontact->country_code) && $targetcontact->country_code != $sourcecompany->country_code) {
568 $stringaddress .= (($stringaddress && !getDolGlobalString('MAIN_PDF_REMOVE_BREAK_BEFORE_COUNTRY')) ? "\n" : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$targetcontact->country_code));
569 } elseif (empty($targetcontact->country_code) && !empty($targetcompany->country_code) && ($targetcompany->country_code != $sourcecompany->country_code)) {
570 $stringaddress .= (($stringaddress && !getDolGlobalString('MAIN_PDF_REMOVE_BREAK_BEFORE_COUNTRY')) ? "\n" : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$targetcompany->country_code));
571 }
572
573 if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || preg_match('/targetwithdetails/', $mode)) {
574 // Phone
575 if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_phone/', $mode)) {
576 if (!empty($targetcontact->phone_pro) || !empty($targetcontact->phone_mobile)) {
577 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("Phone").": ";
578 }
579 if (!empty($targetcontact->phone_pro)) {
580 $stringaddress .= $outputlangs->convToOutputCharset($targetcontact->phone_pro);
581 }
582 if (!empty($targetcontact->phone_pro) && !empty($targetcontact->phone_mobile)) {
583 $stringaddress .= " / ";
584 }
585 if (!empty($targetcontact->phone_mobile)) {
586 $stringaddress .= $outputlangs->convToOutputCharset($targetcontact->phone_mobile);
587 }
588 }
589 // Fax
590 if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_fax/', $mode)) {
591 if ($targetcontact->fax) {
592 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("Fax").": ".$outputlangs->convToOutputCharset($targetcontact->fax);
593 }
594 }
595 // EMail
596 if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_email/', $mode)) {
597 if ($targetcontact->email) {
598 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("Email").": ".$outputlangs->convToOutputCharset($targetcontact->email);
599 }
600 }
601 // Web
602 if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_url/', $mode)) {
603 if ($targetcontact->url) {
604 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("Web").": ".$outputlangs->convToOutputCharset((string) $targetcontact->url);
605 }
606 }
607 }
608 } else {
609 if (is_object($targetcompany)) {
610 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->convToOutputCharset(dol_format_address($targetcompany));
611 // Country
612 if (!empty($targetcompany->country_code) && $targetcompany->country_code != $sourcecompany->country_code) {
613 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$targetcompany->country_code));
614 } else {
615 $stringaddress .= ($stringaddress ? "\n" : '');
616 }
617
618 if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || preg_match('/targetwithdetails/', $mode)) {
619 // Phone
620 if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_phone/', $mode)) {
621 if (!empty($targetcompany->phone) || !empty($targetcompany->phone_mobile)) {
622 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("Phone").": ";
623 }
624 if (!empty($targetcompany->phone)) {
625 $stringaddress .= $outputlangs->convToOutputCharset($targetcompany->phone);
626 }
627 if (!empty($targetcompany->phone) && !empty($targetcompany->phone_mobile)) {
628 $stringaddress .= " / ";
629 }
630 if (!empty($targetcompany->phone_mobile)) {
631 $stringaddress .= $outputlangs->convToOutputCharset($targetcompany->phone_mobile);
632 }
633 }
634 // Fax
635 if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_fax/', $mode)) {
636 if ($targetcompany->fax) {
637 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("Fax").": ".$outputlangs->convToOutputCharset($targetcompany->fax);
638 }
639 }
640 // EMail
641 if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_email/', $mode)) {
642 if ($targetcompany->email) {
643 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("Email").": ".$outputlangs->convToOutputCharset($targetcompany->email);
644 }
645 }
646 // Web
647 if (getDolGlobalString('MAIN_PDF_ADDALSOTARGETDETAILS') || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_url/', $mode)) {
648 if ($targetcompany->url) {
649 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("Web").": ".$outputlangs->convToOutputCharset($targetcompany->url);
650 }
651 }
652 }
653 }
654 }
655
656 // Intra VAT
657 if (!getDolGlobalString('MAIN_TVAINTRA_NOT_IN_ADDRESS')) {
658 if ($usecontact && is_object($targetcontact) && getDolGlobalInt('MAIN_USE_COMPANY_NAME_OF_CONTACT')) {
659 $targetcontact->fetch_thirdparty();
660 if (!empty($targetcontact->thirdparty->id) && $targetcontact->thirdparty->tva_intra) {
661 $stringaddress .= ($stringaddress ? "\n" : '') . $outputlangs->transnoentities("VATIntraShort") . ': ' . $outputlangs->convToOutputCharset($targetcontact->thirdparty->tva_intra);
662 }
663 } elseif (!empty($targetcompany->tva_intra)) {
664 $stringaddress .= ($stringaddress ? "\n" : '').$outputlangs->transnoentities("VATIntraShort").': '.$outputlangs->convToOutputCharset($targetcompany->tva_intra);
665 }
666 }
667
668 // Legal form
669 if (getDolGlobalString('MAIN_LEGALFORM_IN_ADDRESS') && !empty($targetcompany->forme_juridique_code)) {
670 $tmp = getFormeJuridiqueLabel((string) $targetcompany->forme_juridique_code);
671 $stringaddress .= ($stringaddress ? "\n" : '').$tmp;
672 }
673
674 // Professional Ids
675 if (getDolGlobalString('MAIN_PROFID1_IN_ADDRESS') && !empty($targetcompany->idprof1)) {
676 $tmp = $outputlangs->transcountrynoentities("ProfId1", $targetcompany->country_code);
677 if (preg_match('/\‍((.+)\‍)/', $tmp, $reg)) {
678 $tmp = $reg[1];
679 }
680 $stringaddress .= ($stringaddress ? "\n" : '').$tmp.': '.$outputlangs->convToOutputCharset($targetcompany->idprof1);
681 }
682 if (getDolGlobalString('MAIN_PROFID2_IN_ADDRESS') && !empty($targetcompany->idprof2)) {
683 $tmp = $outputlangs->transcountrynoentities("ProfId2", $targetcompany->country_code);
684 if (preg_match('/\‍((.+)\‍)/', $tmp, $reg)) {
685 $tmp = $reg[1];
686 }
687 $stringaddress .= ($stringaddress ? "\n" : '').$tmp.': '.$outputlangs->convToOutputCharset($targetcompany->idprof2);
688 }
689 if (getDolGlobalString('MAIN_PROFID3_IN_ADDRESS') && !empty($targetcompany->idprof3)) {
690 $tmp = $outputlangs->transcountrynoentities("ProfId3", $targetcompany->country_code);
691 if (preg_match('/\‍((.+)\‍)/', $tmp, $reg)) {
692 $tmp = $reg[1];
693 }
694 $stringaddress .= ($stringaddress ? "\n" : '').$tmp.': '.$outputlangs->convToOutputCharset($targetcompany->idprof3);
695 }
696 if (getDolGlobalString('MAIN_PROFID4_IN_ADDRESS') && !empty($targetcompany->idprof4)) {
697 $tmp = $outputlangs->transcountrynoentities("ProfId4", $targetcompany->country_code);
698 if (preg_match('/\‍((.+)\‍)/', $tmp, $reg)) {
699 $tmp = $reg[1];
700 }
701 $stringaddress .= ($stringaddress ? "\n" : '').$tmp.': '.$outputlangs->convToOutputCharset($targetcompany->idprof4);
702 }
703 if (getDolGlobalString('MAIN_PROFID5_IN_ADDRESS') && !empty($targetcompany->idprof5)) {
704 $tmp = $outputlangs->transcountrynoentities("ProfId5", $targetcompany->country_code);
705 if (preg_match('/\‍((.+)\‍)/', $tmp, $reg)) {
706 $tmp = $reg[1];
707 }
708 $stringaddress .= ($stringaddress ? "\n" : '').$tmp.': '.$outputlangs->convToOutputCharset($targetcompany->idprof5);
709 }
710 if (getDolGlobalString('MAIN_PROFID6_IN_ADDRESS') && !empty($targetcompany->idprof6)) {
711 $tmp = $outputlangs->transcountrynoentities("ProfId6", $targetcompany->country_code);
712 if (preg_match('/\‍((.+)\‍)/', $tmp, $reg)) {
713 $tmp = $reg[1];
714 }
715 $stringaddress .= ($stringaddress ? "\n" : '').$tmp.': '.$outputlangs->convToOutputCharset($targetcompany->idprof6);
716 }
717
718 // Public note
719 if (getDolGlobalString('MAIN_PUBLIC_NOTE_IN_ADDRESS')) {
720 if ($mode == 'source' && !empty($sourcecompany->note_public)) {
721 $stringaddress .= ($stringaddress ? "\n" : '').dol_string_nohtmltag($sourcecompany->note_public);
722 }
723 if (($mode == 'target' || preg_match('/targetwithdetails/', $mode)) && !empty($targetcompany->note_public)) {
724 $stringaddress .= ($stringaddress ? "\n" : '').dol_string_nohtmltag($targetcompany->note_public);
725 }
726 }
727 }
728 }
729
730 return $stringaddress;
731}
732
733
742function pdf_pagehead(&$pdf, $outputlangs, $page_height)
743{
744 global $conf;
745
746 // Add a background image on document only if good setup of const
747 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
748 $filepath = $conf->mycompany->dir_output.'/logos/' . getDolGlobalString('MAIN_USE_BACKGROUND_ON_PDF');
749 if (file_exists($filepath)) {
750 $pdf->setAutoPageBreak(false, 0); // Disable auto pagebreak before adding image
751 if (getDolGlobalString('MAIN_USE_BACKGROUND_ON_PDF_ALPHA')) {
752 $pdf->SetAlpha(getDolGlobalFloat('MAIN_USE_BACKGROUND_ON_PDF_ALPHA'));
753 } // Option for change opacity of background
754 $pdf->Image($filepath, getDolGlobalFloat('MAIN_USE_BACKGROUND_ON_PDF_X'), getDolGlobalFloat('MAIN_USE_BACKGROUND_ON_PDF_Y'), 0, $page_height);
755 if (getDolGlobalString('MAIN_USE_BACKGROUND_ON_PDF_ALPHA')) {
756 $pdf->SetAlpha(1);
757 }
758 $pdf->SetPageMark(); // This option avoid to have the images missing on some pages
759 $pdf->setAutoPageBreak(true, 0); // Restore pagebreak
760 }
761 }
762 if (getDolGlobalString('MAIN_ADD_PDF_BACKGROUND') && getDolGlobalString('MAIN_ADD_PDF_BACKGROUND') != '-1') {
763 $pdf->SetPageMark(); // This option avoid to have the images missing on some pages
764 }
765}
766
767
780function pdfWriteBlockedLogSignature(&$pdf, $outputlangs, $page_height, $object, &$w, &$posx, &$posy)
781{
782 global $db;
783
784 // Transaction ID
785 include_once DOL_DOCUMENT_ROOT.'/blockedlog/lib/blockedlog.lib.php';
786
787 if (isALNERunningVersion() && isModEnabled('blockedlog')) {
788 if ($object->status > $object::STATUS_DRAFT) {
789 $unalterablelogid = 'UNDEFINED';
790 $sql = "SELECT signature FROM ".MAIN_DB_PREFIX."blockedlog";
791 $sql .= " WHERE action = 'BILL_VALIDATE' AND element = 'facture' AND ref_object = '".$db->escape($object->ref)."'";
792 $sql .= $db->order('rowid', 'DESC');
793 $sql .= $db->plimit(1);
794
795 $resql = $db->query($sql);
796 if ($resql) {
797 $obj = $db->fetch_object($resql);
798 if ($obj) {
799 $unalterablelogid = $obj->signature;
800 }
801 }
802
803 if ($unalterablelogid != 'UNDEFINED') {
804 $posy += 5;
805 $pdf->SetXY($posx, $posy);
806 $pdf->SetTextColor(0, 0, 60);
807 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("SignatureID")." : ".dol_trunc(strtoupper($unalterablelogid), 10), '', 'R');
808 }
809 }
810 }
811}
812
813
824function pdf_getSubstitutionArray($outputlangs, $exclude = null, $object = null, $onlykey = 0, $include = null)
825{
826 $substitutionarray = getCommonSubstitutionArray($outputlangs, $onlykey, $exclude, $object, $include);
827 $substitutionarray['__FROM_NAME__'] = '__FROM_NAME__';
828 $substitutionarray['__FROM_EMAIL__'] = '__FROM_EMAIL__';
829 return $substitutionarray;
830}
831
832
844function pdf_watermark(&$pdf, $outputlangs, $h, $w, $unit, $text)
845{
846 // Print Draft Watermark
847 if ($unit == 'pt') {
848 $k = 1;
849 } elseif ($unit == 'mm') {
850 $k = 72 / 25.4;
851 } elseif ($unit == 'cm') {
852 $k = 72 / 2.54;
853 } elseif ($unit == 'in') {
854 $k = 72;
855 } else {
856 $k = 1;
857 dol_print_error(null, 'Unexpected unit "'.$unit.'" for pdf_watermark');
858 }
859
860 // Make substitution
861 $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, null);
862 complete_substitutions_array($substitutionarray, $outputlangs, null);
863 $text = make_substitutions($text, $substitutionarray, $outputlangs);
864 $text = $outputlangs->convToOutputCharset($text);
865
866 $savx = $pdf->getX();
867 $savy = $pdf->getY();
868
869 $watermark_angle = atan($h / $w) / 2;
870 $watermark_x_pos = 0;
871 $watermark_y_pos = $h / 3;
872 $watermark_x = $w / 2;
873 $watermark_y = $h / 3;
874 $pdf->SetFont('', 'B', 40);
875 $pdf->SetTextColor(255, 0, 0);
876
877 // rotate
878 $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));
879 // print watermark
880 $pdf->SetAlpha(0.5);
881 $pdf->SetXY($watermark_x_pos, $watermark_y_pos);
882
883 // set alpha to semi-transparency
884 $pdf->SetAlpha(0.3);
885 $pdf->Cell($w - 20, 25, $outputlangs->convToOutputCharset($text), "", 2, "C", false);
886
887 // antirotate
888 $pdf->_out('Q');
889
890 $pdf->SetXY($savx, $savy);
891
892 // Restore alpha
893 $pdf->SetAlpha(1);
894}
895
896
908function pdfCertifMention(&$pdf, $outputlangs, $seller, $default_font_size, &$posy, $pdftemplate)
909{
910 include_once DOL_DOCUMENT_ROOT.'/blockedlog/lib/blockedlog.lib.php';
911
912 return pdfCertifMentionblockedLog($pdf, $outputlangs, $seller, $default_font_size, $posy, $pdftemplate);
913}
914
915
928function pdf_bank(&$pdf, $outputlangs, $curx, $cury, $account, $onlynumber = 0, $default_font_size = 10)
929{
930 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbank.class.php';
931
932 $diffsizetitle = getDolGlobalInt('PDF_DIFFSIZE_TITLE', 3);
933 $diffsizecontent = getDolGlobalInt('PDF_DIFFSIZE_CONTENT', 4);
934 $pdf->SetXY($curx, $cury);
935
936 if (empty($onlynumber)) {
937 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
938 $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByTransferOnThisBankAccount').':', 0, 'L', false);
939 $cury += 4;
940 }
941
942 $outputlangs->load("banks");
943
944 // Use correct name of bank id according to country
945 $bickey = "BICNumber";
946 if ($account->getCountryCode() == 'IN') {
947 $bickey = "SWIFT";
948 }
949
950 // Get format of bank account according to its country
951 $usedetailedbban = $account->useDetailedBBAN();
952
953 //$onlynumber=0; $usedetailedbban=1; // For tests
954 if ($usedetailedbban) {
955 $savcurx = $curx;
956
957 if (empty($onlynumber)) {
958 $pdf->SetFont('', '', $default_font_size - $diffsizecontent);
959 $pdf->SetXY($curx, $cury);
960 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Bank").': '.$outputlangs->convToOutputCharset($account->bank), 0, 'L', false);
961 $cury += 3;
962 }
963
964 if (!getDolGlobalString('PDF_BANK_HIDE_NUMBER_SHOW_ONLY_BICIBAN')) { // Note that some countries still need bank number, BIC/IBAN not enough for them
965 // Note:
966 // bank = code_banque (FR), sort code (GB, IR. Example: 12-34-56)
967 // desk = code guichet (FR), used only when $usedetailedbban = 1
968 // number = account number
969 // key = check control key used only when $usedetailedbban = 1
970 if (empty($onlynumber)) {
971 $pdf->line($curx + 1, $cury + 1, $curx + 1, $cury + 6);
972 }
973
974 $bank_number_length = 0;
975 foreach ($account->getFieldsToShow() as $val) {
976 $pdf->SetXY($curx, $cury + 4);
977 $pdf->SetFont('', '', $default_font_size - 3);
978
979 if ($val == 'BankCode') {
980 // Bank code
981 $tmplength = 18;
982 $content = $account->code_banque;
983 } elseif ($val == 'DeskCode') {
984 // Desk
985 $tmplength = 18;
986 $content = $account->code_guichet;
987 } elseif ($val == 'BankAccountNumber') {
988 // Number
989 $tmplength = 24;
990 $content = $account->number;
991 } elseif ($val == 'BankAccountNumberKey') {
992 // Key
993 $tmplength = 15;
994 $content = $account->cle_rib;
995 } elseif ($val == 'IBAN' || $val == 'BIC') {
996 // Key
997 $tmplength = 0;
998 $content = '';
999 } else {
1000 dol_print_error($account->db, 'Unexpected value for getFieldsToShow: '.$val);
1001 break;
1002 }
1003
1004 if ($content == '') {
1005 continue;
1006 }
1007
1008 $pdf->MultiCell($tmplength, 3, $outputlangs->convToOutputCharset($content), 0, 'C', false);
1009 $pdf->SetXY($curx, $cury + 1);
1010 $curx += $tmplength;
1011 $pdf->SetFont('', 'B', $default_font_size - $diffsizecontent);
1012 $pdf->MultiCell($tmplength, 3, $outputlangs->transnoentities($val), 0, 'C', false);
1013 if (empty($onlynumber)) {
1014 $pdf->line($curx, $cury + 1, $curx, $cury + 7);
1015 }
1016
1017 // Only set this variable when table was printed
1018 $bank_number_length = 8;
1019 }
1020
1021 $curx = $savcurx;
1022 $cury += $bank_number_length;
1023 }
1024 } elseif (!empty($account->number)) {
1025 $pdf->SetFont('', 'B', $default_font_size - $diffsizecontent);
1026 $pdf->SetXY($curx, $cury);
1027 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Bank").': '.$outputlangs->convToOutputCharset($account->bank), 0, 'L', false);
1028 $cury += 3;
1029
1030 $pdf->SetFont('', 'B', $default_font_size - $diffsizecontent);
1031 $pdf->SetXY($curx, $cury);
1032 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("BankAccountNumber").': '.$outputlangs->convToOutputCharset($account->number), 0, 'L', false);
1033 $cury += 3;
1034
1035 if ($diffsizecontent <= 2) {
1036 $cury += 1;
1037 }
1038 }
1039
1040 $pdf->SetFont('', '', $default_font_size - $diffsizecontent);
1041
1042 if (empty($onlynumber) && !empty($account->address)) {
1043 $pdf->SetXY($curx, $cury);
1044 $val = $outputlangs->transnoentities("Residence").': '.$outputlangs->convToOutputCharset($account->address);
1045 $pdf->MultiCell(100, 3, $val, 0, 'L', false);
1046 //$nboflines=dol_nboflines_bis($val,120);
1047 //$cury+=($nboflines*3)+2;
1048 $tmpy = $pdf->getStringHeight(100, $val);
1049 $cury += $tmpy;
1050 }
1051
1052 if (!empty($account->owner_name)) {
1053 $pdf->SetXY($curx, $cury);
1054 $val = $outputlangs->transnoentities("BankAccountOwner").': '.$outputlangs->convToOutputCharset($account->owner_name);
1055 $pdf->MultiCell(100, 3, $val, 0, 'L', false);
1056 $tmpy = $pdf->getStringHeight(100, $val);
1057 $cury += $tmpy;
1058 } elseif (!$usedetailedbban) {
1059 $cury += 1;
1060 }
1061
1062 // Use correct name of bank id according to country
1063 $ibankey = FormBank::getIBANLabel($account);
1064
1065 if (!empty($account->iban)) {
1066 //Remove whitespaces to ensure we are dealing with the format we expect
1067 $ibanDisplay_temp = str_replace(' ', '', $outputlangs->convToOutputCharset($account->iban));
1068 $ibanDisplay = "";
1069
1070 $nbIbanDisplay_temp = dol_strlen($ibanDisplay_temp);
1071 for ($i = 0; $i < $nbIbanDisplay_temp; $i++) {
1072 $ibanDisplay .= $ibanDisplay_temp[$i];
1073 if ($i % 4 == 3 && $i > 0) {
1074 $ibanDisplay .= " ";
1075 }
1076 }
1077
1078 $pdf->SetFont('', 'B', $default_font_size - 3);
1079 $pdf->SetXY($curx, $cury);
1080 $pdf->MultiCell(100, 3, $outputlangs->transnoentities($ibankey).': '.$ibanDisplay, 0, 'L', false);
1081 $cury += 3;
1082 }
1083
1084 if (!empty($account->bic)) {
1085 $pdf->SetFont('', 'B', $default_font_size - 3);
1086 $pdf->SetXY($curx, $cury);
1087 $pdf->MultiCell(100, 3, $outputlangs->transnoentities($bickey).': '.$outputlangs->convToOutputCharset($account->bic), 0, 'L', false);
1088 }
1089
1090 return $pdf->getY();
1091}
1092
1110function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_basse, $marge_gauche, $page_hauteur, $object, $showdetails = 0, $hidefreetext = 0, $page_largeur = 0, $watermark = '')
1111{
1112 global $conf, $hookmanager;
1113
1114 $outputlangs->load("dict");
1115 $line = '';
1116 $reg = array();
1117 $marginwithfooter = 0; // Return value
1118
1119 $dims = $pdf->getPageDimensions();
1120
1121 // Line of free text
1122 if (empty($hidefreetext) && getDolGlobalString($paramfreetext)) {
1123 $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
1124 // More substitution keys
1125 if (is_object($fromcompany)) {
1126 $substitutionarray['__FROM_NAME__'] = $fromcompany->name;
1127 $substitutionarray['__FROM_EMAIL__'] = $fromcompany->email;
1128 }
1129 complete_substitutions_array($substitutionarray, $outputlangs, $object);
1130 $newfreetext = make_substitutions(getDolGlobalString($paramfreetext), $substitutionarray, $outputlangs);
1131
1132 // Make a change into HTML code to allow to include images from medias directory.
1133 // <img alt="" src="/dolibarr_dev/htdocs/viewimage.php?modulepart=medias&amp;entity=1&amp;file=image/ldestailleur_166x166.jpg" style="height:166px; width:166px" />
1134 // become
1135 // <img alt="" src="'.DOL_DATA_ROOT.'/medias/image/ldestailleur_166x166.jpg" style="height:166px; width:166px" />
1136 $newfreetext = preg_replace('/(<img.*src=")[^\"]*viewimage\.php[^\"]*modulepart=medias[^\"]*file=([^\"]*)("[^\/]*\/>)/', '\1file:/'.DOL_DATA_ROOT.'/medias/\2\3', $newfreetext);
1137
1138 $line .= $outputlangs->convToOutputCharset($newfreetext);
1139 }
1140
1141 // First line of company infos
1142 $line1 = "";
1143 $line2 = "";
1144 $line3 = "";
1145 $line4 = "";
1146
1147 if (is_object($fromcompany) && in_array($showdetails, array(1, 3))) {
1148 // Company name
1149 if ($fromcompany->name) {
1150 $line1 .= ($line1 ? " - " : "").$outputlangs->transnoentities("RegisteredOffice").": ".$fromcompany->name;
1151 }
1152 // Address
1153 if ($fromcompany->address) {
1154 $line1 .= ($line1 ? " - " : "").str_replace("\n", ", ", $fromcompany->address);
1155 }
1156 // Zip code
1157 if ($fromcompany->zip) {
1158 $line1 .= ($line1 ? " - " : "").$fromcompany->zip;
1159 }
1160 // Town
1161 if ($fromcompany->town) {
1162 $line1 .= ($line1 ? " " : "").$fromcompany->town;
1163 }
1164 // Country
1165 if ($fromcompany->country) {
1166 $line1 .= ($line1 ? ", " : "").$fromcompany->country;
1167 }
1168 // Phone
1169 if ($fromcompany->phone) {
1170 $line2 .= ($line2 ? " - " : "").$outputlangs->transnoentities("Phone").": ".$fromcompany->phone;
1171 }
1172 // Fax
1173 if ($fromcompany->fax) {
1174 $line2 .= ($line2 ? " - " : "").$outputlangs->transnoentities("Fax").": ".$fromcompany->fax;
1175 }
1176
1177 // URL
1178 if ($fromcompany->url) {
1179 $line2 .= ($line2 ? " - " : "").$fromcompany->url;
1180 }
1181 // Email
1182 if ($fromcompany->email) {
1183 $line2 .= ($line2 ? " - " : "").$fromcompany->email;
1184 }
1185 }
1186 if ($showdetails == 2 || $showdetails == 3 || (!empty($fromcompany->country_code) && $fromcompany->country_code == 'DE')) {
1187 // Managers
1188 if ($fromcompany->managers) {
1189 $line2 .= ($line2 ? " - " : "").$fromcompany->managers;
1190 }
1191 }
1192
1193 // Line 3 of company infos
1194 // Juridical status
1195 if (!empty($fromcompany->forme_juridique_code)) {
1196 $line3 .= ($line3 ? " - " : "").$outputlangs->convToOutputCharset(getFormeJuridiqueLabel((string) $fromcompany->forme_juridique_code));
1197 }
1198 // Capital
1199 if (!empty($fromcompany->capital)) {
1200 $tmpamounttoshow = price2num($fromcompany->capital); // This field is a free string or a float
1201 if (is_numeric($tmpamounttoshow) && $tmpamounttoshow > 0) {
1202 $line3 .= ($line3 ? " - " : "").$outputlangs->transnoentities("CapitalOf", price($tmpamounttoshow, 0, $outputlangs, 0, 0, 0, getDolCurrency()));
1203 } elseif (!empty($fromcompany->capital)) {
1204 $line3 .= ($line3 ? " - " : "").$outputlangs->transnoentities("CapitalOf", (string) $fromcompany->capital);
1205 }
1206 }
1207 // Prof Id 1
1208 if (!empty($fromcompany->idprof1) && ($fromcompany->country_code != 'FR' || (empty($fromcompany->idprof2) || strpos($fromcompany->idprof2, $fromcompany->idprof1) !== 0))) {
1209 $field = $outputlangs->transcountrynoentities("ProfId1", $fromcompany->country_code);
1210 if (preg_match('/\‍((.*)\‍)/i', $field, $reg)) {
1211 $field = $reg[1];
1212 }
1213 $line3 .= ($line3 ? " - " : "").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof1);
1214 }
1215 // Prof Id 2
1216 if (!empty($fromcompany->idprof2)) {
1217 $field = $outputlangs->transcountrynoentities("ProfId2", $fromcompany->country_code);
1218 if (preg_match('/\‍((.*)\‍)/i', $field, $reg)) {
1219 $field = $reg[1];
1220 }
1221 $line3 .= ($line3 ? " - " : "").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof2);
1222 }
1223
1224 // Line 4 of company infos
1225 // Prof Id 3
1226 if (!empty($fromcompany->idprof3)) {
1227 $field = $outputlangs->transcountrynoentities("ProfId3", $fromcompany->country_code);
1228 if (preg_match('/\‍((.*)\‍)/i', $field, $reg)) {
1229 $field = $reg[1];
1230 }
1231 $line4 .= ($line4 ? " - " : "").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof3);
1232 }
1233 // Prof Id 4
1234 if (!empty($fromcompany->idprof4)) {
1235 $field = $outputlangs->transcountrynoentities("ProfId4", $fromcompany->country_code);
1236 if (preg_match('/\‍((.*)\‍)/i', $field, $reg)) {
1237 $field = $reg[1];
1238 }
1239 $line4 .= ($line4 ? " - " : "").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof4);
1240 }
1241 // Prof Id 5
1242 if (!empty($fromcompany->idprof5)) {
1243 $field = $outputlangs->transcountrynoentities("ProfId5", $fromcompany->country_code);
1244 if (preg_match('/\‍((.*)\‍)/i', $field, $reg)) {
1245 $field = $reg[1];
1246 }
1247 $line4 .= ($line4 ? " - " : "").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof5);
1248 }
1249 // Prof Id 6
1250 if (!empty($fromcompany->idprof6)) {
1251 $field = $outputlangs->transcountrynoentities("ProfId6", $fromcompany->country_code);
1252 if (preg_match('/\‍((.*)\‍)/i', $field, $reg)) {
1253 $field = $reg[1];
1254 }
1255 $line4 .= ($line4 ? " - " : "").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof6);
1256 }
1257 // Prof Id 7
1258 if (!empty($fromcompany->idprof7)) {
1259 $field = $outputlangs->transcountrynoentities("ProfId7", $fromcompany->country_code);
1260 if (preg_match('/\‍((.*)\‍)/i', $field, $reg)) {
1261 $field = $reg[1];
1262 }
1263 $line4 .= ($line4 ? " - " : "").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof7);
1264 }
1265 // Prof Id 8
1266 if (!empty($fromcompany->idprof8)) {
1267 $field = $outputlangs->transcountrynoentities("ProfId8", $fromcompany->country_code);
1268 if (preg_match('/\‍((.*)\‍)/i', $field, $reg)) {
1269 $field = $reg[1];
1270 }
1271 $line4 .= ($line4 ? " - " : "").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof8);
1272 }
1273 // Prof Id 9
1274 if (!empty($fromcompany->idprof9)) {
1275 $field = $outputlangs->transcountrynoentities("ProfId9", $fromcompany->country_code);
1276 if (preg_match('/\‍((.*)\‍)/i', $field, $reg)) {
1277 $field = $reg[1];
1278 }
1279 $line4 .= ($line4 ? " - " : "").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof9);
1280 }
1281 // Prof Id 10
1282 if (!empty($fromcompany->idprof10)) {
1283 $field = $outputlangs->transcountrynoentities("ProfId10", $fromcompany->country_code);
1284 if (preg_match('/\‍((.*)\‍)/i', $field, $reg)) {
1285 $field = $reg[1];
1286 }
1287 $line4 .= ($line4 ? " - " : "").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof10);
1288 }
1289 // IntraCommunautary VAT
1290 if (!empty($fromcompany->tva_intra) && $fromcompany->tva_intra != '') {
1291 $line4 .= ($line4 ? " - " : "").$outputlangs->transnoentities("VATIntraShort").": ".$outputlangs->convToOutputCharset($fromcompany->tva_intra);
1292 }
1293
1294 $pdf->SetFont('', '', 7);
1295 $pdf->SetDrawColor(224, 224, 224);
1296 // Option for footer text color
1297 if (getDolGlobalString('PDF_FOOTER_TEXT_COLOR')) {
1298 $tmparray = sscanf(getDolGlobalString('PDF_FOOTER_TEXT_COLOR'), '%d, %d, %d');
1299 $r = $tmparray[0];
1300 $g = $tmparray[1];
1301 $b = $tmparray[2];
1302 $pdf->SetTextColor($r, $g, $b);
1303 }
1304
1305 // The start of the bottom of this page footer is positioned according to # of lines
1306 $freetextheight = 0;
1307 $align = '';
1308 if ($line) { // Free text
1309 //$line="sample text<br>\nfd<strong>sf</strong>sdf<br>\nghfghg<br>";
1310 if (!getDolGlobalString('PDF_ALLOW_HTML_FOR_FREE_TEXT')) {
1311 $width = 20000;
1312 $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.
1313 if (getDolGlobalString('MAIN_USE_AUTOWRAP_ON_FREETEXT')) {
1314 $width = 200;
1315 $align = 'C';
1316 }
1317 $freetextheight = $pdf->getStringHeight($width, $line);
1318 } else {
1319 $freetextheight = pdfGetHeightForHtmlContent($pdf, dol_htmlentitiesbr($line, 1, 'UTF-8', 0)); // New method (works for HTML content)
1320 //print '<br>'.$freetextheight;
1321 }
1322 }
1323
1324 $posy = 0;
1325 // For customized footer
1326 if (is_object($hookmanager)) {
1327 $parameters = array('line1' => $line1, 'line2' => $line2, 'line3' => $line3, 'line4' => $line4, 'outputlangs' => $outputlangs);
1328 $action = '';
1329 $hookmanager->executeHooks('pdf_pagefoot', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
1330 if (!empty($hookmanager->resPrint) && $hidefreetext == 0) {
1331 $mycustomfooter = $hookmanager->resPrint;
1332 $mycustomfooterheight = pdfGetHeightForHtmlContent($pdf, dol_htmlentitiesbr($mycustomfooter, 1, 'UTF-8', 0));
1333
1334 $marginwithfooter = $marge_basse + $freetextheight + $mycustomfooterheight;
1335 $posy = (float) $marginwithfooter;
1336
1337 // Option for footer background color (without freetext zone)
1338 if (getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR')) {
1339 $tmparray = sscanf(getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR'), '%d, %d, %d');
1340 $r = $tmparray[0];
1341 $g = $tmparray[1];
1342 $b = $tmparray[2];
1343 $pdf->setAutoPageBreak(false, 0); // Disable auto pagebreak
1344 $pdf->Rect(0, $dims['hk'] - $posy + $freetextheight, $dims['wk'] + 1, $marginwithfooter + 1, 'F', array(), $fill_color = array($r, $g, $b));
1345 $pdf->setAutoPageBreak(true, 0); // Restore pagebreak
1346 }
1347
1348 if (getDolGlobalInt('PDF_FREETEXT_DISABLE_PAGEBREAK') === 1) {
1349 $pdf->setAutoPageBreak(false, 0);
1350 } // Option for disable auto pagebreak
1351 if ($line) { // Free text
1352 $pdf->SetXY($dims['lm'], -$posy);
1353 if (!getDolGlobalString('PDF_ALLOW_HTML_FOR_FREE_TEXT')) { // by default
1354 $pdf->MultiCell(0, 3, $line, 0, $align, false);
1355 } else {
1356 $pdf->writeHTMLCell($dims['wk'] - $dims['lm'] - $dims['rm'], $freetextheight, $dims['lm'], $dims['hk'] - $marginwithfooter, dol_htmlentitiesbr($line, 1, 'UTF-8', 0));
1357 }
1358 $posy -= $freetextheight;
1359 }
1360 if (getDolGlobalInt('PDF_FREETEXT_DISABLE_PAGEBREAK') === 1) {
1361 $pdf->setAutoPageBreak(true, 0);
1362 } // Restore pagebreak
1363
1364 $pdf->SetY(-$posy);
1365
1366 // Hide footer line if footer background color is set
1367 if (!getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR')) {
1368 $pdf->line($dims['lm'], $dims['hk'] - $posy, $dims['wk'] - $dims['rm'], $dims['hk'] - $posy);
1369 }
1370
1371 // Option for set top margin height of footer after freetext
1372 if (getDolGlobalString('PDF_FOOTER_TOP_MARGIN') || getDolGlobalInt('PDF_FOOTER_TOP_MARGIN') === 0) {
1373 $posy -= (float) getDolGlobalString('PDF_FOOTER_TOP_MARGIN');
1374 } else {
1375 $posy--;
1376 }
1377
1378 if (getDolGlobalInt('PDF_FOOTER_DISABLE_PAGEBREAK') === 1) {
1379 $pdf->setAutoPageBreak(false, 0);
1380 } // Option for disable auto pagebreak
1381 $pdf->writeHTMLCell($dims['wk'] - $dims['lm'] - $dims['rm'], $mycustomfooterheight, $dims['lm'], $dims['hk'] - $posy, dol_htmlentitiesbr($mycustomfooter, 1, 'UTF-8', 0));
1382 if (getDolGlobalInt('PDF_FOOTER_DISABLE_PAGEBREAK') === 1) {
1383 $pdf->setAutoPageBreak(true, 0);
1384 } // Restore pagebreak
1385
1386 $posy -= $mycustomfooterheight - 3;
1387 } else {
1388 // Else default footer
1389 $marginwithfooter = $marge_basse + $freetextheight + (!empty($line1) ? 3 : 0) + (!empty($line2) ? 3 : 0) + (!empty($line3) ? 3 : 0) + (!empty($line4) ? 3 : 0);
1390 $posy = (float) $marginwithfooter;
1391
1392 // Option for footer background color (without freetext zone)
1393 if (getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR')) {
1394 $tmparray = sscanf(getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR'), '%d, %d, %d');
1395 $r = $tmparray[0];
1396 $g = $tmparray[1];
1397 $b = $tmparray[2];
1398 $pdf->setAutoPageBreak(false, 0); // Disable auto pagebreak
1399 $pdf->Rect(0, $dims['hk'] - $posy + $freetextheight, $dims['wk'] + 1, $marginwithfooter + 1, 'F', array(), $fill_color = array($r, $g, $b));
1400 $pdf->setAutoPageBreak(true, 0); // Restore pagebreak
1401 }
1402
1403 if (getDolGlobalInt('PDF_FREETEXT_DISABLE_PAGEBREAK') === 1) {
1404 $pdf->setAutoPageBreak(false, 0);
1405 } // Option for disable auto pagebreak
1406 if ($line) { // Free text
1407 $pdf->SetXY($dims['lm'], -$posy);
1408 if (!getDolGlobalString('PDF_ALLOW_HTML_FOR_FREE_TEXT')) { // by default
1409 $pdf->MultiCell(0, 3, $line, 0, $align, false);
1410 } else {
1411 $pdf->writeHTMLCell($dims['wk'] - $dims['lm'] - $dims['rm'], $freetextheight, $dims['lm'], $dims['hk'] - $marginwithfooter, dol_htmlentitiesbr($line, 1, 'UTF-8', 0));
1412 }
1413 $posy -= $freetextheight;
1414 }
1415 if (getDolGlobalInt('PDF_FREETEXT_DISABLE_PAGEBREAK') === 1) {
1416 $pdf->setAutoPageBreak(true, 0);
1417 } // Restore pagebreak
1418
1419 $pdf->SetY(-$posy);
1420
1421 // Option for hide all footer (page number will no hidden)
1422 if (!getDolGlobalInt('PDF_FOOTER_HIDDEN')) {
1423 // Hide footer line if footer background color is set
1424 if (!getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR')) {
1425 $pdf->line($dims['lm'], $dims['hk'] - $posy, $dims['wk'] - $dims['rm'], $dims['hk'] - $posy);
1426 }
1427
1428 // Option for set top margin height of footer after freetext
1429 if (getDolGlobalString('PDF_FOOTER_TOP_MARGIN') || getDolGlobalInt('PDF_FOOTER_TOP_MARGIN') === 0) {
1430 $posy -= (float) getDolGlobalString('PDF_FOOTER_TOP_MARGIN');
1431 } else {
1432 $posy--;
1433 }
1434
1435 if (!empty($line1)) {
1436 $pdf->SetFont('', 'B', 7);
1437 $pdf->SetXY($dims['lm'], -$posy);
1438 $pdf->MultiCell($dims['wk'] - $dims['rm'] - $dims['lm'], 2, $line1, 0, 'C', false);
1439 $posy -= 3;
1440 $pdf->SetFont('', '', 7);
1441 }
1442
1443 if (!empty($line2)) {
1444 $pdf->SetFont('', 'B', 7);
1445 $pdf->SetXY($dims['lm'], -$posy);
1446 $pdf->MultiCell($dims['wk'] - $dims['rm'] - $dims['lm'], 2, $line2, 0, 'C', false);
1447 $posy -= 3;
1448 $pdf->SetFont('', '', 7);
1449 }
1450
1451 if (!empty($line3)) {
1452 $pdf->SetXY($dims['lm'], -$posy);
1453 $pdf->MultiCell($dims['wk'] - $dims['rm'] - $dims['lm'], 2, $line3, 0, 'C', false);
1454 }
1455
1456 if (!empty($line4)) {
1457 $posy -= 3;
1458 $pdf->SetXY($dims['lm'], -$posy);
1459 $pdf->MultiCell($dims['wk'] - $dims['rm'] - $dims['lm'], 2, $line4, 0, 'C', false);
1460 }
1461 }
1462 }
1463 }
1464
1465 // Show page nb and apply correction for some font.
1466 $pdf->SetXY($dims['wk'] - $dims['rm'] - 18 - getDolGlobalInt('PDF_FOOTER_PAGE_NUMBER_X', 0), -$posy - getDolGlobalInt('PDF_FOOTER_PAGE_NUMBER_Y', 0));
1467
1468 $pagination = $pdf->PageNo().' / '.$pdf->getAliasNbPages();
1469 $fontRenderCorrection = 0;
1470 if (in_array(pdf_getPDFFont($outputlangs), array('freemono', 'DejaVuSans'))) {
1471 $fontRenderCorrection = 10;
1472 }
1473 $pdf->MultiCell(18 + $fontRenderCorrection, 2, $pagination, 0, 'R', false);
1474
1475 // Show Draft Watermark
1476 if (!empty($watermark)) {
1477 pdf_watermark($pdf, $outputlangs, $page_hauteur, $page_largeur, 'mm', $watermark);
1478 }
1479
1480 return $marginwithfooter;
1481}
1482
1497function pdf_writeLinkedObjects(&$pdf, $object, $outputlangs, $posx, $posy, $w, $h, $align, $default_font_size)
1498{
1499 $linkedobjects = pdf_getLinkedObjects($object, $outputlangs); // May update $object->note_public
1500
1501 if (!empty($linkedobjects)) {
1502 foreach ($linkedobjects as $linkedobject) {
1503 $reftoshow = $linkedobject["ref_title"].' : '.$linkedobject["ref_value"];
1504 if (!empty($linkedobject["date_value"])) {
1505 $reftoshow .= ' / '.$linkedobject["date_value"];
1506 }
1507
1508 $posy += 3;
1509 $pdf->SetXY($posx, $posy);
1510 $pdf->SetFont('', '', (float) $default_font_size - 2);
1511 $pdf->MultiCell($w, $h, $reftoshow, '', $align);
1512 }
1513 }
1514
1515 return $pdf->getY();
1516}
1517
1535function pdf_writelinedesc(&$pdf, $object, $i, $outputlangs, $w, $h, $posx, $posy, $hideref = 0, $hidedesc = 0, $issupplierline = 0, $align = 'J')
1536{
1537 global $hookmanager;
1538
1539 $reshook = 0;
1540 $result = '';
1541 //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) ) )
1542 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
1543 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
1544 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
1545 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1546 }
1547 $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);
1548 $action = '';
1549 // WARNING: A hook must not close/open the PDF transaction. Doing this generates a lot of trouble.
1550 // Test to know if content added by the hooks is already done by the main caller of pdf_writelinedesc
1551 $reshook = $hookmanager->executeHooks('pdf_writelinedesc', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
1552
1553 if (!empty($hookmanager->resPrint)) {
1554 $result .= $hookmanager->resPrint;
1555 }
1556 }
1557 if (empty($reshook)) {
1558 $labelproductservice = pdf_getlinedesc($object, $i, $outputlangs, $hideref, $hidedesc, $issupplierline);
1559 $labelproductservice = preg_replace('/(<img[^>]*src=")[^\"]*viewimage\.php[^\"]*modulepart=medias[^\"]*file=([^\"]*)/', '\1file:/'.DOL_DATA_ROOT.'/medias/\2\3', $labelproductservice, -1, $nbrep);
1560
1561 //var_dump($labelproductservice);exit;
1562
1563 // 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"
1564 // We make the reverse, so PDF generation has the real URL.
1565 $nbrep = 0;
1566 $labelproductservice = preg_replace('/(<img[^>]*src=")([^"]*)(&amp;)([^"]*")/', '\1\2&\4', $labelproductservice, -1, $nbrep);
1567
1568 if (getDolGlobalString('MARGIN_TOP_ZERO_UL')) {
1569 $pdf->setListIndentWidth(5);
1570 $TMarginList = ['ul' => [['h' => 0.1, ],['h' => 0.1, ]], 'li' => [['h' => 0.1, ],],];
1571 $pdf->setHtmlVSpace($TMarginList);
1572 }
1573
1574 // Description
1575 $pdf->writeHTMLCell($w, $h, $posx, $posy, $outputlangs->convToOutputCharset($labelproductservice), 0, 1, false, true, $align, true);
1576 $result .= $labelproductservice;
1577 }
1578 return $result;
1579}
1580
1592function pdf_getlinedesc($object, $i, $outputlangs, $hideref = 0, $hidedesc = 0, $issupplierline = 0)
1593{
1594 global $db, $conf, $langs;
1595
1596 $idprod = (!empty($object->lines[$i]->fk_product) ? $object->lines[$i]->fk_product : false);
1597 $label = (!empty($object->lines[$i]->label) ? $object->lines[$i]->label : (!empty($object->lines[$i]->product_label) ? $object->lines[$i]->product_label : ''));
1598 $product_barcode = (!empty($object->lines[$i]->product_barcode) ? $object->lines[$i]->product_barcode : "");
1599 $desc = (!empty($object->lines[$i]->desc) ? $object->lines[$i]->desc : (!empty($object->lines[$i]->description) ? $object->lines[$i]->description : ''));
1600 $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
1601 $note = (!empty($object->lines[$i]->note) ? $object->lines[$i]->note : '');
1602 $dbatch = (!empty($object->lines[$i]->detail_batch) ? $object->lines[$i]->detail_batch : false);
1603
1604 $multilangsactive = getDolGlobalInt('MAIN_MULTILANGS');
1605
1606 if ($issupplierline) {
1607 include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
1608 $prodser = new ProductFournisseur($db);
1609 } else {
1610 include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1611 $prodser = new Product($db);
1612
1613 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
1614 include_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php';
1615 }
1616 }
1617
1618 //id
1619 $idprod = (!empty($object->lines[$i]->fk_product) ? $object->lines[$i]->fk_product : false);
1620 if ($idprod) {
1621 $prodser->fetch($idprod);
1622 //load multilangs
1623 if ($multilangsactive) {
1624 $prodser->getMultiLangs();
1625 $object->lines[$i]->multilangs = $prodser->multilangs;
1626 }
1627 }
1628 //label
1629 if (!empty($object->lines[$i]->label)) {
1630 $label = $object->lines[$i]->label;
1631 } else {
1632 if (!empty($object->lines[$i]->multilangs[$outputlangs->defaultlang]['label']) && $multilangsactive) {
1633 $label = $object->lines[$i]->multilangs[$outputlangs->defaultlang]['label'];
1634 } else {
1635 if (!empty($object->lines[$i]->product_label)) {
1636 $label = $object->lines[$i]->product_label;
1637 } else {
1638 $label = '';
1639 }
1640 }
1641 }
1642 //description
1643 if (!empty($object->lines[$i]->desc)) {
1644 $desc = $object->lines[$i]->desc;
1645 } else {
1646 if (!empty($object->lines[$i]->multilangs[$outputlangs->defaultlang]['description']) && $multilangsactive) {
1647 $desc = $object->lines[$i]->multilangs[$outputlangs->defaultlang]['description'];
1648 } else {
1649 if (!empty($object->lines[$i]->description)) {
1650 $desc = $object->lines[$i]->description;
1651 } else {
1652 $desc = '';
1653 }
1654 }
1655 }
1656 //ref supplier
1657 $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
1658 //note
1659 $note = (!empty($object->lines[$i]->note) ? $object->lines[$i]->note : '');
1660 //dbatch
1661 $dbatch = (!empty($object->lines[$i]->detail_batch) ? $object->lines[$i]->detail_batch : false);
1662
1663 if ($idprod) {
1664 // If a predefined product and multilang and on other lang, we renamed label with label translated
1665 if ($multilangsactive && ($outputlangs->defaultlang != $langs->defaultlang)) {
1666 $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)
1667
1668 // 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
1669 // ($textwasnotmodified is replaced with $textwasmodifiedorcompleted and we add completion).
1670
1671 // Set label
1672 // 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.
1673 //var_dump($outputlangs->defaultlang.' - '.$langs->defaultlang.' - '.$label.' - '.$prodser->label);exit;
1674 $textwasnotmodified = ($label == $prodser->label);
1675 if (!empty($prodser->multilangs[$outputlangs->defaultlang]["label"]) && ($textwasnotmodified || $translatealsoifmodified)) {
1676 $label = $prodser->multilangs[$outputlangs->defaultlang]["label"];
1677 }
1678
1679 // Set desc
1680 // Manage HTML entities description test because $prodser->description is store with htmlentities but $desc no
1681 $textwasnotmodified = false;
1682 $textdiffersonlybymarkup = false;
1683 if (!empty($desc) && dol_textishtml($desc) && !empty($prodser->description) && dol_textishtml($prodser->description)) {
1684 $textwasnotmodified = (strpos(dol_html_entity_decode($desc, ENT_QUOTES | ENT_HTML5), dol_html_entity_decode($prodser->description, ENT_QUOTES | ENT_HTML5)) !== false);
1685 } elseif (!empty($desc) && !empty($prodser->description) && dol_textishtml($desc) != dol_textishtml($prodser->description)) {
1686 // One side is HTML and the other is not. This happens as soon as a line is saved while the
1687 // WYSIWYG editor is enabled on line details: the plain product description becomes "<p>...</p>".
1688 // Comparing the raw strings would then report a manual change and silently drop the translation,
1689 // so compare the text content instead.
1690 $desctextonly = trim(dol_html_entity_decode(dol_string_nohtmltag($desc, 1), ENT_QUOTES | ENT_HTML5));
1691 $prodtextonly = trim(dol_html_entity_decode(dol_string_nohtmltag($prodser->description, 1), ENT_QUOTES | ENT_HTML5));
1692 $textwasnotmodified = ($prodtextonly !== '' && strpos($desctextonly, $prodtextonly) !== false);
1693 $textdiffersonlybymarkup = ($textwasnotmodified && $desctextonly === $prodtextonly);
1694 } else {
1695 $textwasnotmodified = ($desc == $prodser->description);
1696 }
1697 if (!empty($prodser->multilangs[$outputlangs->defaultlang]["description"])) {
1698 if ($textwasnotmodified) {
1699 if ($textdiffersonlybymarkup && strpos($desc, $prodser->description) === false) {
1700 // Same text, but wrapped in tags or written with HTML entities: the product description
1701 // is not present verbatim, so the str_replace below would find nothing to replace.
1702 $desc = $prodser->multilangs[$outputlangs->defaultlang]["description"];
1703 } else {
1704 $desc = str_replace($prodser->description, $prodser->multilangs[$outputlangs->defaultlang]["description"], $desc);
1705 }
1706 } elseif ($translatealsoifmodified) {
1707 $desc = $prodser->multilangs[$outputlangs->defaultlang]["description"];
1708 }
1709 }
1710
1711 // Set note
1712 $textwasnotmodified = ($note == $prodser->note_public);
1713 if (!empty($prodser->multilangs[$outputlangs->defaultlang]["other"]) && ($textwasnotmodified || $translatealsoifmodified)) {
1714 $note = $prodser->multilangs[$outputlangs->defaultlang]["other"];
1715 }
1716 }
1717 } 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
1718 $desc = str_replace('(DEPOSIT)', $outputlangs->trans('Deposit'), $desc);
1719 }
1720
1721 $libelleproduitservice = ''; // Default value
1722 if (!getDolGlobalString('PDF_HIDE_PRODUCT_LABEL_IN_SUPPLIER_LINES')) {
1723 // Description short of product line
1724 $libelleproduitservice = $label;
1725 if (!empty($libelleproduitservice) && getDolGlobalString('PDF_BOLD_PRODUCT_LABEL')) {
1726 // Adding <b> may convert the original string into a HTML string. So we have to first
1727 // convert \n into <br> we text is not already HTML.
1728 if (!dol_textishtml($libelleproduitservice)) {
1729 $libelleproduitservice = str_replace("\n", '<br>', $libelleproduitservice);
1730 }
1731 $libelleproduitservice = '<b>'.$libelleproduitservice.'</b>';
1732 }
1733 }
1734
1735
1736 // Add ref of subproducts
1737 if (getDolGlobalString('SHOW_SUBPRODUCT_REF_IN_PDF')) {
1738 $prodser->get_sousproduits_arbo();
1739 if (!empty($prodser->sousprods) && is_array($prodser->sousprods) && count($prodser->sousprods)) {
1740 $outputlangs->load('mrp');
1741 $tmparrayofsubproducts = reset($prodser->sousprods);
1742
1743 $qtyText = null;
1744 if (isset($object->lines[$i]->qty) && !empty($object->lines[$i]->qty)) {
1745 $qtyText = $object->lines[$i]->qty;
1746 } elseif (isset($object->lines[$i]->qty_shipped) && !empty($object->lines[$i]->qty_shipped)) {
1747 $qtyText = $object->lines[$i]->qty;
1748 }
1749
1750 if (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF')) {
1751 foreach ($tmparrayofsubproducts as $subprodval) {
1752 $libelleproduitservice = dol_concatdesc(
1753 dol_concatdesc($libelleproduitservice, " * ".$subprodval[3]),
1754 (!empty($qtyText) ?
1755 $outputlangs->trans('Qty').':'.$qtyText.' x '.$outputlangs->trans('AssociatedProducts').':'.$subprodval[1].'= '.$outputlangs->trans('QtyTot').':'.$subprodval[1] * $qtyText :
1756 $outputlangs->trans('Qty').' '.$outputlangs->trans('AssociatedProducts').':'.$subprodval[1])
1757 );
1758 }
1759 } else {
1760 foreach ($tmparrayofsubproducts as $subprodval) {
1761 $libelleproduitservice = dol_concatdesc(
1762 dol_concatdesc($libelleproduitservice, " * ".$subprodval[5].(($subprodval[5] && $subprodval[3]) ? ' - ' : '').$subprodval[3]),
1763 (!empty($qtyText) ?
1764 $outputlangs->trans('Qty').':'.$qtyText.' x '.$outputlangs->trans('AssociatedProducts').':'.$subprodval[1].'= '.$outputlangs->trans('QtyTot').':'.$subprodval[1] * $qtyText :
1765 $outputlangs->trans('Qty').' '.$outputlangs->trans('AssociatedProducts').':'.$subprodval[1])
1766 );
1767 }
1768 }
1769 }
1770 }
1771
1772 if (isModEnabled('barcode') && getDolGlobalString('MAIN_GENERATE_DOCUMENTS_SHOW_PRODUCT_BARCODE') && !empty($product_barcode)) {
1773 $libelleproduitservice = dol_concatdesc($libelleproduitservice, $outputlangs->trans("BarCode")." ".$product_barcode);
1774 }
1775
1776 // Description long of product line
1777 if (!empty($desc) && ($desc != $label)) {
1778 if ($desc == '(CREDIT_NOTE)' && $object->lines[$i]->fk_remise_except) {
1779 $discount = new DiscountAbsolute($db);
1780 $discount->fetch($object->lines[$i]->fk_remise_except);
1781 $sourceref = !empty($discount->discount_type) ? $discount->ref_invoice_supplier_source : $discount->ref_facture_source;
1782 $libelleproduitservice = $outputlangs->transnoentitiesnoconv("DiscountFromCreditNote", $sourceref);
1783 } elseif ($desc == '(DEPOSIT)' && $object->lines[$i]->fk_remise_except) {
1784 $discount = new DiscountAbsolute($db);
1785 $discount->fetch($object->lines[$i]->fk_remise_except);
1786 $sourceref = !empty($discount->discount_type) ? $discount->ref_invoice_supplier_source : $discount->ref_facture_source;
1787 $libelleproduitservice = $outputlangs->transnoentitiesnoconv("DiscountFromDeposit", $sourceref);
1788 // Add date of deposit
1789 if (getDolGlobalString('INVOICE_ADD_DEPOSIT_DATE')) {
1790 $libelleproduitservice .= ' ('.dol_print_date($discount->datec, 'day', '', $outputlangs).')';
1791 }
1792 } elseif ($desc == '(EXCESS RECEIVED)' && $object->lines[$i]->fk_remise_except) {
1793 $discount = new DiscountAbsolute($db);
1794 $discount->fetch($object->lines[$i]->fk_remise_except);
1795 $libelleproduitservice = $outputlangs->transnoentitiesnoconv("DiscountFromExcessReceived", $discount->ref_facture_source);
1796 } elseif ($desc == '(EXCESS PAID)' && $object->lines[$i]->fk_remise_except) {
1797 $discount = new DiscountAbsolute($db);
1798 $discount->fetch($object->lines[$i]->fk_remise_except);
1799 $libelleproduitservice = $outputlangs->transnoentitiesnoconv("DiscountFromExcessPaid", $discount->ref_invoice_supplier_source);
1800 } else {
1801 if ($idprod) {
1802 // Check if description must be output
1803 if (!empty($object->element)) {
1804 $tmpkey = 'MAIN_DOCUMENTS_HIDE_DESCRIPTION_FOR_'.strtoupper($object->element);
1805 if (getDolGlobalString($tmpkey)) {
1806 $hidedesc = 1;
1807 }
1808 }
1809 if (empty($hidedesc)) {
1810 if (getDolGlobalString('MAIN_DOCUMENTS_DESCRIPTION_FIRST')) {
1811 $libelleproduitservice = dol_concatdesc($desc, $libelleproduitservice);
1812 } else {
1813 if (getDolGlobalString('HIDE_LABEL_VARIANT_PDF') && $prodser->isVariant()) {
1814 $libelleproduitservice = $desc;
1815 } else {
1816 $libelleproduitservice = dol_concatdesc($libelleproduitservice, $desc);
1817 }
1818 }
1819 }
1820 } else {
1821 $libelleproduitservice = dol_concatdesc($libelleproduitservice, $desc);
1822 }
1823 }
1824 }
1825
1826 // We add ref of product (and supplier ref if defined)
1827 $prefix_prodserv = "";
1828 $ref_prodserv = "";
1829 if (getDolGlobalString('PRODUCT_ADD_TYPE_IN_DOCUMENTS')) { // In standard mode, we do not show this
1830 if ($prodser->isService()) {
1831 $prefix_prodserv = $outputlangs->transnoentitiesnoconv("Service")." ";
1832 } else {
1833 $prefix_prodserv = $outputlangs->transnoentitiesnoconv("Product")." ";
1834 }
1835 }
1836
1837 if (empty($hideref)) {
1838 if ($issupplierline) {
1839 if (!getDolGlobalString('PDF_HIDE_PRODUCT_REF_IN_SUPPLIER_LINES')) { // Common case
1840 $ref_prodserv = $prodser->ref; // Show local ref
1841 if ($ref_supplier) {
1842 $ref_prodserv .= ($prodser->ref ? ' (' : '').$outputlangs->transnoentitiesnoconv("SupplierRef").' '.$ref_supplier.($prodser->ref ? ')' : '');
1843 }
1844 } elseif (getDolGlobalInt('PDF_HIDE_PRODUCT_REF_IN_SUPPLIER_LINES') == 1) {
1845 $ref_prodserv = $ref_supplier;
1846 } elseif (getDolGlobalInt('PDF_HIDE_PRODUCT_REF_IN_SUPPLIER_LINES') == 2) {
1847 $ref_prodserv = $ref_supplier.' ('.$outputlangs->transnoentitiesnoconv("InternalRef").' '.$prodser->ref.')';
1848 }
1849 } else {
1850 $ref_prodserv = $prodser->ref; // Show local ref only
1851
1852 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
1853 $productCustomerPriceStatic = new ProductCustomerPrice($db);
1854 $filter = array('fk_product' => (string) $idprod, 'fk_soc' => (string) $object->socid);
1855
1856 $nbCustomerPrices = $productCustomerPriceStatic->fetchAll('', '', 1, 0, $filter);
1857
1858 if ($nbCustomerPrices > 0) {
1859 $productCustomerPrice = null;
1860 if (count($productCustomerPriceStatic->lines) > 0) {
1861 $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours
1862 foreach ($productCustomerPriceStatic->lines as $k => $custprice_line) {
1863 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
1864 $productCustomerPrice = $custprice_line;
1865 break;
1866 }
1867 }
1868 }
1869
1870 if (isset($productCustomerPrice) && !empty($productCustomerPrice->ref_customer)) {
1871 $idcustprice = getDolGlobalInt('PRODUIT_CUSTOMER_PRICES_PDF_REF_MODE');
1872 switch ($idcustprice) {
1873 case 1:
1874 $ref_prodserv = $productCustomerPrice->ref_customer;
1875 break;
1876
1877 case 2:
1878 $ref_prodserv = $productCustomerPrice->ref_customer . ' (' . $outputlangs->transnoentitiesnoconv('InternalRef') . ' ' . $ref_prodserv . ')';
1879 break;
1880
1881 default:
1882 $ref_prodserv = $ref_prodserv . ' (' . $outputlangs->transnoentitiesnoconv('RefCustomer') . ' ' . $productCustomerPrice->ref_customer . ')';
1883 }
1884 }
1885 }
1886 }
1887 }
1888
1889 if (!empty($libelleproduitservice) && !empty($ref_prodserv)) {
1890 $ref_prodserv .= " - ";
1891 }
1892 }
1893
1894 if (!empty($ref_prodserv) && getDolGlobalString('PDF_BOLD_PRODUCT_REF_AND_PERIOD')) {
1895 if (!dol_textishtml($libelleproduitservice)) {
1896 $libelleproduitservice = str_replace("\n", '<br>', $libelleproduitservice);
1897 }
1898 $ref_prodserv = '<b>'.$ref_prodserv.'</b>';
1899 // $prefix_prodserv and $ref_prodser are not HTML var
1900 }
1901 $libelleproduitservice = $prefix_prodserv.$ref_prodserv.$libelleproduitservice;
1902
1903 // Add an additional description for the category products
1904 if (getDolGlobalString('CATEGORY_ADD_DESC_INTO_DOC') && $idprod && isModEnabled('category')) {
1905 include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1906 $categstatic = new Categorie($db);
1907 // recovering the list of all the categories linked to product
1908 $tblcateg = $categstatic->containing($idprod, Categorie::TYPE_PRODUCT);
1909 foreach ($tblcateg as $cate) {
1910 // Adding the descriptions if they are filled
1911 $desccateg = $cate->description;
1912 if ($desccateg) {
1913 $libelleproduitservice = dol_concatdesc($libelleproduitservice, $desccateg);
1914 }
1915 }
1916 }
1917
1918 if (!empty($object->lines[$i]->date_start) || !empty($object->lines[$i]->date_end)) {
1919 $format = 'day';
1920 $period = '';
1921 // Show duration if exists
1922 if ($object->lines[$i]->date_start && $object->lines[$i]->date_end) {
1923 $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)).')';
1924 }
1925 if ($object->lines[$i]->date_start && !$object->lines[$i]->date_end) {
1926 $period = '('.$outputlangs->transnoentitiesnoconv('DateFrom', dol_print_date($object->lines[$i]->date_start, $format, false, $outputlangs)).')';
1927 }
1928 if (!$object->lines[$i]->date_start && $object->lines[$i]->date_end) {
1929 $period = '('.$outputlangs->transnoentitiesnoconv('DateUntil', dol_print_date($object->lines[$i]->date_end, $format, false, $outputlangs)).')';
1930 }
1931 //print '>'.$outputlangs->charset_output.','.$period;
1932 if (getDolGlobalString('PDF_BOLD_PRODUCT_REF_AND_PERIOD')) {
1933 if (!dol_textishtml($libelleproduitservice)) {
1934 $libelleproduitservice = str_replace("\n", '<br>', $libelleproduitservice);
1935 }
1936 $libelleproduitservice .= '<br><b style="color:#333666;" ><em>'.$period.'</em></b>';
1937 } else {
1938 $libelleproduitservice = dol_concatdesc($libelleproduitservice, $period);
1939 }
1940 //print $libelleproduitservice;
1941 }
1942
1943 // Show information for lot
1944 if (!empty($dbatch)) {
1945 // $object is a shipment.
1946 //var_dump($object->lines[$i]->details_entrepot); // array from llx_expeditiondet (we can have several lines for one fk_origin_line)
1947 //var_dump($object->lines[$i]->detail_batch); // array from llx_expeditiondet_batch (each line with a lot is linked to llx_expeditiondet)
1948
1949 include_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
1950 include_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php';
1951 $tmpwarehouse = new Entrepot($db);
1952 $tmpproductbatch = new Productbatch($db);
1953
1954 $format = 'day';
1955 foreach ($dbatch as $detail) {
1956 $dte = array();
1957 if ($detail->eatby) {
1958 $dte[] = $outputlangs->transnoentitiesnoconv('printEatby', dol_print_date($detail->eatby, $format, false, $outputlangs));
1959 }
1960 if ($detail->sellby) {
1961 $dte[] = $outputlangs->transnoentitiesnoconv('printSellby', dol_print_date($detail->sellby, $format, false, $outputlangs));
1962 }
1963 if ($detail->batch) {
1964 $dte[] = $outputlangs->transnoentitiesnoconv('printBatch', $detail->batch);
1965 }
1966 if ($detail->qty) {
1967 $dte[] = $outputlangs->transnoentitiesnoconv('printQty', (string) $detail->qty);
1968 }
1969
1970 // Add also info of planned warehouse for lot
1971 if ($object->element == 'shipping' && $detail->fk_origin_stock > 0 && getDolGlobalInt('PRODUCTBATCH_SHOW_WAREHOUSE_ON_SHIPMENT')) {
1972 $resproductbatch = $tmpproductbatch->fetch($detail->fk_origin_stock);
1973 if ($resproductbatch > 0) {
1974 $reswarehouse = $tmpwarehouse->fetch($tmpproductbatch->warehouseid);
1975 if ($reswarehouse > 0) {
1976 $dte[] = $tmpwarehouse->ref;
1977 }
1978 }
1979 }
1980
1981 $libelleproduitservice .= "__N__ ".implode(" - ", $dte);
1982 }
1983 } else {
1984 if (getDolGlobalInt('PRODUCTBATCH_SHOW_WAREHOUSE_ON_SHIPMENT')) {
1985 // TODO Show warehouse for shipment line without batch
1986 }
1987 }
1988
1989 // Now we convert \n into br
1990 if (dol_textishtml($libelleproduitservice)) {
1991 $libelleproduitservice = preg_replace('/__N__/', '<br>', $libelleproduitservice);
1992 } else {
1993 $libelleproduitservice = preg_replace('/__N__/', "\n", $libelleproduitservice);
1994 }
1995 $libelleproduitservice = dol_htmlentitiesbr($libelleproduitservice, 1);
1996
1997 return $libelleproduitservice;
1998}
1999
2009function pdf_getlinenum($object, $i, $outputlangs, $hidedetails = 0)
2010{
2011 global $hookmanager;
2012
2013 $reshook = 0;
2014 $result = '';
2015 //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) ) )
2016 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
2017 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2018 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2019 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2020 }
2021 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2022 $action = '';
2023 $reshook = $hookmanager->executeHooks('pdf_getlinenum', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2024 $result .= $hookmanager->resPrint;
2025 }
2026 if (empty($reshook)) {
2027 $result .= dol_htmlentitiesbr($object->lines[$i]->num);
2028 }
2029 return $result;
2030}
2031
2032
2042function pdf_getlineref($object, $i, $outputlangs, $hidedetails = 0)
2043{
2044 global $hookmanager;
2045
2046 $reshook = 0;
2047 $result = '';
2048 //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) ) )
2049 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
2050 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2051 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2052 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2053 }
2054 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2055 $action = '';
2056 $reshook = $hookmanager->executeHooks('pdf_getlineref', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2057 $result .= $hookmanager->resPrint;
2058 }
2059 if (empty($reshook)) {
2060 $result .= dol_htmlentitiesbr($object->lines[$i]->product_ref);
2061 }
2062 return $result;
2063}
2064
2065
2075function pdf_getlineref_supplier($object, $i, $outputlangs, $hidedetails = 0)
2076{
2077 global $hookmanager;
2078
2079 $reshook = 0;
2080 $result = '';
2081 //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) ) )
2082 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
2083 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2084 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2085 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2086 }
2087 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2088 $action = '';
2089 $reshook = $hookmanager->executeHooks('pdf_getlineref_supplier', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2090 $result .= $hookmanager->resPrint;
2091 }
2092 if (empty($reshook)) {
2093 $result .= dol_htmlentitiesbr($object->lines[$i]->ref_supplier);
2094 }
2095 return $result;
2096}
2097
2107function pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails = 0)
2108{
2109 global $conf, $hookmanager, $mysoc;
2110
2111 $result = '';
2112 $reshook = 0;
2113 //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) ) )
2114 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
2115 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2116 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2117 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2118 }
2119 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2120 $action = '';
2121 $reshook = $hookmanager->executeHooks('pdf_getlinevatrate', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2122
2123 if (!empty($hookmanager->resPrint)) {
2124 $result .= $hookmanager->resPrint;
2125 }
2126 }
2127 if (empty($reshook)) {
2128 if (empty($hidedetails) || $hidedetails > 1) {
2129 $tmpresult = '';
2130
2131 $tmpresult .= vatrate($object->lines[$i]->tva_tx, false, $object->lines[$i]->info_bits, -1);
2132 if (!getDolGlobalString('MAIN_PDF_MAIN_HIDE_SECOND_TAX')) {
2133 if (price2num($object->lines[$i]->localtax1_tx)) {
2134 if (preg_replace('/[\s0%]/', '', $tmpresult)) {
2135 $tmpresult .= '/';
2136 } else {
2137 $tmpresult = '';
2138 }
2139 $tmpresult .= vatrate((string) abs($object->lines[$i]->localtax1_tx), false);
2140 }
2141 }
2142 if (!getDolGlobalString('MAIN_PDF_MAIN_HIDE_THIRD_TAX')) {
2143 if (price2num($object->lines[$i]->localtax2_tx)) {
2144 if (preg_replace('/[\s0%]/', '', $tmpresult)) {
2145 $tmpresult .= '/';
2146 } else {
2147 $tmpresult = '';
2148 }
2149 $tmpresult .= vatrate((string) abs($object->lines[$i]->localtax2_tx), false);
2150 }
2151 }
2152 $tmpresult .= '%';
2153
2154 $result .= $tmpresult;
2155 }
2156 }
2157 return $result;
2158}
2159
2169function pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails = 0)
2170{
2171 global $hookmanager;
2172
2173 $sign = 1;
2174 if (isset($object->type) && $object->type == 2 && getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE')) {
2175 $sign = -1;
2176 }
2177
2178 $result = '';
2179 $reshook = 0;
2180 //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) ) )
2181 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
2182 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2183 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2184 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2185 }
2186 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2187 $action = '';
2188 $reshook = $hookmanager->executeHooks('pdf_getlineupexcltax', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2189
2190 if (!empty($hookmanager->resPrint)) {
2191 $result .= $hookmanager->resPrint;
2192 }
2193 }
2194 if (empty($reshook)) {
2195 if (empty($hidedetails) || $hidedetails > 1) {
2196 $subprice = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1 ? $object->lines[$i]->multicurrency_subprice : $object->lines[$i]->subprice);
2197 $result .= price($sign * $subprice, 0, $outputlangs);
2198 }
2199 }
2200 return $result;
2201}
2202
2212function pdf_getlineupwithtax($object, $i, $outputlangs, $hidedetails = 0)
2213{
2214 global $hookmanager;
2215
2216 $sign = 1;
2217 if (isset($object->type) && $object->type == 2 && getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE')) {
2218 $sign = -1;
2219 }
2220
2221 $result = '';
2222 $reshook = 0;
2223 //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) ) )
2224 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
2225 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2226 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2227 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2228 }
2229 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2230 $action = '';
2231 $reshook = $hookmanager->executeHooks('pdf_getlineupwithtax', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2232
2233 if (!empty($hookmanager->resPrint)) {
2234 $result .= $hookmanager->resPrint;
2235 }
2236 }
2237 if (empty($reshook)) {
2238 if (empty($hidedetails) || $hidedetails > 1) {
2239 $result .= price($sign * (($object->lines[$i]->subprice) + ($object->lines[$i]->subprice) * ($object->lines[$i]->tva_tx) / 100), 0, $outputlangs);
2240 }
2241 }
2242 return $result;
2243}
2244
2254function pdf_getlineqty($object, $i, $outputlangs, $hidedetails = 0)
2255{
2256 global $hookmanager;
2257
2258 $result = '';
2259 $reshook = 0;
2260 //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) ) )
2261 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
2262 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2263 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2264 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2265 }
2266 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2267 $action = '';
2268 $reshook = $hookmanager->executeHooks('pdf_getlineqty', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2269
2270 if (!empty($hookmanager->resPrint)) {
2271 $result = $hookmanager->resPrint;
2272 }
2273 }
2274 if (empty($reshook)) {
2275 if ($object->lines[$i]->special_code == 3) {
2276 return '';
2277 }
2278 if (empty($hidedetails) || $hidedetails > 1) {
2279 $result .= $object->lines[$i]->qty;
2280 }
2281 }
2282 return $result;
2283}
2284
2294function pdf_getlineqty_asked($object, $i, $outputlangs, $hidedetails = 0)
2295{
2296 global $hookmanager;
2297
2298 $reshook = 0;
2299 $result = '';
2300 //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) ) )
2301 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
2302 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2303 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2304 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2305 }
2306 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2307 $action = '';
2308 $reshook = $hookmanager->executeHooks('pdf_getlineqty_asked', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2309
2310 if (!empty($hookmanager->resPrint)) {
2311 $result .= $hookmanager->resPrint;
2312 }
2313 }
2314 if (empty($reshook)) {
2315 if ($object->lines[$i]->special_code == 3) {
2316 return '';
2317 }
2318 if (empty($hidedetails) || $hidedetails > 1) {
2319 $result .= $object->lines[$i]->qty_asked;
2320 }
2321 }
2322 return $result;
2323}
2324
2334function pdf_getlineqty_shipped($object, $i, $outputlangs, $hidedetails = 0)
2335{
2336 global $hookmanager;
2337
2338 $reshook = 0;
2339 $result = '';
2340 //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) ) )
2341 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
2342 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2343 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2344 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2345 }
2346 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2347 $action = '';
2348 $reshook = $hookmanager->executeHooks('pdf_getlineqty_shipped', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2349
2350 if (!empty($hookmanager->resPrint)) {
2351 $result .= $hookmanager->resPrint;
2352 }
2353 }
2354 if (empty($reshook)) {
2355 if ($object->lines[$i]->special_code == 3) {
2356 return '';
2357 }
2358 if (empty($hidedetails) || $hidedetails > 1) {
2359 $result .= $object->lines[$i]->qty_shipped;
2360 }
2361 }
2362 return $result;
2363}
2364
2374function pdf_getlineqty_keeptoship($object, $i, $outputlangs, $hidedetails = 0)
2375{
2376 global $hookmanager;
2377
2378 $reshook = 0;
2379 $result = '';
2380 //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) ) )
2381 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
2382 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2383 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) { // @phan-suppress-current-line PhanUndeclaredProperty
2384 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2385 }
2386 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2387 $action = '';
2388 $reshook = $hookmanager->executeHooks('pdf_getlineqty_keeptoship', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2389
2390 if (!empty($hookmanager->resPrint)) {
2391 $result .= $hookmanager->resPrint;
2392 }
2393 }
2394 if (empty($reshook)) {
2395 if ($object->lines[$i]->special_code == 3) {
2396 return '';
2397 }
2398 if (empty($hidedetails) || $hidedetails > 1) {
2399 $result .= ($object->lines[$i]->qty_asked - $object->lines[$i]->qty_shipped);
2400 }
2401 }
2402 return $result;
2403}
2404
2414function pdf_getlineunit($object, $i, $outputlangs, $hidedetails = 0)
2415{
2416 global $hookmanager;
2417
2418 $reshook = 0;
2419 $result = '';
2420 //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) ) )
2421 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
2422 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2423 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2424 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2425 }
2426 $parameters = array(
2427 'i' => $i,
2428 'outputlangs' => $outputlangs,
2429 'hidedetails' => $hidedetails,
2430 'special_code' => $special_code
2431 );
2432 $action = '';
2433 $reshook = $hookmanager->executeHooks('pdf_getlineunit', $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 (empty($hidedetails) || $hidedetails > 1) {
2441 $result .= $object->lines[$i]->getLabelOfUnit('short', $outputlangs, 1);
2442 }
2443 }
2444 return $result;
2445}
2446
2447
2457function pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails = 0)
2458{
2459 global $hookmanager;
2460
2461 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
2462
2463 $reshook = 0;
2464 $result = '';
2465 //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) ) )
2466 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
2467 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2468 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2469 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2470 }
2471 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2472 $action = '';
2473 $reshook = $hookmanager->executeHooks('pdf_getlineremisepercent', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2474
2475 if (!empty($hookmanager->resPrint)) {
2476 $result .= $hookmanager->resPrint;
2477 }
2478 }
2479 if (empty($reshook)) {
2480 if ($object->lines[$i]->special_code == 3) {
2481 return '';
2482 }
2483 if (empty($hidedetails) || $hidedetails > 1) {
2484 $result .= dol_print_reduction($object->lines[$i]->remise_percent, $outputlangs);
2485 }
2486 }
2487 return $result;
2488}
2489
2500function pdf_getlineprogress($object, $i, $outputlangs, $hidedetails = 0, $hookmanager = null)
2501{
2502 if (empty($hookmanager)) {
2503 global $hookmanager;
2504 }
2505
2506 $reshook = 0;
2507 $result = '';
2508 //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) ) )
2509 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
2510 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2511 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2512 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2513 }
2514 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2515 $action = '';
2516 $reshook = $hookmanager->executeHooks('pdf_getlineprogress', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2517
2518 if (!empty($hookmanager->resPrint)) {
2519 return $hookmanager->resPrint;
2520 }
2521 }
2522 if (empty($reshook)) {
2523 if ($object->lines[$i]->special_code == 3) {
2524 return '';
2525 }
2526 if (empty($hidedetails) || $hidedetails > 1) {
2527 // 2 = situation_percent is non-cumulative (delta of current situation)
2528 // 1 = (old mode): situation_percent is cumulative (state at situation)
2529 $isCumulative = getDolGlobalInt('INVOICE_USE_SITUATION') === 1;
2530 $showDelta = (bool) getDolGlobalInt('SITUATION_DISPLAY_DIFF_ON_PDF');
2531
2532 if ($isCumulative xor $showDelta) {
2533 // Either:
2534 // - old mode and we want to show a total or
2535 // - new mode and we want to show a delta
2536 $result = $object->lines[$i]->situation_percent;
2537 } else {
2538 // Either:
2539 // - old mode but we want to show a delta or
2540 // - new mode but we want to show a total
2541 $prev_progress = 0;
2542 if ($isCumulative) {
2543 // old mode: the previous line already holds the running total
2544 if (method_exists($object->lines[$i], 'get_prev_progress')) {
2545 $prev_progress = $object->lines[$i]->get_prev_progress($object->id);
2546 }
2547 } else {
2548 // new mode: each line holds its own delta, so we must sum every previous one.
2549 // get_prev_progress() only reads the line pointed by fk_prev_id, which is the last
2550 // delta and not the accumulated progress, so it under-reports from the third
2551 // situation on. getAllPrevProgress() walks the whole fk_prev_id chain, and it is
2552 // what the screen uses to compute the same value.
2553 if (method_exists($object->lines[$i], 'getAllPrevProgress')) {
2554 $prev_progress = $object->lines[$i]->getAllPrevProgress($object->id);
2555 } elseif (method_exists($object->lines[$i], 'get_prev_progress')) {
2556 $prev_progress = $object->lines[$i]->get_prev_progress($object->id);
2557 }
2558 }
2559 $result = $isCumulative ?
2560 // old mode: we need to compute the delta (total - sum of previous)
2561 $object->lines[$i]->situation_percent - $prev_progress :
2562 // new mode: we need to compute the total (sum of previous + delta)
2563 $prev_progress + $object->lines[$i]->situation_percent;
2564 }
2565 $result = round($result, 1).'%';
2566 }
2567 }
2568 return $result;
2569}
2570
2580function pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails = 0)
2581{
2582 global $hookmanager;
2583
2584 $sign = 1;
2585 if (isset($object->type) && $object->type == 2 && getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE')) {
2586 $sign = -1;
2587 }
2588
2589 $reshook = 0;
2590 $result = '';
2591 //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) ) )
2592 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
2593 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2594 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2595 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2596 }
2597 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code, 'sign' => $sign);
2598 $action = '';
2599 $reshook = $hookmanager->executeHooks('pdf_getlinetotalexcltax', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2600
2601 if (!empty($hookmanager->resPrint)) {
2602 $result .= $hookmanager->resPrint;
2603 }
2604 }
2605 if (empty($reshook)) {
2606 if (!empty($object->lines[$i]) && $object->lines[$i]->special_code == 3) {
2607 $result .= $outputlangs->transnoentities("Option");
2608 } elseif (empty($hidedetails) || $hidedetails > 1) {
2609 $total_ht = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1 ? $object->lines[$i]->multicurrency_total_ht : $object->lines[$i]->total_ht);
2610 if (!empty($object->lines[$i]->situation_percent) && $object->lines[$i]->situation_percent > 0) {
2611 if (method_exists($object->lines[$i], 'getSituationRatio')) {
2612 $total_ht *= $object->lines[$i]->getSituationRatio();
2613 }
2614 }
2615 $result .= price($sign * $total_ht, 0, $outputlangs);
2616 }
2617 }
2618 return $result;
2619}
2620
2630function pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails = 0)
2631{
2632 global $hookmanager;
2633
2634 $sign = 1;
2635 if (isset($object->type) && $object->type == 2 && getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE')) {
2636 $sign = -1;
2637 }
2638
2639 $reshook = 0;
2640 $result = '';
2641 //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) ) )
2642 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
2643 $special_code = empty($object->lines[$i]->special_code) ? '' : $object->lines[$i]->special_code;
2644 if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {
2645 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2646 }
2647 $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
2648 $action = '';
2649 $reshook = $hookmanager->executeHooks('pdf_getlinetotalwithtax', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2650
2651 if (!empty($hookmanager->resPrint)) {
2652 $result .= $hookmanager->resPrint;
2653 }
2654 }
2655 if (empty($reshook)) {
2656 if ($object->lines[$i]->special_code == 3) {
2657 $result .= $outputlangs->transnoentities("Option");
2658 } elseif (empty($hidedetails) || $hidedetails > 1) {
2659 $total_ttc = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1 ? $object->lines[$i]->multicurrency_total_ttc : $object->lines[$i]->total_ttc);
2660 if (isset($object->lines[$i]->situation_percent) && $object->lines[$i]->situation_percent > 0) {
2661 $total_ttc *= $object->lines[$i]->getSituationRatio();
2662 }
2663 $result .= price($sign * $total_ttc, 0, $outputlangs);
2664 }
2665 }
2666 return $result;
2667}
2668
2679function canDisplayLinkedObjectInPDF($object, $elementobject)
2680{
2681 $objectSocId = getObjectSocId($object);
2682 $elementSocId = getObjectSocId($elementobject);
2683
2684 if (getDolGlobalBool("PDF_ALLOW_DISPLAY_LINKED_OBJECT_FOR_OTHER_SOC")) {
2685 return true;
2686 }
2687
2688 if (!empty($objectSocId) && !empty($elementSocId) && $objectSocId != $elementSocId) {
2689 return false;
2690 }
2691
2692 return true;
2693}
2694
2703function pdf_getLinkedObjects(&$object, $outputlangs)
2704{
2705 global $db, $hookmanager;
2706
2707 $linkedobjects = array();
2708
2709 $object->fetchObjectLinked();
2710
2711 foreach ($object->linkedObjects as $objecttype => $objects) {
2712 if ($objecttype == 'facture') {
2713 // 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.
2714 } elseif ($objecttype == 'propal' || $objecttype == 'supplier_proposal') {
2715 '@phan-var-force array<Propal|SupplierProposal> $objects';
2717 $outputlangs->load('propal');
2718
2719 foreach ($objects as $elementobject) {
2720 $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefProposal");
2721 $linkedobjects[$objecttype]['ref_value'] = $outputlangs->transnoentities($elementobject->ref);
2722 $linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("DatePropal");
2723 $linkedobjects[$objecttype]['date_value'] = dol_print_date($elementobject->date, 'day', '', $outputlangs);
2724 }
2725 } elseif ($objecttype == 'commande' || $objecttype == 'supplier_order' || $objecttype == 'order_supplier') {
2726 $optiontohidelinkedorders = "PDF_HIDE_LINKED_ORDERS_ON_SAME_THIRDPARTY";
2727 if ($objecttype == 'supplier_order' || $objecttype == 'order_supplier') {
2728 $optiontohidelinkedorders = "PDF_HIDE_LINKED_PURCHASE_ORDERS_ON_SAME_THIRDPARTY";
2729 }
2730 '@phan-var-force array<Commande|CommandeFournisseur> $objects';
2731 $outputlangs->load('orders');
2732
2733 if (count($objects) > 1 && count($objects) <= getDolGlobalInt("MAXREFONDOC", 10) && !getDolGlobalString($optiontohidelinkedorders)) {
2734 if (empty($object->context['DolPublicNoteAppendedGetLinkedObjects'])) { // Check if already appended before add to avoid repeat data
2735 $outputList = '';
2736 foreach ($objects as $elementobject) {
2737 if (canDisplayLinkedObjectInPDF($object, $elementobject)) {
2738 $outputList = dol_concatdesc($outputList, $outputlangs->transnoentities($elementobject->ref) . (empty($elementobject->ref_client) ? '' : ' (' . $elementobject->ref_client . ')') . (empty($elementobject->ref_supplier) ? '' : ' (' . $elementobject->ref_supplier . ')') . ' ');
2739 $outputList = dol_concatdesc($outputList, $outputlangs->transnoentities("OrderDate") . ' : ' . dol_print_date($elementobject->date, 'day', '', $outputlangs));
2740 }
2741 }
2742
2743 if (!empty($outputList)) {
2744 $object->note_public = dol_concatdesc($object->note_public, $outputlangs->transnoentities("RefOrder").' :');
2745 $object->note_public = dol_concatdesc($object->note_public, $outputList);
2746 }
2747 }
2748 } elseif (count($objects) == 1 && !getDolGlobalString($optiontohidelinkedorders)) {
2749 $elementobject = array_shift($objects);
2750 if (canDisplayLinkedObjectInPDF($object, $elementobject)) {
2751 $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefOrder");
2752 $linkedobjects[$objecttype]['ref_value'] = $outputlangs->transnoentities($elementobject->ref).(!empty($elementobject->ref_client) ? ' ('.$elementobject->ref_client.')' : '').(!empty($elementobject->ref_supplier) ? ' ('.$elementobject->ref_supplier.')' : '');
2753 $linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("OrderDate");
2754 $linkedobjects[$objecttype]['date_value'] = dol_print_date($elementobject->date, 'day', '', $outputlangs);
2755 }
2756 }
2757 } elseif ($objecttype == 'contrat') {
2758 '@phan-var-force Contrat[] $objects';
2759 $outputlangs->load('contracts');
2760 foreach ($objects as $elementobject) {
2761 if (canDisplayLinkedObjectInPDF($object, $elementobject)) {
2762 $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefContract");
2763 $linkedobjects[$objecttype]['ref_value'] = $outputlangs->transnoentities($elementobject->ref);
2764 $linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("DateContract");
2765 $linkedobjects[$objecttype]['date_value'] = dol_print_date($elementobject->date_contrat, 'day', '', $outputlangs);
2766 }
2767 }
2768 } elseif ($objecttype == 'fichinter') {
2769 '@phan-var-force Fichinter[] $objects';
2770 $outputlangs->load('interventions');
2771 foreach ($objects as $elementobject) {
2772 if (canDisplayLinkedObjectInPDF($object, $elementobject)) {
2773 $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("InterRef");
2774 $linkedobjects[$objecttype]['ref_value'] = $outputlangs->transnoentities($elementobject->ref);
2775 $linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("InterDate");
2776 $linkedobjects[$objecttype]['date_value'] = dol_print_date($elementobject->datec, 'day', '', $outputlangs);
2777 }
2778 }
2779 } elseif ($objecttype == 'shipping') {
2780 '@phan-var-force Expedition[] $objects';
2781 $outputlangs->loadLangs(array("orders", "sendings"));
2782
2783 if (count($objects) > 1) {
2784 $order = null;
2785
2786 $refListsTxt = '';
2787 if (empty($object->linkedObjects['commande']) && $object->element != 'commande') {
2788 $refListsTxt .= $outputlangs->transnoentities("RefOrder").' / '.$outputlangs->transnoentities("RefSending").' :';
2789 } else {
2790 $refListsTxt .= $outputlangs->transnoentities("RefSending").' :';
2791 }
2792 // We concat this record info into fields xxx_value. title is overwrote.
2793 foreach ($objects as $elementobject) {
2794 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
2795 $elementobject->fetchObjectLinked(null, '', null, '', 'OR', 1, 'sourcetype', 0);
2796 if (!empty($elementobject->linkedObjectsIds['commande'])) {
2797 include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
2798 $order = new Commande($db);
2799 $ret = $order->fetch(reset($elementobject->linkedObjectsIds['commande']));
2800 if ($ret < 1) {
2801 $order = null;
2802 }
2803 }
2804 }
2805 $refListsTxt .= (!empty($refListsTxt) ? ' ' : '');
2806 if (! is_object($order)) {
2807 $refListsTxt .= $outputlangs->transnoentities($elementobject->ref);
2808 } else {
2809 $refListsTxt .= $outputlangs->convToOutputCharset($order->ref).($order->ref_client ? ' ('.$order->ref_client.')' : '');
2810 $refListsTxt .= ' / '.$outputlangs->transnoentities($elementobject->ref);
2811 }
2812 }
2813
2814 if (empty($object->context['DolPublicNoteAppendedGetLinkedObjects']) && !getDolGlobalString("PDF_HIDE_LINKED_OBJECT_IN_PUBLIC_NOTE")) { // Check if already appended before add to avoid repeat data
2815 $object->note_public = dol_concatdesc($object->note_public, $refListsTxt);
2816 }
2817 } elseif (count($objects) == 1) {
2818 $elementobject = array_shift($objects);
2819 $order = null;
2820 // We concat this record info into fields xxx_value. title is overwrote.
2821 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
2822 $elementobject->fetchObjectLinked(null, '', null, '', 'OR', 1, 'sourcetype', 0);
2823 if (!empty($elementobject->linkedObjectsIds['commande'])) {
2824 include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
2825 $order = new Commande($db);
2826 $ret = $order->fetch(reset($elementobject->linkedObjectsIds['commande']));
2827 if ($ret < 1) {
2828 $order = null;
2829 }
2830 }
2831 }
2832
2833 if (! is_object($order)) {
2834 $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefSending");
2835 if (empty($linkedobjects[$objecttype]['ref_value'])) {
2836 $linkedobjects[$objecttype]['ref_value'] = '';
2837 } else {
2838 $linkedobjects[$objecttype]['ref_value'] .= ' / ';
2839 }
2840 $linkedobjects[$objecttype]['ref_value'] .= $outputlangs->transnoentities($elementobject->ref);
2841 $linkedobjects[$objecttype]['date_value'] = dol_print_date(empty($elementobject->date_shipping) ? $elementobject->date_delivery : $elementobject->date_shipping, 'day', '', $outputlangs);
2842 } else {
2843 $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefOrder").' / '.$outputlangs->transnoentities("RefSending");
2844 if (empty($linkedobjects[$objecttype]['ref_value'])) {
2845 $linkedobjects[$objecttype]['ref_value'] = $outputlangs->convToOutputCharset($order->ref).($order->ref_client ? ' ('.$order->ref_client.')' : '');
2846 }
2847 $linkedobjects[$objecttype]['ref_value'] .= ' / '.$outputlangs->transnoentities($elementobject->ref);
2848 $linkedobjects[$objecttype]['date_value'] = dol_print_date(empty($elementobject->date_shipping) ? $elementobject->date_delivery : $elementobject->date_shipping, 'day', '', $outputlangs);
2849 }
2850 }
2851 }
2852 }
2853
2854 $object->context['DolPublicNoteAppendedGetLinkedObjects'] = 1;
2855
2856 // For add external linked objects
2857 if (is_object($hookmanager)) {
2858 $parameters = array('linkedobjects' => $linkedobjects, 'outputlangs' => $outputlangs);
2859 $action = '';
2860 $reshook = $hookmanager->executeHooks('pdf_getLinkedObjects', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
2861 if (empty($reshook)) {
2862 $linkedobjects = array_replace($linkedobjects, $hookmanager->resArray); // array_replace is used to preserve keys
2863 } elseif ($reshook > 0) {
2864 // The array must be reinserted even if it is empty because clearing the array could be one of the actions performed by the hook.
2865 $linkedobjects = $hookmanager->resArray;
2866 }
2867 }
2868
2869 return $linkedobjects;
2870}
2871
2879function pdf_getSizeForImage($realpath)
2880{
2881 $maxwidth = getDolGlobalInt('MAIN_DOCUMENTS_WITH_PICTURE_WIDTH', 20);
2882 $maxheight = getDolGlobalInt('MAIN_DOCUMENTS_WITH_PICTURE_HEIGHT', 32);
2883
2884 include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
2885 $tmp = dol_getImageSize($realpath);
2886 $width = 0;
2887 $height = 0;
2888 if ($tmp['height']) {
2889 $width = (int) round($maxheight * $tmp['width'] / $tmp['height']); // I try to use maxheight
2890 if ($width > $maxwidth) { // Pb with maxheight, so i use maxwidth
2891 $width = $maxwidth;
2892 $height = (int) round($maxwidth * $tmp['height'] / $tmp['width']);
2893 } else { // No pb with maxheight
2894 $height = $maxheight;
2895 }
2896 }
2897 return array('width' => $width, 'height' => $height);
2898}
2899
2911function pdfGetLineTotalDiscountAmount($object, $i, $outputlangs, $hidedetails = 0, $multicurrency = 0)
2912{
2913 global $hookmanager;
2914
2915 $sign = 1;
2916 if (isset($object->type) && $object->type == 2 && getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE')) {
2917 $sign = -1;
2918 }
2919 if ($object->lines[$i]->special_code == 3) {
2920 // If option
2921 return $outputlangs->transnoentities("Option");
2922 } else {
2923 if (is_object($hookmanager)) {
2924 $special_code = $object->lines[$i]->special_code;
2925 if (!empty($object->lines[$i]->fk_parent_line)) {
2926 $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2927 }
2928
2929 $parameters = array(
2930 'i' => $i,
2931 'outputlangs' => $outputlangs,
2932 'hidedetails' => $hidedetails,
2933 'special_code' => $special_code,
2934 'multicurrency' => $multicurrency
2935 );
2936
2937 $action = '';
2938
2939 if ($hookmanager->executeHooks('getlinetotalremise', $parameters, $object, $action) > 0) { // Note that $action and $object may have been modified by some hooks
2940 if (isset($hookmanager->resArray['linetotalremise'])) {
2941 return (float) $hookmanager->resArray['linetotalremise'];
2942 } else {
2943 return (float) $hookmanager->resPrint; // For backward compatibility
2944 }
2945 }
2946 }
2947
2948 if (empty($hidedetails) || $hidedetails > 1) {
2949 if (empty($multicurrency)) {
2950 $diff = (float) price2num($sign * $object->lines[$i]->subprice * (float) $object->lines[$i]->qty, 'MT', 1) - $object->lines[$i]->total_ht;
2951 return (float) price2num($diff, 'MT', 1);
2952 } else {
2953 $diff = (float) price2num($sign * $object->lines[$i]->multicurrency_subprice * (float) $object->lines[$i]->qty, 'MT', 1) - $object->lines[$i]->multicurrency_total_ht;
2954 return (float) price2num($diff, 'MT', 1);
2955 }
2956 }
2957 }
2958 return 0;
2959}
2960
2968function pdfExtractMetadata($file, $field = 'Keywords')
2969{
2970 if (!dol_is_file($file)) {
2971 return "ERROR: FILE NOT FOUND OR NOT VALID";
2972 }
2973
2974 // Get content of PDF file
2975 $content = file_get_contents(dol_osencode($file));
2976
2977 // Use a regex to capture the metadata
2978 if ($content) {
2979 $matches = array();
2980
2981 // Remove non printablecaracters
2982 $content = preg_replace('/[^(\x20-\x7F)]*/', '', $content);
2983 if (preg_match('/\/' . preg_quote($field, '/') . '\s*\‍((.*?)\‍)/', $content, $matches)) {
2984 return trim($matches[1]);
2985 }
2986 return "ERROR: NOT FOUND";
2987 } else {
2988 return "ERROR: FAILED TO READ PDF";
2989 }
2990}
2991
3010 TCPDF $pdf,
3011 CommonDocGenerator $generator,
3012 float $curY,
3014 int $i,
3015 Translate $outputlangs,
3016 int $hideref,
3017 int $hidedesc,
3018 array $bgColor,
3019 bool $isSubtotal = false,
3020 bool $applySubtotalLogic = true
3021) {
3022 $savePage = $pdf->getPage();
3023 $saveX = $pdf->GetX();
3024 $prevAlign = $generator->cols['desc']['content']['align'];
3025
3026 if ($isSubtotal && $applySubtotalLogic && $object->lines[$i]->qty < 0) {
3027 $outputlangs->load("subtotals");
3028 $object->lines[$i]->desc = getDolGlobalString("SUBTOTAL_LINE_TEXT_DOES_NOT_INCLUDE_TITLE_TEXT") ? $outputlangs->trans("SubTotal") : $outputlangs->trans("SubtotalOf", $object->lines[$i]->desc);
3029 $generator->cols['desc']['content']['align'] = ($prevAlign === 'L') ? 'R' : 'L';
3030 }
3031
3032 $pdf->startTransaction();
3033 $pdf->SetXY($saveX, $curY);
3034 $generator->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc);
3035 $pageAfter = $pdf->getPage();
3036 $yAfter = $pdf->GetY();
3037 $pdf->rollbackTransaction(true);
3038
3039 $pdf->SetFillColor($bgColor[0], $bgColor[1], $bgColor[2]);
3040 $width = $generator->page_largeur - $generator->marge_droite - $generator->marge_gauche;
3041
3042 $pdf->SetXY($generator->marge_gauche, $curY);
3043 if ($pageAfter === $savePage) {
3044 $pdf->MultiCell($width, max(0, $yAfter - $curY), '', 0, '', true);
3045 } else {
3046 $pdf->MultiCell($width, $pdf->getPageHeight() - $pdf->getBreakMargin() - $curY, '', 0, '', true);
3047
3048 // The page reached by the measuring pass above was discarded along with
3049 // the transaction, and the MultiCell only recreates it when some room was
3050 // left to fill. A line starting below the break margin leaves none, so
3051 // the page must be added before it can be selected.
3052 while ($pdf->getNumPages() < $pageAfter) {
3053 $pdf->AddPage();
3054 }
3055 $pdf->setPage($pageAfter);
3056 $pdf->SetXY($generator->marge_gauche, $pdf->getMargins()['top']);
3057 $pdf->MultiCell($width, max(0, $yAfter - $pdf->getMargins()['top']), '', 0, '', true);
3058
3059 $pdf->setPage($savePage);
3060 }
3061
3062 $pdf->SetTextColor(colorIsLight(implode(',', $bgColor)));
3063 $pdf->SetXY($saveX, $curY);
3064 $generator->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc);
3065 $generator->setAfterColsLinePositionsData('desc', $pdf->GetY(), $pdf->getPage());
3066
3067 $generator->cols['desc']['content']['align'] = $prevAlign;
3068}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
pdfCertifMentionblockedLog(&$pdf, $outputlangs, $seller, $default_font_size, &$posy, $pdftemplate)
Add legal mention.
isALNERunningVersion($blockedlogtestalreadydone=0)
Return if the application is executed with the LNE requirements on.
Class to manage categories.
Class to manage customers orders.
Parent class for documents (PDF, ODT, ...) generators.
printColDescContent($pdf, &$curY, $colKey, $object, $i, $outputlangs, $hideref=0, $hidedesc=0, $issupplierline=0)
print description column content
setAfterColsLinePositionsData(string $colId, float $y, int $pageNumb)
Used for to set afterColsLinePositions var in a pdf draw line loop.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Class to manage contact/addresses.
Class to manage absolute discounts.
Class to manage warehouses.
static getIBANLabel(Account $account)
Returns the name of the Iban label.
File of class to manage predefined price products or services by customer.
Class to manage predefined suppliers products.
Class to manage products or services.
Manage record for batch number management.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
getState($id, $withcode='0', $dbtouse=null, $withregion=0, $outputlangs=null, $entconv=1)
Return state translated from an id.
getFormeJuridiqueLabel($code)
Return the name translated of juridical status.
global $mysoc
dol_is_file($pathoffile)
Return if path is a file.
dol_print_reduction($reduction, $langs)
Returns formatted reduction.
dol_getDefaultFormat($outputlangs=null)
Try to guess default paper format according to language into $langs.
dol_html_entity_decode($a, $b, $c='UTF-8', $keepsomeentities=0)
Replace html_entity_decode functions to manage errors.
dol_now($mode='gmt')
Return date for now.
getDolGlobalFloat($key, $default=0)
Return a Dolibarr global constant float value.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
dol_format_address($object, $withcountry=0, $sep="\n", $outputlangs=null, $mode=0, $extralangcode='')
Return a formatted address (part address/zip/town/state) according to country rules.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
getObjectSocId($obj)
Get the socid of an object, supporting legacy attribute names.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
getDolCurrency()
Return the main currency ('EUR', 'USD', ...)
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
dol_textishtml($msg, $option=0)
Return if a text is a html content.
colorIsLight($stringcolor)
Return true if the color is light.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalBool($key, $default=false)
Return a Dolibarr global constant boolean value.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode='add', $filterorigmodule='')
Complete or removed entries into a head array (used to build tabs).
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_getImageSize($file, $url=false)
Return size of image file on disk (Supported extensions are gif, jpg, png, bmp and webp)
pdf_getSizeForImage($realpath)
Return dimensions to use for images onto PDF checking that width and height are not higher than maxim...
Definition pdf.lib.php:2879
pdf_writelinedesc(&$pdf, $object, $i, $outputlangs, $w, $h, $posx, $posy, $hideref=0, $hidedesc=0, $issupplierline=0, $align='J')
Output line description into PDF.
Definition pdf.lib.php:1535
pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line total excluding tax.
Definition pdf.lib.php:2580
pdf_getlinedesc($object, $i, $outputlangs, $hideref=0, $hidedesc=0, $issupplierline=0)
Return line description translated in outputlangs and encoded into htmlentities and with
Definition pdf.lib.php:1592
pdf_getFormat($outputlangs=null, $mode='setup')
Return array with format properties of default PDF format.
Definition pdf.lib.php:87
pdfGetLineTotalDiscountAmount($object, $i, $outputlangs, $hidedetails=0, $multicurrency=0)
Return line total amount discount.
Definition pdf.lib.php:2911
pdf_getPDFFontSize($outputlangs)
Return font size to use for PDF generation.
Definition pdf.lib.php:289
pdfExtractMetadata($file, $field='Keywords')
Function to extract metadata from a PDF file by doing a binary parsing of the PDF file.
Definition pdf.lib.php:2968
pdf_getlineqty_shipped($object, $i, $outputlangs, $hidedetails=0)
Return line quantity shipped.
Definition pdf.lib.php:2334
pdf_getlinenum($object, $i, $outputlangs, $hidedetails=0)
Return line num.
Definition pdf.lib.php:2009
pdf_getEncryption($pathoffile)
Return if pdf file is protected/encrypted.
Definition pdf.lib.php:235
pdfCertifMention(&$pdf, $outputlangs, $seller, $default_font_size, &$posy, $pdftemplate)
Add legal certificate mention.
Definition pdf.lib.php:908
pdf_getlineupwithtax($object, $i, $outputlangs, $hidedetails=0)
Return line unit price including tax.
Definition pdf.lib.php:2212
pdfWriteBlockedLogSignature(&$pdf, $outputlangs, $page_height, $object, &$w, &$posx, &$posy)
Show header of page for PDF generation.
Definition pdf.lib.php:780
pdf_getHeightForLogo($logo, $url=false)
Return height to use for Logo onto PDF.
Definition pdf.lib.php:312
pdf_getlineref_supplier($object, $i, $outputlangs, $hidedetails=0)
Return line ref_supplier.
Definition pdf.lib.php:2075
pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails=0)
Return line total including tax.
Definition pdf.lib.php:2630
pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_basse, $marge_gauche, $page_hauteur, $object, $showdetails=0, $hidefreetext=0, $page_largeur=0, $watermark='')
Show footer of page for PDF generation.
Definition pdf.lib.php:1110
pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line unit price excluding tax.
Definition pdf.lib.php:2169
pdf_getlineprogress($object, $i, $outputlangs, $hidedetails=0, $hookmanager=null)
Return line percent.
Definition pdf.lib.php:2500
pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails=0)
Return line vat rate.
Definition pdf.lib.php:2107
pdfGetHeightForHtmlContent(&$pdf, $htmlcontent)
Function to try to calculate height of a HTML Content.
Definition pdf.lib.php:337
pdf_admin_prepare_head()
Return array head with list of tabs to view object information.
Definition pdf.lib.php:49
pdf_pagehead(&$pdf, $outputlangs, $page_height)
Show header of page for PDF generation.
Definition pdf.lib.php:742
canDisplayLinkedObjectInPDF($object, $elementobject)
Check if a linked object can be displayed based on third-party privacy rules.
Definition pdf.lib.php:2679
pdf_writeLinkedObjects(&$pdf, $object, $outputlangs, $posx, $posy, $w, $h, $align, $default_font_size)
Show linked objects for PDF generation.
Definition pdf.lib.php:1497
pdf_bank(&$pdf, $outputlangs, $curx, $cury, $account, $onlynumber=0, $default_font_size=10)
Show bank information for PDF generation.
Definition pdf.lib.php:928
pdf_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition pdf.lib.php:268
pdf_render_subtotals(TCPDF $pdf, CommonDocGenerator $generator, float $curY, CommonObject $object, int $i, Translate $outputlangs, int $hideref, int $hidedesc, array $bgColor, bool $isSubtotal=false, bool $applySubtotalLogic=true)
Render subtotals line with a colored background and adapted text color .
Definition pdf.lib.php:3009
pdf_getlineqty_keeptoship($object, $i, $outputlangs, $hidedetails=0)
Return line keep to ship quantity.
Definition pdf.lib.php:2374
pdf_getlineref($object, $i, $outputlangs, $hidedetails=0)
Return line product ref.
Definition pdf.lib.php:2042
pdf_build_address($outputlangs, $sourcecompany, $targetcompany='', $targetcontact='', $usecontact=0, $mode='source', $object=null)
Return a string with full address formatted for output on PDF documents.
Definition pdf.lib.php:433
pdf_getlineunit($object, $i, $outputlangs, $hidedetails=0)
Return line unit.
Definition pdf.lib.php:2414
pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails=0)
Return line remise percent.
Definition pdf.lib.php:2457
pdf_getlineqty_asked($object, $i, $outputlangs, $hidedetails=0)
Return line quantity asked.
Definition pdf.lib.php:2294
pdf_getlineqty($object, $i, $outputlangs, $hidedetails=0)
Return line quantity.
Definition pdf.lib.php:2254
pdf_getSubstitutionArray($outputlangs, $exclude=null, $object=null, $onlykey=0, $include=null)
Return array of possible substitutions for PDF content (without external module substitutions).
Definition pdf.lib.php:824
pdf_getInstance($format='', $metric='mm', $pagetype='P')
Return a PDF instance object.
Definition pdf.lib.php:129
pdfBuildThirdpartyName($thirdparty, Translate $outputlangs, $includealias=0)
Returns the name of the thirdparty.
Definition pdf.lib.php:388
pdf_watermark(&$pdf, $outputlangs, $h, $w, $unit, $text)
Add a draft watermark on PDF files.
Definition pdf.lib.php:844