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