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