dolibarr  18.0.6
pdf_cyan.modules.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2004-2014 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
4  * Copyright (C) 2008 Raphael Bertrand <raphael.bertrand@resultic.fr>
5  * Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
6  * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
7  * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
8  * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
9  * Copyright (C) 2017 Ferran Marcet <fmarcet@2byte.es>
10  * Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program. If not, see <https://www.gnu.org/licenses/>.
24  * or see https://www.gnu.org/
25  */
26 
32 require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php';
33 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
35 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
36 require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
37 
38 
43 {
47  public $db;
48 
52  public $name;
53 
57  public $description;
58 
62  public $update_main_doc_field;
63 
67  public $type;
68 
73  public $version = 'dolibarr';
74 
78  public $page_largeur;
79 
83  public $page_hauteur;
84 
88  public $format;
89 
93  public $marge_gauche;
94 
98  public $marge_droite;
99 
103  public $marge_haute;
104 
108  public $marge_basse;
109 
114  public $emetteur;
115 
119  public $cols;
120 
121 
127  public function __construct($db)
128  {
129  global $conf, $langs, $mysoc;
130 
131  // Translations
132  $langs->loadLangs(array("main", "bills"));
133 
134  $this->db = $db;
135  $this->name = "cyan";
136  $this->description = $langs->trans('DocModelCyanDescription');
137  $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template
138 
139  // Dimension page
140  $this->type = 'pdf';
141  $formatarray = pdf_getFormat();
142  $this->page_largeur = $formatarray['width'];
143  $this->page_hauteur = $formatarray['height'];
144  $this->format = array($this->page_largeur, $this->page_hauteur);
145  $this->marge_gauche = getDolGlobalInt('MAIN_PDF_MARGIN_LEFT', 10);
146  $this->marge_droite = getDolGlobalInt('MAIN_PDF_MARGIN_RIGHT', 10);
147  $this->marge_haute = getDolGlobalInt('MAIN_PDF_MARGIN_TOP', 10);
148  $this->marge_basse = getDolGlobalInt('MAIN_PDF_MARGIN_BOTTOM', 10);
149 
150  $this->option_logo = 1; // Display logo
151  $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION
152  $this->option_modereg = 1; // Display payment mode
153  $this->option_condreg = 1; // Display payment terms
154  $this->option_multilang = 1; // Available in several languages
155  $this->option_escompte = 0; // Displays if there has been a discount
156  $this->option_credit_note = 0; // Support credit notes
157  $this->option_freetext = 1; // Support add of a personalised text
158  $this->option_draft_watermark = 1; // Support add of a watermark on drafts
159  $this->watermark = '';
160 
161  // Get source company
162  $this->emetteur = $mysoc;
163  if (empty($this->emetteur->country_code)) {
164  $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined
165  }
166 
167  // Define position of columns
168  $this->posxdesc = $this->marge_gauche + 1; // used for notes ans other stuff
169 
170 
171  $this->tabTitleHeight = 5; // default height
172 
173  // Use new system for position of columns, view $this->defineColumnField()
174 
175  $this->tva = array();
176  $this->tva_array = array();
177  $this->localtax1 = array();
178  $this->localtax2 = array();
179  $this->atleastoneratenotnull = 0;
180  $this->atleastonediscount = 0;
181  }
182 
183  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
195  public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
196  {
197  // phpcs:enable
198  global $user, $langs, $conf, $mysoc, $db, $hookmanager, $nblines;
199 
200  dol_syslog("write_file outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null'));
201 
202  if (!is_object($outputlangs)) {
203  $outputlangs = $langs;
204  }
205  // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
206  if (!empty($conf->global->MAIN_USE_FPDF)) {
207  $outputlangs->charset_output = 'ISO-8859-1';
208  }
209 
210  // Load translation files required by page
211  $outputlangs->loadLangs(array("main", "dict", "companies", "bills", "products", "propal"));
212 
213  // Show Draft Watermark
214  if ($object->statut == $object::STATUS_DRAFT && getDolGlobalString('PROPALE_DRAFT_WATERMARK')) {
215  $this->watermark = getDolGlobalString('PROPALE_DRAFT_WATERMARK');
216  }
217 
218  global $outputlangsbis;
219  $outputlangsbis = null;
220  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) {
221  $outputlangsbis = new Translate('', $conf);
222  $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE);
223  $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal"));
224  }
225 
226  $nblines = count($object->lines);
227 
228  $hidetop = 0;
229  if (!empty($conf->global->MAIN_PDF_DISABLE_COL_HEAD_TITLE)) {
230  $hidetop = $conf->global->MAIN_PDF_DISABLE_COL_HEAD_TITLE;
231  }
232 
233  // Loop on each lines to detect if there is at least one image to show
234  $realpatharray = array();
235  $this->atleastonephoto = false;
236  if (!empty($conf->global->MAIN_GENERATE_PROPOSALS_WITH_PICTURE)) {
237  $objphoto = new Product($this->db);
238 
239  for ($i = 0; $i < $nblines; $i++) {
240  if (empty($object->lines[$i]->fk_product)) {
241  continue;
242  }
243 
244  $objphoto->fetch($object->lines[$i]->fk_product);
245  //var_dump($objphoto->ref);exit;
246  if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
247  $pdir[0] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/";
248  $pdir[1] = get_exdir(0, 0, 0, 0, $objphoto, 'product').dol_sanitizeFileName($objphoto->ref).'/';
249  } else {
250  $pdir[0] = get_exdir(0, 0, 0, 0, $objphoto, 'product'); // default
251  $pdir[1] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/"; // alternative
252  }
253 
254  $arephoto = false;
255  foreach ($pdir as $midir) {
256  if (!$arephoto) {
257  if ($conf->entity != $objphoto->entity) {
258  $dir = $conf->product->multidir_output[$objphoto->entity].'/'.$midir; //Check repertories of current entities
259  } else {
260  $dir = $conf->product->dir_output.'/'.$midir; //Check repertory of the current product
261  }
262 
263  foreach ($objphoto->liste_photos($dir, 1) as $key => $obj) {
264  if (!getDolGlobalInt('CAT_HIGH_QUALITY_IMAGES')) { // If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo
265  if ($obj['photo_vignette']) {
266  $filename = $obj['photo_vignette'];
267  } else {
268  $filename = $obj['photo'];
269  }
270  } else {
271  $filename = $obj['photo'];
272  }
273 
274  $realpath = $dir.$filename;
275  $arephoto = true;
276  $this->atleastonephoto = true;
277  }
278  }
279  }
280 
281  if ($realpath && $arephoto) {
282  $realpatharray[$i] = $realpath;
283  }
284  }
285  }
286 
287  if (count($realpatharray) == 0) {
288  $this->posxpicture = $this->posxtva;
289  }
290 
291  if ($conf->propal->multidir_output[$conf->entity]) {
292  $object->fetch_thirdparty();
293 
294  $deja_regle = 0;
295 
296  // Definition of $dir and $file
297  if ($object->specimen) {
298  $dir = $conf->propal->multidir_output[$conf->entity];
299  $file = $dir."/SPECIMEN.pdf";
300  } else {
301  $objectref = dol_sanitizeFileName($object->ref);
302  $dir = $conf->propal->multidir_output[$object->entity]."/".$objectref;
303  $file = $dir."/".$objectref.".pdf";
304  }
305 
306  if (!file_exists($dir)) {
307  if (dol_mkdir($dir) < 0) {
308  $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
309  return 0;
310  }
311  }
312 
313  if (file_exists($dir)) {
314  // Add pdfgeneration hook
315  if (!is_object($hookmanager)) {
316  include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
317  $hookmanager = new HookManager($this->db);
318  }
319  $hookmanager->initHooks(array('pdfgeneration'));
320  $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
321  global $action;
322  $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
323 
324  // Set nblines with the new content of lines after hook
325  $nblines = count($object->lines);
326  //$nbpayments = count($object->getListOfPayments());
327 
328  // Create pdf instance
329  $pdf = pdf_getInstance($this->format);
330  $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
331  $pdf->SetAutoPageBreak(1, 0);
332 
333  if (class_exists('TCPDF')) {
334  $pdf->setPrintHeader(false);
335  $pdf->setPrintFooter(false);
336  }
337  $pdf->SetFont(pdf_getPDFFont($outputlangs));
338  // Set path to the background PDF File
339  if (!empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) {
340  $logodir = $conf->mycompany->dir_output;
341  if (!empty($conf->mycompany->multidir_output[$object->entity])) {
342  $logodir = $conf->mycompany->multidir_output[$object->entity];
343  }
344  $pagecount = $pdf->setSourceFile($logodir.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND);
345  $tplidx = $pdf->importPage(1);
346  }
347 
348  $pdf->Open();
349  $pagenb = 0;
350  $pdf->SetDrawColor(128, 128, 128);
351 
352  $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
353  $pdf->SetSubject($outputlangs->transnoentities("PdfCommercialProposalTitle"));
354  $pdf->SetCreator("Dolibarr ".DOL_VERSION);
355  $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
356  $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfCommercialProposalTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
357  if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
358  $pdf->SetCompression(false);
359  }
360 
361  $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
362 
363  // Set $this->atleastonediscount if you have at least one discount
364  for ($i = 0; $i < $nblines; $i++) {
365  if ($object->lines[$i]->remise_percent) {
366  $this->atleastonediscount++;
367  }
368  }
369 
370 
371  // New page
372  $pdf->AddPage();
373  if (!empty($tplidx)) {
374  $pdf->useTemplate($tplidx);
375  }
376  $pagenb++;
377 
378  $heightforinfotot = 40; // Height reserved to output the info and total part
379  $heightforsignature = empty($conf->global->PROPAL_DISABLE_SIGNATURE) ? (pdfGetHeightForHtmlContent($pdf, $outputlangs->transnoentities("ProposalCustomerSignature")) + 10) : 0;
380  $heightforfreetext = (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT) ? $conf->global->MAIN_PDF_FREETEXT_HEIGHT : 5); // Height reserved to output the free text on last page
381  $heightforfooter = $this->marge_basse + (empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS) ? 12 : 22); // Height reserved to output the footer (value include bottom margin)
382  //print $heightforinfotot + $heightforsignature + $heightforfreetext + $heightforfooter;exit;
383 
384  $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis);
385  $pdf->SetFont('', '', $default_font_size - 1);
386  $pdf->MultiCell(0, 3, ''); // Set interline to 3
387  $pdf->SetTextColor(0, 0, 0);
388 
389 
390  $tab_top = 90 + $top_shift;
391  $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
392 
393  $nexY = $tab_top;
394 
395  // Incoterm
396  $height_incoterms = 0;
397  if (isModEnabled('incoterm')) {
398  $desc_incoterms = $object->getIncotermsForPDF();
399  if ($desc_incoterms) {
400  $tab_top -= 2;
401 
402  $pdf->SetFont('', '', $default_font_size - 1);
403  $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($desc_incoterms), 0, 1);
404  $nexY = max($pdf->GetY(), $nexY);
405  $height_incoterms = $nexY - $tab_top;
406 
407  // Rect takes a length in 3rd parameter
408  $pdf->SetDrawColor(192, 192, 192);
409  $pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_incoterms + 1);
410 
411  $tab_top = $nexY + 6;
412  $height_incoterms += 4;
413  }
414  }
415 
416  // Displays notes
417  $notetoshow = empty($object->note_public) ? '' : $object->note_public;
418  if (!empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE)) {
419  // Get first sale rep
420  if (is_object($object->thirdparty)) {
421  $salereparray = $object->thirdparty->getSalesRepresentatives($user);
422  $salerepobj = new User($this->db);
423  $salerepobj->fetch($salereparray[0]['id']);
424  if (!empty($salerepobj->signature)) {
425  $notetoshow = dol_concatdesc($notetoshow, $salerepobj->signature);
426  }
427  }
428  }
429 
430  // Extrafields in note
431  $extranote = $this->getExtrafieldsInHtml($object, $outputlangs);
432  if (!empty($extranote)) {
433  $notetoshow = dol_concatdesc($notetoshow, $extranote);
434  }
435 
436  if (!empty($conf->global->MAIN_ADD_CREATOR_IN_NOTE) && $object->user_author_id > 0) {
437  $tmpuser = new User($this->db);
438  $tmpuser->fetch($object->user_author_id);
439 
440  $creator_info = $langs->trans("CaseFollowedBy").' '.$tmpuser->getFullName($langs);
441  if ($tmpuser->email) $creator_info .= ', '.$langs->trans("EMail").': '.$tmpuser->email;
442  if ($tmpuser->office_phone) $creator_info .= ', '.$langs->trans("Phone").': '.$tmpuser->office_phone;
443 
444  $notetoshow = dol_concatdesc($notetoshow, $creator_info);
445  }
446 
447  $tab_height = $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter;
448 
449  $pagenb = $pdf->getPage();
450  if ($notetoshow) {
451  $tab_top -= 2;
452 
453  $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite;
454  $pageposbeforenote = $pagenb;
455 
456  $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
457  complete_substitutions_array($substitutionarray, $outputlangs, $object);
458  $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
459  $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);
460 
461  $pdf->startTransaction();
462 
463  $pdf->SetFont('', '', $default_font_size - 1);
464  $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
465  // Description
466  $pageposafternote = $pdf->getPage();
467  $posyafter = $pdf->GetY();
468 
469  if ($pageposafternote > $pageposbeforenote) {
470  $pdf->rollbackTransaction(true);
471 
472  // prepare pages to receive notes
473  while ($pagenb < $pageposafternote) {
474  $pdf->AddPage();
475  $pagenb++;
476  if (!empty($tplidx)) {
477  $pdf->useTemplate($tplidx);
478  }
479  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
480  $this->_pagehead($pdf, $object, 0, $outputlangs);
481  }
482  // $this->_pagefoot($pdf,$object,$outputlangs,1);
483  $pdf->setTopMargin($tab_top_newpage);
484  // The only function to edit the bottom margin of current page to set it.
485  $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
486  }
487 
488  // back to start
489  $pdf->setPage($pageposbeforenote);
490  $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
491  $pdf->SetFont('', '', $default_font_size - 1);
492  $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
493  $pageposafternote = $pdf->getPage();
494 
495  $posyafter = $pdf->GetY();
496 
497  if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) { // There is no space left for total+free text
498  $pdf->AddPage('', '', true);
499  $pagenb++;
500  $pageposafternote++;
501  $pdf->setPage($pageposafternote);
502  $pdf->setTopMargin($tab_top_newpage);
503  // The only function to edit the bottom margin of current page to set it.
504  $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
505  //$posyafter = $tab_top_newpage;
506  }
507 
508 
509  // apply note frame to previous pages
510  $i = $pageposbeforenote;
511  while ($i < $pageposafternote) {
512  $pdf->setPage($i);
513 
514 
515  $pdf->SetDrawColor(128, 128, 128);
516  // Draw note frame
517  if ($i > $pageposbeforenote) {
518  $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter);
519  $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1);
520  } else {
521  $height_note = $this->page_hauteur - ($tab_top + $heightforfooter);
522  $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1);
523  }
524 
525  // Add footer
526  $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
527  $this->_pagefoot($pdf, $object, $outputlangs, 1);
528 
529  $i++;
530  }
531 
532  // apply note frame to last page
533  $pdf->setPage($pageposafternote);
534  if (!empty($tplidx)) {
535  $pdf->useTemplate($tplidx);
536  }
537  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
538  $this->_pagehead($pdf, $object, 0, $outputlangs);
539  }
540  $height_note = $posyafter - $tab_top_newpage;
541  $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1);
542  } else {
543  // No pagebreak
544  $pdf->commitTransaction();
545  $posyafter = $pdf->GetY();
546  $height_note = $posyafter - $tab_top;
547  $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1);
548 
549 
550  if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) {
551  // not enough space, need to add page
552  $pdf->AddPage('', '', true);
553  $pagenb++;
554  $pageposafternote++;
555  $pdf->setPage($pageposafternote);
556  if (!empty($tplidx)) {
557  $pdf->useTemplate($tplidx);
558  }
559  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
560  $this->_pagehead($pdf, $object, 0, $outputlangs);
561  }
562 
563  $posyafter = $tab_top_newpage;
564  }
565  }
566  $tab_height = $tab_height - $height_note;
567  $tab_top = $posyafter + 6;
568  } else {
569  $height_note = 0;
570  }
571 
572  // Use new auto column system
573  $this->prepareArrayColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref);
574 
575  // Table simulation to know the height of the title line
576  $pdf->startTransaction();
577  $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop);
578  $pdf->rollbackTransaction(true);
579 
580  $nexY = $tab_top + $this->tabTitleHeight;
581 
582  // Loop on each lines
583  $pageposbeforeprintlines = $pdf->getPage();
584  $pagenb = $pageposbeforeprintlines;
585  for ($i = 0; $i < $nblines; $i++) {
586  $curY = $nexY;
587  $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
588  $pdf->SetTextColor(0, 0, 0);
589 
590  // Define size of image if we need it
591  $imglinesize = array();
592  if (!empty($realpatharray[$i])) {
593  $imglinesize = pdf_getSizeForImage($realpatharray[$i]);
594  }
595 
596  $pdf->setTopMargin($tab_top_newpage);
597  $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext + $heightforsignature + $heightforinfotot); // The only function to edit the bottom margin of current page to set it.
598  $pageposbefore = $pdf->getPage();
599 
600  $showpricebeforepagebreak = 1;
601  $posYAfterImage = 0;
602  $posYAfterDescription = 0;
603 
604  if ($this->getColumnStatus('photo')) {
605  // We start with Photo of product line
606  if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforsignature + $heightforinfotot))) { // If photo too high, we moved completely on new page
607  $pdf->AddPage('', '', true);
608  if (!empty($tplidx)) {
609  $pdf->useTemplate($tplidx);
610  }
611  $pdf->setPage($pageposbefore + 1);
612 
613  $curY = $tab_top_newpage;
614 
615  // Allows data in the first page if description is long enough to break in multiples pages
616  if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {
617  $showpricebeforepagebreak = 1;
618  } else {
619  $showpricebeforepagebreak = 0;
620  }
621  }
622 
623 
624  if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height'])) {
625  $pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY + 1, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi
626  // $pdf->Image does not increase value return by getY, so we save it manually
627  $posYAfterImage = $curY + $imglinesize['height'];
628  }
629  }
630 
631  // Description of product line
632  if ($this->getColumnStatus('desc')) {
633  $pdf->startTransaction();
634 
635  $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc);
636  $pageposafter = $pdf->getPage();
637 
638  if ($pageposafter > $pageposbefore) { // There is a pagebreak
639  $pdf->rollbackTransaction(true);
640 
641  $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
642 
643  $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc);
644 
645  $pageposafter = $pdf->getPage();
646  $posyafter = $pdf->GetY();
647  //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit;
648  if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforsignature + $heightforinfotot))) { // There is no space left for total+free text
649  if ($i == ($nblines - 1)) { // No more lines, and no space left to show total, so we create a new page
650  $pdf->AddPage('', '', true);
651  if (!empty($tplidx)) {
652  $pdf->useTemplate($tplidx);
653  }
654  $pdf->setPage($pageposafter + 1);
655  }
656  } else {
657  // We found a page break
658  // Allows data in the first page if description is long enough to break in multiples pages
659  if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {
660  $showpricebeforepagebreak = 1;
661  } else {
662  $showpricebeforepagebreak = 0;
663  }
664  }
665  } else // No pagebreak
666  {
667  $pdf->commitTransaction();
668  }
669  $posYAfterDescription = $pdf->GetY();
670  }
671 
672  $nexY = $pdf->GetY();
673  $pageposafter = $pdf->getPage();
674 
675  $pdf->setPage($pageposbefore);
676  $pdf->setTopMargin($this->marge_haute);
677  $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
678 
679  // We suppose that a too long description or photo were moved completely on next page
680  if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
681  $pdf->setPage($pageposafter);
682  $curY = $tab_top_newpage;
683  }
684 
685  $pdf->SetFont('', '', $default_font_size - 1); // We reposition the default font
686 
687  // VAT Rate
688  if ($this->getColumnStatus('vat')) {
689  $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
690  $this->printStdColumnContent($pdf, $curY, 'vat', $vat_rate);
691  $nexY = max($pdf->GetY(), $nexY);
692  }
693 
694  // Unit price before discount
695  if ($this->getColumnStatus('subprice')) {
696  $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);
697  $this->printStdColumnContent($pdf, $curY, 'subprice', $up_excl_tax);
698  $nexY = max($pdf->GetY(), $nexY);
699  }
700 
701  // Quantity
702  // Enough for 6 chars
703  if ($this->getColumnStatus('qty')) {
704  $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
705  $this->printStdColumnContent($pdf, $curY, 'qty', $qty);
706  $nexY = max($pdf->GetY(), $nexY);
707  }
708 
709 
710  // Unit
711  if ($this->getColumnStatus('unit')) {
712  $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager);
713  $this->printStdColumnContent($pdf, $curY, 'unit', $unit);
714  $nexY = max($pdf->GetY(), $nexY);
715  }
716 
717  // Discount on line
718  if ($this->getColumnStatus('discount') && $object->lines[$i]->remise_percent) {
719  $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);
720  $this->printStdColumnContent($pdf, $curY, 'discount', $remise_percent);
721  $nexY = max($pdf->GetY(), $nexY);
722  }
723 
724  // Total excl tax line (HT)
725  if ($this->getColumnStatus('totalexcltax')) {
726  $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails);
727  $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax);
728  $nexY = max($pdf->GetY(), $nexY);
729  }
730 
731  // Total with tax line (TTC)
732  if ($this->getColumnStatus('totalincltax')) {
733  $total_incl_tax = pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails);
734  $this->printStdColumnContent($pdf, $curY, 'totalincltax', $total_incl_tax);
735  $nexY = max($pdf->GetY(), $nexY);
736  }
737 
738  // Extrafields
739  if (!empty($object->lines[$i]->array_options)) {
740  foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) {
741  if ($this->getColumnStatus($extrafieldColKey)) {
742  $extrafieldValue = $this->getExtrafieldContent($object->lines[$i], $extrafieldColKey, $outputlangs);
743  $this->printStdColumnContent($pdf, $curY, $extrafieldColKey, $extrafieldValue);
744  $nexY = max($pdf->GetY(), $nexY);
745  }
746  }
747  }
748 
749  $parameters = array(
750  'object' => $object,
751  'i' => $i,
752  'pdf' =>& $pdf,
753  'curY' =>& $curY,
754  'nexY' =>& $nexY,
755  'outputlangs' => $outputlangs,
756  'hidedetails' => $hidedetails
757  );
758  $reshook = $hookmanager->executeHooks('printPDFline', $parameters, $this); // Note that $object may have been modified by hook
759 
760 
761  // Collection of totals by value of vat in $this->tva["rate"] = total_tva
762  if (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) {
763  $tvaligne = $object->lines[$i]->multicurrency_total_tva;
764  } else {
765  $tvaligne = $object->lines[$i]->total_tva;
766  }
767 
768  $localtax1ligne = $object->lines[$i]->total_localtax1;
769  $localtax2ligne = $object->lines[$i]->total_localtax2;
770  $localtax1_rate = $object->lines[$i]->localtax1_tx;
771  $localtax2_rate = $object->lines[$i]->localtax2_tx;
772  $localtax1_type = $object->lines[$i]->localtax1_type;
773  $localtax2_type = $object->lines[$i]->localtax2_type;
774 
775  // TODO remise_percent is an obsolete field for object parent
776  /*if ($object->remise_percent) {
777  $tvaligne -= ($tvaligne * $object->remise_percent) / 100;
778  }
779  if ($object->remise_percent) {
780  $localtax1ligne -= ($localtax1ligne * $object->remise_percent) / 100;
781  }
782  if ($object->remise_percent) {
783  $localtax2ligne -= ($localtax2ligne * $object->remise_percent) / 100;
784  }*/
785 
786  $vatrate = (string) $object->lines[$i]->tva_tx;
787 
788  // Retrieve type from database for backward compatibility with old records
789  if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined
790  && (!empty($localtax1_rate) || !empty($localtax2_rate))) { // and there is local tax
791  $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $object->thirdparty, $mysoc);
792  $localtax1_type = isset($localtaxtmp_array[0]) ? $localtaxtmp_array[0] : '';
793  $localtax2_type = isset($localtaxtmp_array[2]) ? $localtaxtmp_array[2] : '';
794  }
795 
796  // retrieve global local tax
797  if ($localtax1_type && $localtax1ligne != 0) {
798  if (empty($this->localtax1[$localtax1_type][$localtax1_rate])) {
799  $this->localtax1[$localtax1_type][$localtax1_rate] = $localtax1ligne;
800  } else {
801  $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne;
802  }
803  }
804  if ($localtax2_type && $localtax2ligne != 0) {
805  if (empty($this->localtax2[$localtax2_type][$localtax2_rate])) {
806  $this->localtax2[$localtax2_type][$localtax2_rate] = $localtax2ligne;
807  } else {
808  $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne;
809  }
810  }
811 
812  if (($object->lines[$i]->info_bits & 0x01) == 0x01) {
813  $vatrate .= '*';
814  }
815 
816  // Fill $this->tva and $this->tva_array
817  if (!isset($this->tva[$vatrate])) {
818  $this->tva[$vatrate] = 0;
819  }
820  $this->tva[$vatrate] += $tvaligne;
821  $vatcode = $object->lines[$i]->vat_src_code;
822  if (empty($this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'])) {
823  $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] = 0;
824  }
825  $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')] = array('vatrate'=>$vatrate, 'vatcode'=>$vatcode, 'amount'=> $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] + $tvaligne);
826 
827  if ($posYAfterImage > $posYAfterDescription) {
828  $nexY = max($nexY, $posYAfterImage);
829  }
830 
831  // Add line
832  if (!empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblines - 1)) {
833  $pdf->setPage($pageposafter);
834  $pdf->SetLineStyle(array('dash'=>'1,1', 'color'=>array(80, 80, 80)));
835  //$pdf->SetDrawColor(190,190,200);
836  $pdf->line($this->marge_gauche, $nexY + 1, $this->page_largeur - $this->marge_droite, $nexY + 1);
837  $pdf->SetLineStyle(array('dash'=>0));
838  }
839 
840  $nexY += 2; // Add space between lines
841 
842  // Detect if some page were added automatically and output _tableau for past pages
843  while ($pagenb < $pageposafter) {
844  $pdf->setPage($pagenb);
845  if ($pagenb == $pageposbeforeprintlines) {
846  $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code, $outputlangsbis);
847  } else {
848  $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code, $outputlangsbis);
849  }
850  $this->_pagefoot($pdf, $object, $outputlangs, 1);
851  $pagenb++;
852  $pdf->setPage($pagenb);
853  $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
854  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
855  $this->_pagehead($pdf, $object, 0, $outputlangs);
856  }
857  if (!empty($tplidx)) {
858  $pdf->useTemplate($tplidx);
859  }
860  }
861 
862  if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) {
863  if ($pagenb == $pageposafter) {
864  $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code, $outputlangsbis);
865  } else {
866  $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code, $outputlangsbis);
867  }
868  $this->_pagefoot($pdf, $object, $outputlangs, 1);
869  // New page
870  $pdf->AddPage();
871  if (!empty($tplidx)) {
872  $pdf->useTemplate($tplidx);
873  }
874  $pagenb++;
875  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
876  $this->_pagehead($pdf, $object, 0, $outputlangs);
877  }
878  }
879  }
880 
881  // Show square
882  if ($pagenb == $pageposbeforeprintlines) {
883  $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter, 0, $outputlangs, $hidetop, 0, $object->multicurrency_code, $outputlangsbis);
884  $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter + 1;
885  } else {
886  $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code, $outputlangsbis);
887  $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter + 1;
888  }
889 
890  // Display infos area
891  $posy = $this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs);
892 
893  // Display total zone
894  $posy = $this->drawTotalTable($pdf, $object, 0, $bottomlasttab, $outputlangs);
895 
896  // Display payment area
897  /*
898  if ($deja_regle || $amount_credit_notes_included || $amount_deposits_included)
899  {
900  $posy=$this->drawPaymentsTable($pdf, $object, $posy, $outputlangs);
901  }
902  */
903 
904  // Customer signature area
905  if (empty($conf->global->PROPAL_DISABLE_SIGNATURE)) {
906  $posy = $this->drawSignatureArea($pdf, $object, $posy, $outputlangs);
907  }
908 
909  // Pagefoot
910  $this->_pagefoot($pdf, $object, $outputlangs);
911  if (method_exists($pdf, 'AliasNbPages')) {
912  $pdf->AliasNbPages();
913  }
914 
915  //If propal merge product PDF is active
916  if (!empty($conf->global->PRODUIT_PDF_MERGE_PROPAL)) {
917  require_once DOL_DOCUMENT_ROOT.'/product/class/propalmergepdfproduct.class.php';
918 
919  $already_merged = array();
920  foreach ($object->lines as $line) {
921  if (!empty($line->fk_product) && !(in_array($line->fk_product, $already_merged))) {
922  // Find the desire PDF
923  $filetomerge = new Propalmergepdfproduct($this->db);
924 
925  if (getDolGlobalInt('MAIN_MULTILANGS')) {
926  $filetomerge->fetch_by_product($line->fk_product, $outputlangs->defaultlang);
927  } else {
928  $filetomerge->fetch_by_product($line->fk_product);
929  }
930 
931  $already_merged[] = $line->fk_product;
932 
933  $product = new Product($this->db);
934  $product->fetch($line->fk_product);
935 
936  if ($product->entity != $conf->entity) {
937  $entity_product_file = $product->entity;
938  } else {
939  $entity_product_file = $conf->entity;
940  }
941 
942  // If PDF is selected and file is not empty
943  if (count($filetomerge->lines) > 0) {
944  foreach ($filetomerge->lines as $linefile) {
945  if (!empty($linefile->id) && !empty($linefile->file_name)) {
946  if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
947  if (isModEnabled("product")) {
948  $filetomerge_dir = $conf->product->multidir_output[$entity_product_file].'/'.get_exdir($product->id, 2, 0, 0, $product, 'product').$product->id."/photos";
949  } elseif (isModEnabled("service")) {
950  $filetomerge_dir = $conf->service->multidir_output[$entity_product_file].'/'.get_exdir($product->id, 2, 0, 0, $product, 'product').$product->id."/photos";
951  }
952  } else {
953  if (isModEnabled("product")) {
954  $filetomerge_dir = $conf->product->multidir_output[$entity_product_file].'/'.get_exdir(0, 0, 0, 0, $product, 'product');
955  } elseif (isModEnabled("service")) {
956  $filetomerge_dir = $conf->service->multidir_output[$entity_product_file].'/'.get_exdir(0, 0, 0, 0, $product, 'product');
957  }
958  }
959 
960  dol_syslog(get_class($this).':: upload_dir='.$filetomerge_dir, LOG_DEBUG);
961 
962  $infile = $filetomerge_dir.'/'.$linefile->file_name;
963  if (file_exists($infile) && is_readable($infile)) {
964  $pagecount = $pdf->setSourceFile($infile);
965  for ($i = 1; $i <= $pagecount; $i++) {
966  $tplIdx = $pdf->importPage($i);
967  if ($tplIdx !== false) {
968  $s = $pdf->getTemplatesize($tplIdx);
969  $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
970  $pdf->useTemplate($tplIdx);
971  } else {
972  setEventMessages(null, array($infile.' cannot be added, probably protected PDF'), 'warnings');
973  }
974  }
975  }
976  }
977  }
978  }
979  }
980  }
981  }
982 
983  $pdf->Close();
984 
985  $pdf->Output($file, 'F');
986 
987  //Add pdfgeneration hook
988  $hookmanager->initHooks(array('pdfgeneration'));
989  $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
990  global $action;
991  $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
992  if ($reshook < 0) {
993  $this->error = $hookmanager->error;
994  $this->errors = $hookmanager->errors;
995  }
996 
997  dolChmod($file);
998 
999  $this->result = array('fullpath'=>$file);
1000 
1001  return 1; // No error
1002  } else {
1003  $this->error = $langs->trans("ErrorCanNotCreateDir", $dir);
1004  return 0;
1005  }
1006  } else {
1007  $this->error = $langs->trans("ErrorConstantNotDefined", "PROP_OUTPUTDIR");
1008  return 0;
1009  }
1010  }
1011 
1021  protected function drawPaymentsTable(&$pdf, $object, $posy, $outputlangs)
1022  {
1023  }
1024 
1034  public function drawInfoTable(&$pdf, $object, $posy, $outputlangs)
1035  {
1036  global $conf, $mysoc;
1037  $default_font_size = pdf_getPDFFontSize($outputlangs);
1038 
1039  $pdf->SetFont('', '', $default_font_size - 1);
1040 
1041  $diffsizetitle = (empty($conf->global->PDF_DIFFSIZE_TITLE) ? 3 : $conf->global->PDF_DIFFSIZE_TITLE);
1042 
1043  // If France, show VAT mention if not applicable
1044  if ($this->emetteur->country_code == 'FR' && empty($mysoc->tva_assuj)) {
1045  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1046  $pdf->SetXY($this->marge_gauche, $posy);
1047  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0);
1048 
1049  $posy = $pdf->GetY() + 4;
1050  }
1051 
1052  $posxval = 52;
1053  if (!empty($conf->global->MAIN_PDF_DATE_TEXT)) {
1054  $displaydate = "daytext";
1055  } else {
1056  $displaydate = "day";
1057  }
1058 
1059  // Show shipping date
1060  if (!empty($object->delivery_date)) {
1061  $outputlangs->load("sendings");
1062  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1063  $pdf->SetXY($this->marge_gauche, $posy);
1064  $titre = $outputlangs->transnoentities("DateDeliveryPlanned").':';
1065  $pdf->MultiCell(80, 4, $titre, 0, 'L');
1066  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1067  $pdf->SetXY($posxval, $posy);
1068  $dlp = dol_print_date($object->delivery_date, $displaydate, false, $outputlangs, true);
1069  $pdf->MultiCell(80, 4, $dlp, 0, 'L');
1070 
1071  $posy = $pdf->GetY() + 1;
1072  } elseif ($object->availability_code || $object->availability) { // Show availability conditions
1073  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1074  $pdf->SetXY($this->marge_gauche, $posy);
1075  $titre = $outputlangs->transnoentities("AvailabilityPeriod").':';
1076  $pdf->MultiCell(80, 4, $titre, 0, 'L');
1077  $pdf->SetTextColor(0, 0, 0);
1078  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1079  $pdf->SetXY($posxval, $posy);
1080  $lib_availability = $outputlangs->transnoentities("AvailabilityType".$object->availability_code) != ('AvailabilityType'.$object->availability_code) ? $outputlangs->transnoentities("AvailabilityType".$object->availability_code) : $outputlangs->convToOutputCharset($object->availability);
1081  $lib_availability = str_replace('\n', "\n", $lib_availability);
1082  $pdf->MultiCell(80, 4, $lib_availability, 0, 'L');
1083 
1084  $posy = $pdf->GetY() + 1;
1085  }
1086 
1087  // Show delivery mode
1088  if (empty($conf->global->PROPOSAL_PDF_HIDE_DELIVERYMODE) && $object->shipping_method_id > 0) {
1089  $outputlangs->load("sendings");
1090 
1091  $shipping_method_id = $object->shipping_method_id;
1092  if (!empty($conf->global->SOCIETE_ASK_FOR_SHIPPING_METHOD) && !empty($this->emetteur->shipping_method_id)) {
1093  $shipping_method_id = $this->emetteur->shipping_method_id;
1094  }
1095  $shipping_method_code = dol_getIdFromCode($this->db, $shipping_method_id, 'c_shipment_mode', 'rowid', 'code');
1096  $shipping_method_label = dol_getIdFromCode($this->db, $shipping_method_id, 'c_shipment_mode', 'rowid', 'libelle');
1097 
1098  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1099  $pdf->SetXY($this->marge_gauche, $posy);
1100  $titre = $outputlangs->transnoentities("SendingMethod").':';
1101  $pdf->MultiCell(43, 4, $titre, 0, 'L');
1102 
1103  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1104  $pdf->SetXY($posxval, $posy);
1105  $lib_condition_paiement = ($outputlangs->transnoentities("SendingMethod".strtoupper($shipping_method_code)) != "SendingMethod".strtoupper($shipping_method_code)) ? $outputlangs->trans("SendingMethod".strtoupper($shipping_method_code)) : $shipping_method_label;
1106  $lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
1107  $pdf->MultiCell(67, 4, $lib_condition_paiement, 0, 'L');
1108 
1109  $posy = $pdf->GetY() + 1;
1110  }
1111 
1112  // Show payments conditions
1113  if (empty($conf->global->PROPOSAL_PDF_HIDE_PAYMENTTERM) && $object->cond_reglement_code) {
1114  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1115  $pdf->SetXY($this->marge_gauche, $posy);
1116  $titre = $outputlangs->transnoentities("PaymentConditions").':';
1117  $pdf->MultiCell(43, 4, $titre, 0, 'L');
1118 
1119  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1120  $pdf->SetXY($posxval, $posy);
1121  $lib_condition_paiement = $outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code) != ('PaymentCondition'.$object->cond_reglement_code) ? $outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code) : $outputlangs->convToOutputCharset($object->cond_reglement_doc ? $object->cond_reglement_doc : $object->cond_reglement_label);
1122  $lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
1123  if ($object->deposit_percent > 0) {
1124  $lib_condition_paiement = str_replace('__DEPOSIT_PERCENT__', $object->deposit_percent, $lib_condition_paiement);
1125  }
1126  $pdf->MultiCell(67, 4, $lib_condition_paiement, 0, 'L');
1127 
1128  $posy = $pdf->GetY() + 3;
1129  }
1130 
1131  if (empty($conf->global->PROPOSAL_PDF_HIDE_PAYMENTMODE)) {
1132  // Show payment mode
1133  if ($object->mode_reglement_code
1134  && $object->mode_reglement_code != 'CHQ'
1135  && $object->mode_reglement_code != 'VIR') {
1136  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1137  $pdf->SetXY($this->marge_gauche, $posy);
1138  $titre = $outputlangs->transnoentities("PaymentMode").':';
1139  $pdf->MultiCell(80, 5, $titre, 0, 'L');
1140  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1141  $pdf->SetXY($posxval, $posy);
1142  $lib_mode_reg = $outputlangs->transnoentities("PaymentType".$object->mode_reglement_code) != ('PaymentType'.$object->mode_reglement_code) ? $outputlangs->transnoentities("PaymentType".$object->mode_reglement_code) : $outputlangs->convToOutputCharset($object->mode_reglement);
1143  $pdf->MultiCell(80, 5, $lib_mode_reg, 0, 'L');
1144 
1145  $posy = $pdf->GetY() + 2;
1146  }
1147 
1148  // Show payment mode CHQ
1149  if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ') {
1150  // Si mode reglement non force ou si force a CHQ
1151  if (getDolGlobalInt('FACTURE_CHQ_NUMBER')) {
1152  if ($conf->global->FACTURE_CHQ_NUMBER > 0) {
1153  $account = new Account($this->db);
1154  $account->fetch(getDolGlobalInt('FACTURE_CHQ_NUMBER'));
1155 
1156  $pdf->SetXY($this->marge_gauche, $posy);
1157  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1158  $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $account->proprio), 0, 'L', 0);
1159  $posy = $pdf->GetY() + 1;
1160 
1161  if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) {
1162  $pdf->SetXY($this->marge_gauche, $posy);
1163  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1164  $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0);
1165  $posy = $pdf->GetY() + 2;
1166  }
1167  }
1168  if (getDolGlobalInt('FACTURE_CHQ_NUMBER') == -1) {
1169  $pdf->SetXY($this->marge_gauche, $posy);
1170  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1171  $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $this->emetteur->name), 0, 'L', 0);
1172  $posy = $pdf->GetY() + 1;
1173 
1174  if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) {
1175  $pdf->SetXY($this->marge_gauche, $posy);
1176  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1177  $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0);
1178  $posy = $pdf->GetY() + 2;
1179  }
1180  }
1181  }
1182  }
1183 
1184  // If payment mode not forced or forced to VIR, show payment with BAN
1185  if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') {
1186  if ($object->fk_account > 0 || $object->fk_bank > 0 || getDolGlobalInt('FACTURE_RIB_NUMBER')) {
1187  $bankid = ($object->fk_account <= 0 ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account);
1188  if ($object->fk_bank > 0) {
1189  $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank
1190  }
1191  $account = new Account($this->db);
1192  $account->fetch($bankid);
1193 
1194  $curx = $this->marge_gauche;
1195  $cury = $posy;
1196 
1197  $posy = pdf_bank($pdf, $outputlangs, $curx, $cury, $account, 0, $default_font_size);
1198 
1199  $posy += 2;
1200  }
1201  }
1202  }
1203 
1204  return $posy;
1205  }
1206 
1207 
1219  protected function drawTotalTable(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis = null)
1220  {
1221  global $conf, $mysoc, $hookmanager;
1222 
1223  $default_font_size = pdf_getPDFFontSize($outputlangs);
1224 
1225  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) {
1226  $outputlangsbis = new Translate('', $conf);
1227  $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE);
1228  $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal"));
1229  $default_font_size--;
1230  }
1231 
1232  $tab2_top = $posy;
1233  $tab2_hl = 4;
1234  $pdf->SetFont('', '', $default_font_size - 1);
1235 
1236  // Total table
1237  $col1x = 120;
1238  $col2x = 170;
1239  if ($this->page_largeur < 210) { // To work with US executive format
1240  $col2x -= 20;
1241  }
1242  $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
1243 
1244  $useborder = 0;
1245  $index = 0;
1246 
1247  // Total HT
1248  $pdf->SetFillColor(255, 255, 255);
1249  $pdf->SetXY($col1x, $tab2_top);
1250  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("TotalHT") : ''), 0, 'L', 1);
1251 
1252  $total_ht = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht);
1253  $pdf->SetXY($col2x, $tab2_top);
1254  $pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + (!empty($object->remise) ? $object->remise : 0), 0, $outputlangs), 0, 'R', 1);
1255 
1256  // Show VAT by rates and total
1257  $pdf->SetFillColor(248, 248, 248);
1258 
1259  $total_ttc = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
1260 
1261  $this->atleastoneratenotnull = 0;
1262  if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) {
1263  $tvaisnull = ((!empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false);
1264  if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull) {
1265  // Nothing to do
1266  } else {
1267  //Local tax 1 before VAT
1268  //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1269  //{
1270  foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1271  if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1272  continue;
1273  }
1274 
1275  foreach ($localtax_rate as $tvakey => $tvaval) {
1276  if ($tvakey != 0) { // On affiche pas taux 0
1277  //$this->atleastoneratenotnull++;
1278 
1279  $index++;
1280  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1281 
1282  $tvacompl = '';
1283  if (preg_match('/\*/', $tvakey)) {
1284  $tvakey = str_replace('*', '', $tvakey);
1285  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1286  }
1287  $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : '');
1288  $totalvat .= ' ';
1289  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1290  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1291 
1292  $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1293 
1294  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1295  $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1);
1296  }
1297  }
1298  }
1299  //}
1300  //Local tax 2 before VAT
1301  //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1302  //{
1303  foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1304  if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1305  continue;
1306  }
1307 
1308  foreach ($localtax_rate as $tvakey => $tvaval) {
1309  if ($tvakey != 0) { // On affiche pas taux 0
1310  //$this->atleastoneratenotnull++;
1311 
1312  $index++;
1313  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1314 
1315  $tvacompl = '';
1316  if (preg_match('/\*/', $tvakey)) {
1317  $tvakey = str_replace('*', '', $tvakey);
1318  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1319  }
1320  $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : '');
1321  $totalvat .= ' ';
1322  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1323  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1324 
1325  $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1326 
1327  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1328  $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1);
1329  }
1330  }
1331  }
1332  //}
1333 
1334  // VAT
1335  foreach ($this->tva as $tvakey => $tvaval) {
1336  if ($tvakey != 0) { // On affiche pas taux 0
1337  $this->atleastoneratenotnull++;
1338 
1339  $index++;
1340  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1341 
1342  $tvacompl = '';
1343  if (preg_match('/\*/', $tvakey)) {
1344  $tvakey = str_replace('*', '', $tvakey);
1345  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1346  }
1347  $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalVAT", $mysoc->country_code) : '');
1348  $totalvat .= ' ';
1349  $totalvat .= vatrate($tvakey, 1).$tvacompl;
1350  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1351 
1352  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1353  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1354  }
1355  }
1356 
1357  //Local tax 1 after VAT
1358  //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1359  //{
1360  foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1361  if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1362  continue;
1363  }
1364 
1365  foreach ($localtax_rate as $tvakey => $tvaval) {
1366  if ($tvakey != 0) { // On affiche pas taux 0
1367  //$this->atleastoneratenotnull++;
1368 
1369  $index++;
1370  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1371 
1372  $tvacompl = '';
1373  if (preg_match('/\*/', $tvakey)) {
1374  $tvakey = str_replace('*', '', $tvakey);
1375  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1376  }
1377  $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : '');
1378  $totalvat .= ' ';
1379 
1380  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1381  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1382 
1383  $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1384 
1385  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1386  $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1);
1387  }
1388  }
1389  }
1390  //}
1391  //Local tax 2 after VAT
1392  //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1393  //{
1394  foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1395  if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1396  continue;
1397  }
1398 
1399  foreach ($localtax_rate as $tvakey => $tvaval) {
1400  // retrieve global local tax
1401  if ($tvakey != 0) { // On affiche pas taux 0
1402  //$this->atleastoneratenotnull++;
1403 
1404  $index++;
1405  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1406 
1407  $tvacompl = '';
1408  if (preg_match('/\*/', $tvakey)) {
1409  $tvakey = str_replace('*', '', $tvakey);
1410  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1411  }
1412  $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : '');
1413  $totalvat .= ' ';
1414 
1415  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1416  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1417 
1418  $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1419 
1420  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1421  $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1);
1422  }
1423  }
1424  }
1425  //}
1426 
1427  // Total TTC
1428  $index++;
1429  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1430  $pdf->SetTextColor(0, 0, 60);
1431  $pdf->SetFillColor(224, 224, 224);
1432  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("TotalTTC") : ''), $useborder, 'L', 1);
1433 
1434  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1435  $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', 1);
1436  }
1437  }
1438 
1439  $pdf->SetTextColor(0, 0, 0);
1440 
1441  $resteapayer = 0;
1442  /*
1443  $resteapayer = $object->total_ttc - $deja_regle;
1444  if (!empty($object->paye)) $resteapayer=0;
1445  */
1446 
1447  if ($deja_regle > 0) {
1448  // Already paid + Deposits
1449  $index++;
1450 
1451  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1452  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("AlreadyPaid") : ''), 0, 'L', 0);
1453 
1454  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1455  $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', 0);
1456 
1457  /*
1458  if ($object->close_code == 'discount_vat')
1459  {
1460  $index++;
1461  $pdf->SetFillColor(255,255,255);
1462 
1463  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1464  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("EscompteOfferedShort"), $useborder, 'L', 1);
1465 
1466  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1467  $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle, 0, $outputlangs), $useborder, 'R', 1);
1468 
1469  $resteapayer=0;
1470  }
1471  */
1472 
1473  $index++;
1474  $pdf->SetTextColor(0, 0, 60);
1475  $pdf->SetFillColor(224, 224, 224);
1476  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1477  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("RemainderToPay") : ''), $useborder, 'L', 1);
1478 
1479  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1480  $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1);
1481 
1482  $pdf->SetFont('', '', $default_font_size - 1);
1483  $pdf->SetTextColor(0, 0, 0);
1484  }
1485 
1486  $index++;
1487  return ($tab2_top + ($tab2_hl * $index));
1488  }
1489 
1490  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1505  protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '', $outputlangsbis = null)
1506  {
1507  global $conf;
1508 
1509  // Force to disable hidetop and hidebottom
1510  $hidebottom = 0;
1511  if ($hidetop) {
1512  $hidetop = -1;
1513  }
1514 
1515  $currency = !empty($currency) ? $currency : $conf->currency;
1516  $default_font_size = pdf_getPDFFontSize($outputlangs);
1517 
1518  // Amount in (at tab_top - 1)
1519  $pdf->SetTextColor(0, 0, 0);
1520  $pdf->SetFont('', '', $default_font_size - 2);
1521 
1522  if (empty($hidetop)) {
1523  $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
1524  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {
1525  $titre .= ' - '.$outputlangsbis->transnoentities("AmountInCurrency", $outputlangsbis->transnoentitiesnoconv("Currency".$currency));
1526  }
1527 
1528  $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
1529  $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
1530 
1531  //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
1532  if (!empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) {
1533  $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite - $this->marge_gauche, $this->tabTitleHeight, 'F', null, explode(',', $conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR));
1534  }
1535  }
1536 
1537  $pdf->SetDrawColor(128, 128, 128);
1538  $pdf->SetFont('', '', $default_font_size - 1);
1539 
1540  // Output Rect
1541  $this->printRect($pdf, $this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $tab_height, $hidetop, $hidebottom); // Rect takes a length in 3rd parameter and 4th parameter
1542 
1543  $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop);
1544 
1545  if (empty($hidetop)) {
1546  $pdf->line($this->marge_gauche, $tab_top + $this->tabTitleHeight, $this->page_largeur - $this->marge_droite, $tab_top + $this->tabTitleHeight); // line takes a position y in 2nd parameter and 4th parameter
1547  }
1548  }
1549 
1550  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1561  protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null)
1562  {
1563  global $conf, $langs;
1564 
1565  $ltrdirection = 'L';
1566  if ($outputlangs->trans("DIRECTION") == 'rtl') $ltrdirection = 'R';
1567 
1568  // Load traductions files required by page
1569  $outputlangs->loadLangs(array("main", "propal", "companies", "bills"));
1570 
1571  $default_font_size = pdf_getPDFFontSize($outputlangs);
1572 
1573  pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
1574 
1575  $pdf->SetTextColor(0, 0, 60);
1576  $pdf->SetFont('', 'B', $default_font_size + 3);
1577 
1578  $w = 100;
1579 
1580  $posy = $this->marge_haute;
1581  $posx = $this->page_largeur - $this->marge_droite - $w;
1582 
1583  $pdf->SetXY($this->marge_gauche, $posy);
1584 
1585  // Logo
1586  if (!getDolGlobalInt('PDF_DISABLE_MYCOMPANY_LOGO')) {
1587  if ($this->emetteur->logo) {
1588  $logodir = $conf->mycompany->dir_output;
1589  if (!empty($conf->mycompany->multidir_output[$object->entity])) {
1590  $logodir = $conf->mycompany->multidir_output[$object->entity];
1591  }
1592  if (!getDolGlobalInt('MAIN_PDF_USE_LARGE_LOGO')) {
1593  $logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
1594  } else {
1595  $logo = $logodir.'/logos/'.$this->emetteur->logo;
1596  }
1597  if (is_readable($logo)) {
1598  $height = pdf_getHeightForLogo($logo);
1599  $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
1600  } else {
1601  $pdf->SetTextColor(200, 0, 0);
1602  $pdf->SetFont('', 'B', $default_font_size - 2);
1603  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
1604  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
1605  }
1606  } else {
1607  $text = $this->emetteur->name;
1608  $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);
1609  }
1610  }
1611 
1612  $pdf->SetFont('', 'B', $default_font_size + 3);
1613  $pdf->SetXY($posx, $posy);
1614  $pdf->SetTextColor(0, 0, 60);
1615  $title = $outputlangs->transnoentities("PdfCommercialProposalTitle");
1616  $title .= ' '.$outputlangs->convToOutputCharset($object->ref);
1617  if ($object->statut == $object::STATUS_DRAFT) {
1618  $pdf->SetTextColor(128, 0, 0);
1619  $title .= ' - '.$outputlangs->transnoentities("NotValidated");
1620  }
1621 
1622  $pdf->MultiCell($w, 4, $title, '', 'R');
1623 
1624  $pdf->SetFont('', 'B', $default_font_size);
1625 
1626  /*
1627  $posy += 5;
1628  $pdf->SetXY($posx, $posy);
1629  $pdf->SetTextColor(0, 0, 60);
1630  $textref = $outputlangs->transnoentities("Ref")." : ".$outputlangs->convToOutputCharset($object->ref);
1631  if ($object->statut == $object::STATUS_DRAFT) {
1632  $pdf->SetTextColor(128, 0, 0);
1633  $textref .= ' - '.$outputlangs->transnoentities("NotValidated");
1634  }
1635  $pdf->MultiCell($w, 4, $textref, '', 'R');
1636  */
1637 
1638  $posy += 3;
1639  $pdf->SetFont('', '', $default_font_size - 2);
1640 
1641  if ($object->ref_client) {
1642  $posy += 4;
1643  $pdf->SetXY($posx, $posy);
1644  $pdf->SetTextColor(0, 0, 60);
1645  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".dol_trunc($outputlangs->convToOutputCharset($object->ref_client), 65), '', 'R');
1646  }
1647 
1648  if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) {
1649  $object->fetch_projet();
1650  if (!empty($object->project->ref)) {
1651  $posy += 3;
1652  $pdf->SetXY($posx, $posy);
1653  $pdf->SetTextColor(0, 0, 60);
1654  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->project->title), '', 'R');
1655  }
1656  }
1657 
1658  if (!empty($conf->global->PDF_SHOW_PROJECT)) {
1659  $object->fetch_projet();
1660  if (!empty($object->project->ref)) {
1661  $outputlangs->load("projects");
1662  $posy += 3;
1663  $pdf->SetXY($posx, $posy);
1664  $pdf->SetTextColor(0, 0, 60);
1665  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefProject")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R');
1666  }
1667  }
1668 
1669  if (!empty($conf->global->MAIN_PDF_DATE_TEXT)) {
1670  $displaydate = "daytext";
1671  } else {
1672  $displaydate = "day";
1673  }
1674 
1675  //$posy += 4;
1676  $posy = $pdf->getY();
1677  $pdf->SetXY($posx, $posy);
1678  $pdf->SetTextColor(0, 0, 60);
1679  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Date")." : ".dol_print_date($object->date, $displaydate, false, $outputlangs, true), '', 'R');
1680 
1681  $posy += 4;
1682  $pdf->SetXY($posx, $posy);
1683  $pdf->SetTextColor(0, 0, 60);
1684 
1685  $title = $outputlangs->transnoentities("DateEndPropal");
1686  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {
1687  $title .= ' - '.$outputlangsbis->transnoentities("DateEndPropal");
1688  }
1689  $pdf->MultiCell($w, 3, $title." : ".dol_print_date($object->fin_validite, $displaydate, false, $outputlangs, true), '', 'R');
1690 
1691  if (empty($conf->global->MAIN_PDF_HIDE_CUSTOMER_CODE) && $object->thirdparty->code_client) {
1692  $posy += 4;
1693  $pdf->SetXY($posx, $posy);
1694  $pdf->SetTextColor(0, 0, 60);
1695  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R');
1696  }
1697 
1698  // Get contact
1699  if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) {
1700  $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1701  if (count($arrayidcontact) > 0) {
1702  $usertmp = new User($this->db);
1703  $usertmp->fetch($arrayidcontact[0]);
1704  $posy += 4;
1705  $pdf->SetXY($posx, $posy);
1706  $pdf->SetTextColor(0, 0, 60);
1707  $pdf->MultiCell($w, 3, $langs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
1708  }
1709  }
1710 
1711  $posy += 2;
1712 
1713  $top_shift = 0;
1714  // Show list of linked objects
1715  $current_y = $pdf->getY();
1716  $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size);
1717  if ($current_y < $pdf->getY()) {
1718  $top_shift = $pdf->getY() - $current_y;
1719  }
1720 
1721  if ($showaddress) {
1722  // Sender properties
1723  $carac_emetteur = '';
1724  // Add internal contact of object if defined
1725  $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1726  if (count($arrayidcontact) > 0) {
1727  $object->fetch_user($arrayidcontact[0]);
1728  $labelbeforecontactname = ($outputlangs->transnoentities("FromContactName") != 'FromContactName' ? $outputlangs->transnoentities("FromContactName") : $outputlangs->transnoentities("Name"));
1729  $carac_emetteur .= ($carac_emetteur ? "\n" : '').$labelbeforecontactname." ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs));
1730  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ' (' : '';
1731  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && !empty($object->user->office_phone)) ? $object->user->office_phone : '';
1732  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ', ' : '';
1733  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT') && !empty($object->user->email)) ? $object->user->email : '';
1734  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ')' : '';
1735  $carac_emetteur .= "\n";
1736  }
1737 
1738  $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
1739 
1740  // Show sender
1741  $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42;
1742  $posy += $top_shift;
1743  $posx = $this->marge_gauche;
1744  if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1745  $posx = $this->page_largeur - $this->marge_droite - 80;
1746  }
1747 
1748  $hautcadre = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 38 : 40;
1749  $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 82;
1750 
1751  // Show sender frame
1752  if (empty($conf->global->MAIN_PDF_NO_SENDER_FRAME)) {
1753  $pdf->SetTextColor(0, 0, 0);
1754  $pdf->SetFont('', '', $default_font_size - 2);
1755  $pdf->SetXY($posx, $posy - 5);
1756  $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillFrom"), 0, $ltrdirection);
1757  $pdf->SetXY($posx, $posy);
1758  $pdf->SetFillColor(230, 230, 230);
1759  $pdf->MultiCell($widthrecbox, $hautcadre, "", 0, 'R', 1);
1760  $pdf->SetTextColor(0, 0, 60);
1761  }
1762 
1763  // Show sender name
1764  if (empty($conf->global->MAIN_PDF_HIDE_SENDER_NAME)) {
1765  $pdf->SetXY($posx + 2, $posy + 3);
1766  $pdf->SetFont('', 'B', $default_font_size);
1767  $pdf->MultiCell($widthrecbox - 2, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, $ltrdirection);
1768  $posy = $pdf->getY();
1769  }
1770 
1771  // Show sender information
1772  $pdf->SetXY($posx + 2, $posy);
1773  $pdf->SetFont('', '', $default_font_size - 1);
1774  $pdf->MultiCell($widthrecbox - 2, 4, $carac_emetteur, 0, $ltrdirection);
1775 
1776 
1777  // If CUSTOMER contact defined, we use it
1778  $usecontact = false;
1779  $arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
1780  if (count($arrayidcontact) > 0) {
1781  $usecontact = true;
1782  $result = $object->fetch_contact($arrayidcontact[0]);
1783  }
1784 
1785  // Recipient name
1786  if ($usecontact && ($object->contact->socid != $object->thirdparty->id && (!isset($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT) || !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)))) {
1787  $thirdparty = $object->contact;
1788  } else {
1789  $thirdparty = $object->thirdparty;
1790  }
1791 
1792  $carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);
1793 
1794  $mode = 'target';
1795  $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), $usecontact, $mode, $object);
1796 
1797  // Show recipient
1798  $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100;
1799  if ($this->page_largeur < 210) {
1800  $widthrecbox = 84; // To work with US executive format
1801  }
1802  $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42;
1803  $posy += $top_shift;
1804  $posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
1805  if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1806  $posx = $this->marge_gauche;
1807  }
1808 
1809  // Show recipient frame
1810  if (empty($conf->global->MAIN_PDF_NO_RECIPENT_FRAME)) {
1811  $pdf->SetTextColor(0, 0, 0);
1812  $pdf->SetFont('', '', $default_font_size - 2);
1813  $pdf->SetXY($posx + 2, $posy - 5);
1814  $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo"), 0, $ltrdirection);
1815  $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
1816  }
1817 
1818  // Show recipient name
1819  $pdf->SetXY($posx + 2, $posy + 3);
1820  $pdf->SetFont('', 'B', $default_font_size);
1821  $pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, $ltrdirection);
1822 
1823  $posy = $pdf->getY();
1824 
1825  // Show recipient information
1826  $pdf->SetFont('', '', $default_font_size - 1);
1827  $pdf->SetXY($posx + 2, $posy);
1828  $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, $ltrdirection);
1829  }
1830 
1831  $pdf->SetTextColor(0, 0, 0);
1832  return $top_shift;
1833  }
1834 
1835  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1845  protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
1846  {
1847  $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0);
1848  return pdf_pagefoot($pdf, $outputlangs, 'PROPOSAL_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext, $this->page_largeur, $this->watermark);
1849  }
1850 
1860  protected function drawSignatureArea(&$pdf, $object, $posy, $outputlangs)
1861  {
1862  global $conf;
1863  $default_font_size = pdf_getPDFFontSize($outputlangs);
1864  $tab_top = $posy + 4;
1865  $tab_hl = 4;
1866 
1867  $posx = 120;
1868  $largcol = ($this->page_largeur - $this->marge_droite - $posx);
1869  $useborder = 0;
1870  $index = 0;
1871  // Total HT
1872  $pdf->SetFillColor(255, 255, 255);
1873  $pdf->SetXY($posx, $tab_top);
1874  $pdf->SetFont('', '', $default_font_size - 2);
1875  $pdf->MultiCell($largcol, $tab_hl, $outputlangs->transnoentities("ProposalCustomerSignature"), 0, 'L', 1);
1876 
1877  $pdf->SetXY($posx, $tab_top + $tab_hl);
1878  $pdf->MultiCell($largcol, $tab_hl * 3, '', 1, 'R');
1879  if (!empty($conf->global->MAIN_PDF_PROPAL_USE_ELECTRONIC_SIGNING)) {
1880  $pdf->addEmptySignatureAppearance($posx, $tab_top + $tab_hl, $largcol, $tab_hl * 3);
1881  }
1882 
1883  return ($tab_hl * 7);
1884  }
1885 
1886 
1897  public function defineColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1898  {
1899  global $conf, $hookmanager;
1900 
1901  // Default field style for content
1902  $this->defaultContentsFieldsStyle = array(
1903  'align' => 'R', // R,C,L
1904  'padding' => array(1, 0.5, 1, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1905  );
1906 
1907  // Default field style for content
1908  $this->defaultTitlesFieldsStyle = array(
1909  'align' => 'C', // R,C,L
1910  'padding' => array(0.5, 0, 0.5, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1911  );
1912 
1913  /*
1914  * For exemple
1915  $this->cols['theColKey'] = array(
1916  'rank' => $rank, // int : use for ordering columns
1917  'width' => 20, // the column width in mm
1918  'title' => array(
1919  'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
1920  'label' => ' ', // the final label : used fore final generated text
1921  'align' => 'L', // text alignement : R,C,L
1922  'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1923  ),
1924  'content' => array(
1925  'align' => 'L', // text alignement : R,C,L
1926  'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1927  ),
1928  );
1929  */
1930 
1931  $rank = 0; // do not use negative rank
1932  $this->cols['desc'] = array(
1933  'rank' => $rank,
1934  'width' => false, // only for desc
1935  'status' => true,
1936  'title' => array(
1937  'textkey' => 'Designation', // use lang key is usefull in somme case with module
1938  'align' => 'L',
1939  // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
1940  // 'label' => ' ', // the final label
1941  'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1942  ),
1943  'content' => array(
1944  'align' => 'L',
1945  'padding' => array(1, 0.5, 1, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1946  ),
1947  );
1948 
1949  // Image of product
1950  $rank = $rank + 10;
1951  $this->cols['photo'] = array(
1952  'rank' => $rank,
1953  'width' => (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH) ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH), // in mm
1954  'status' => false,
1955  'title' => array(
1956  'textkey' => 'Photo',
1957  'label' => ' '
1958  ),
1959  'content' => array(
1960  'padding' => array(0, 0, 0, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1961  ),
1962  'border-left' => false, // remove left line separator
1963  );
1964 
1965  if (!empty($conf->global->MAIN_GENERATE_PROPOSALS_WITH_PICTURE) && !empty($this->atleastonephoto)) {
1966  $this->cols['photo']['status'] = true;
1967  $this->cols['photo']['border-left'] = true;
1968  }
1969 
1970 
1971  $rank = $rank + 10;
1972  $this->cols['vat'] = array(
1973  'rank' => $rank,
1974  'status' => false,
1975  'width' => 16, // in mm
1976  'title' => array(
1977  'textkey' => 'VAT'
1978  ),
1979  'border-left' => true, // add left line separator
1980  );
1981 
1982  if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
1983  $this->cols['vat']['status'] = true;
1984  }
1985 
1986  $rank = $rank + 10;
1987  $this->cols['subprice'] = array(
1988  'rank' => $rank,
1989  'width' => 19, // in mm
1990  'status' => true,
1991  'title' => array(
1992  'textkey' => 'PriceUHT'
1993  ),
1994  'border-left' => true, // add left line separator
1995  );
1996 
1997  // Adapt dynamically the width of subprice, if text is too long.
1998  $tmpwidth = 0;
1999  $nblines = count($object->lines);
2000  for ($i = 0; $i < $nblines; $i++) {
2001  $tmpwidth2 = dol_strlen(dol_string_nohtmltag(pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails)));
2002  $tmpwidth = max($tmpwidth, $tmpwidth2);
2003  }
2004  if ($tmpwidth > 10) {
2005  $this->cols['subprice']['width'] += (2 * ($tmpwidth - 10));
2006  }
2007 
2008  $rank = $rank + 10;
2009  $this->cols['qty'] = array(
2010  'rank' => $rank,
2011  'width' => 16, // in mm
2012  'status' => true,
2013  'title' => array(
2014  'textkey' => 'Qty'
2015  ),
2016  'border-left' => true, // add left line separator
2017  );
2018 
2019  $rank = $rank + 10;
2020  $this->cols['unit'] = array(
2021  'rank' => $rank,
2022  'width' => 11, // in mm
2023  'status' => false,
2024  'title' => array(
2025  'textkey' => 'Unit'
2026  ),
2027  'border-left' => true, // add left line separator
2028  );
2029  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2030  $this->cols['unit']['status'] = true;
2031  }
2032 
2033  $rank = $rank + 10;
2034  $this->cols['discount'] = array(
2035  'rank' => $rank,
2036  'width' => 13, // in mm
2037  'status' => false,
2038  'title' => array(
2039  'textkey' => 'ReductionShort'
2040  ),
2041  'border-left' => true, // add left line separator
2042  );
2043  if ($this->atleastonediscount) {
2044  $this->cols['discount']['status'] = true;
2045  }
2046 
2047  $rank = $rank + 1000; // add a big offset to be sure is the last col because default extrafield rank is 100
2048  $this->cols['totalexcltax'] = array(
2049  'rank' => $rank,
2050  'width' => 26, // in mm
2051  'status' => empty($conf->global->PDF_PROPAL_HIDE_PRICE_EXCL_TAX) ? true : false,
2052  'title' => array(
2053  'textkey' => 'TotalHTShort'
2054  ),
2055  'border-left' => true, // add left line separator
2056  );
2057 
2058  $rank = $rank + 1010; // add a big offset to be sure is the last col because default extrafield rank is 100
2059  $this->cols['totalincltax'] = array(
2060  'rank' => $rank,
2061  'width' => 26, // in mm
2062  'status' => empty($conf->global->PDF_PROPAL_SHOW_PRICE_INCL_TAX) ? false : true,
2063  'title' => array(
2064  'textkey' => 'TotalTTCShort'
2065  ),
2066  'border-left' => true, // add left line separator
2067  );
2068 
2069  // Add extrafields cols
2070  if (!empty($object->lines)) {
2071  $line = reset($object->lines);
2072  $this->defineColumnExtrafield($line, $outputlangs, $hidedetails);
2073  }
2074 
2075  $parameters = array(
2076  'object' => $object,
2077  'outputlangs' => $outputlangs,
2078  'hidedetails' => $hidedetails,
2079  'hidedesc' => $hidedesc,
2080  'hideref' => $hideref
2081  );
2082 
2083  $reshook = $hookmanager->executeHooks('defineColumnField', $parameters, $this); // Note that $object may have been modified by hook
2084  if ($reshook < 0) {
2085  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2086  } elseif (empty($reshook)) {
2087  $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys
2088  } else {
2089  $this->cols = $hookmanager->resArray;
2090  }
2091  }
2092 }
Class to manage bank accounts.
prepareArrayColumnField($object, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Prepare Array Column Field.
getColumnStatus($colKey)
get column status from column key
printStdColumnContent($pdf, &$curY, $colKey, $columnText='')
print standard column content
pdfTabTitles(&$pdf, $tab_top, $tab_height, $outputlangs, $hidetop=0)
Print standard column content.
printColDescContent($pdf, &$curY, $colKey, $object, $i, $outputlangs, $hideref=0, $hidedesc=0, $issupplierline=0)
print description column content
getColumnContentXStart($colKey)
get column content X (abscissa) left position from column key
printRect($pdf, $x, $y, $l, $h, $hidetop=0, $hidebottom=0)
Rect pdf.
getExtrafieldContent($object, $extrafieldKey, $outputlangs=null)
get extrafield content for pdf writeHtmlCell compatibility usage for PDF line columns and object note...
defineColumnExtrafield($object, $outputlangs, $hidedetails=0)
Define Array Column Field for extrafields.
Class to manage hooks.
Classe mere des modeles de propale.
Class to manage products or services.
Put here description of your class.
Class to manage translations.
Class to manage Dolibarr users.
Definition: user.class.php:48
Class to generate PDF proposal Cyan.
drawTotalTable(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis=null)
Show total to pay.
defineColumnField($object, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Define Array Column Field.
_tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='', $outputlangsbis=null)
Show table for lines.
__construct($db)
Constructor.
_pagefoot(&$pdf, $object, $outputlangs, $hidefreetext=0)
Show footer of page.
_pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis=null)
Show top header of page.
write_file($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0)
Function to build pdf onto disk.
drawSignatureArea(&$pdf, $object, $posy, $outputlangs)
Show area for the customer to sign.
drawInfoTable(&$pdf, $object, $posy, $outputlangs)
Show miscellaneous information (payment mode, payment term, ...)
drawPaymentsTable(&$pdf, $object, $posy, $outputlangs)
Show payments table.
print *****$script_file(".$version.") pid cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
if(!function_exists('dolEscapeXML')) convertBackOfficeMediasLinksToPublicLinks($notetoshow)
Convert links to local wrapper to medias files into a string into a public external URL readable on i...
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_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).
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
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...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
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)
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
pdf_getSizeForImage($realpath)
Return dimensions to use for images onto PDF checking that width and height are not higher than maxim...
Definition: pdf.lib.php:2529
pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line total excluding tax.
Definition: pdf.lib.php:2284
pdf_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_getHeightForLogo($logo, $url=false)
Return height to use for Logo onto PDF.
Definition: pdf.lib.php:314
pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails=0)
Return line total including tax.
Definition: pdf.lib.php:2340
pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_basse, $marge_gauche, $page_hauteur, $object, $showdetails=0, $hidefreetext=0, $page_largeur=0, $watermark='')
Show footer of page for PDF generation.
Definition: pdf.lib.php:1010
pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line unit price excluding tax.
Definition: pdf.lib.php:1901
pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails=0)
Return line vat rate.
Definition: pdf.lib.php:1839
pdf_getlineunit($object, $i, $outputlangs, $hidedetails=0, $hookmanager=false)
Return line unit.
Definition: pdf.lib.php:2147
pdfGetHeightForHtmlContent(&$pdf, $htmlcontent)
Function to try to calculate height of a HTML Content.
Definition: pdf.lib.php:339
pdf_pagehead(&$pdf, $outputlangs, $page_height)
Show header of page for PDF generation.
Definition: pdf.lib.php:726
pdf_writeLinkedObjects(&$pdf, $object, $outputlangs, $posx, $posy, $w, $h, $align, $default_font_size)
Show linked objects for PDF generation.
Definition: pdf.lib.php:1338
pdf_bank(&$pdf, $outputlangs, $curx, $cury, $account, $onlynumber=0, $default_font_size=10)
Show bank informations for PDF generation.
Definition: pdf.lib.php:833
pdf_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition: pdf.lib.php:266
pdf_build_address($outputlangs, $sourcecompany, $targetcompany='', $targetcontact='', $usecontact=0, $mode='source', $object=null)
Return a string with full address formated for output on documents.
Definition: pdf.lib.php:435
pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails=0)
Return line remise percent.
Definition: pdf.lib.php:2190
pdf_getlineqty($object, $i, $outputlangs, $hidedetails=0)
Return line quantity.
Definition: pdf.lib.php:1986
pdf_getSubstitutionArray($outputlangs, $exclude=null, $object=null, $onlykey=0, $include=null)
Return array of possible substitutions for PDF content (without external module substitutions).
Definition: pdf.lib.php:758
pdf_getInstance($format='', $metric='mm', $pagetype='P')
Return a PDF instance object.
Definition: pdf.lib.php:127
pdfBuildThirdpartyName($thirdparty, Translate $outputlangs, $includealias=0)
Returns the name of the thirdparty.
Definition: pdf.lib.php:387
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:120
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:123