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