dolibarr  19.0.0-dev
pdf_azur.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-2018 Ferran Marcet <fmarcet@2byte.es>
10  * Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
11  * Copyright (C) 2019 Pierre Ardoin <mapiolca@me.com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program. If not, see <https://www.gnu.org/licenses/>.
25  * or see https://www.gnu.org/
26  */
27 
34 require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php';
35 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
36 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
38 require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
39 
40 
45 {
49  public $db;
50 
54  public $entity;
55 
59  public $name;
60 
64  public $description;
65 
69  public $update_main_doc_field;
70 
74  public $type;
75 
80  public $version = 'dolibarr';
81 
85  public $page_largeur;
86 
90  public $page_hauteur;
91 
95  public $format;
96 
100  public $marge_gauche;
101 
105  public $marge_droite;
106 
110  public $marge_haute;
111 
115  public $marge_basse;
116 
121  public $emetteur;
122 
123 
129  public function __construct($db)
130  {
131  global $conf, $langs, $mysoc;
132 
133  // Translations
134  $langs->loadLangs(array("main", "bills"));
135 
136  $this->db = $db;
137  $this->name = "azur";
138  $this->description = $langs->trans('DocModelAzurDescription');
139  $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template
140 
141  // Dimension page
142  $this->type = 'pdf';
143  $formatarray = pdf_getFormat();
144  $this->page_largeur = $formatarray['width'];
145  $this->page_hauteur = $formatarray['height'];
146  $this->format = array($this->page_largeur, $this->page_hauteur);
147  $this->marge_gauche = getDolGlobalInt('MAIN_PDF_MARGIN_LEFT', 10);
148  $this->marge_droite = getDolGlobalInt('MAIN_PDF_MARGIN_RIGHT', 10);
149  $this->marge_haute = getDolGlobalInt('MAIN_PDF_MARGIN_TOP', 10);
150  $this->marge_basse = getDolGlobalInt('MAIN_PDF_MARGIN_BOTTOM', 10);
151 
152  $this->option_logo = 1; // Display logo
153  $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION
154  $this->option_modereg = 1; // Display payment mode
155  $this->option_condreg = 1; // Display payment terms
156  $this->option_multilang = 1; // Available in several languages
157  $this->option_escompte = 0; // Displays if there has been a discount
158  $this->option_credit_note = 0; // Support credit notes
159  $this->option_freetext = 1; // Support add of a personalised text
160  $this->option_draft_watermark = 1; // Support add of a watermark on drafts
161  $this->watermark = '';
162 
163  // Get source company
164  $this->emetteur = $mysoc;
165  if (empty($this->emetteur->country_code)) {
166  $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined
167  }
168 
169  // Define position of columns
170  $this->posxdesc = $this->marge_gauche + 1;
171  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
172  $this->posxtva = 101;
173  $this->posxup = 118;
174  $this->posxqty = 135;
175  $this->posxunit = 151;
176  } else {
177  $this->posxtva = 106;
178  $this->posxup = 122;
179  $this->posxqty = 145;
180  $this->posxunit = 162;
181  }
182  $this->posxdiscount = 162;
183  $this->postotalht = 174;
184  if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) || !empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
185  $this->posxtva = $this->posxup;
186  }
187  $this->posxpicture = $this->posxtva - (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH) ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH); // width of images
188  if ($this->page_largeur < 210) { // To work with US executive format
189  $this->posxpicture -= 20;
190  $this->posxtva -= 20;
191  $this->posxup -= 20;
192  $this->posxqty -= 20;
193  $this->posxunit -= 20;
194  $this->posxdiscount -= 20;
195  $this->postotalht -= 20;
196  }
197 
198  $this->tva = array();
199  $this->tva_array = array();
200  $this->localtax1 = array();
201  $this->localtax2 = array();
202  $this->atleastoneratenotnull = 0;
203  $this->atleastonediscount = 0;
204  }
205 
206  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
218  public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
219  {
220  // phpcs:enable
221  global $user, $langs, $conf, $mysoc, $db, $hookmanager, $nblines;
222 
223  dol_syslog("write_file outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null'));
224 
225  if (!is_object($outputlangs)) {
226  $outputlangs = $langs;
227  }
228  // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
229  if (!empty($conf->global->MAIN_USE_FPDF)) {
230  $outputlangs->charset_output = 'ISO-8859-1';
231  }
232 
233  // Load translation files required by page
234  $outputlangs->loadLangs(array("main", "dict", "companies", "bills", "propal", "products"));
235 
236  global $outputlangsbis;
237  $outputlangsbis = null;
238  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) {
239  $outputlangsbis = new Translate('', $conf);
240  $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE);
241  $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal"));
242  }
243 
244  // Show Draft Watermark
245  if ($object->statut == $object::STATUS_DRAFT && getDolGlobalString('PROPALE_DRAFT_WATERMARK')) {
246  $this->watermark = getDolGlobalString('PROPALE_DRAFT_WATERMARK');
247  }
248 
249  $nblines = count($object->lines);
250 
251  // Loop on each lines to detect if there is at least one image to show
252  $realpatharray = array();
253  $this->atleastonephoto = false;
254  if (!empty($conf->global->MAIN_GENERATE_PROPOSALS_WITH_PICTURE)) {
255  $objphoto = new Product($this->db);
256 
257  for ($i = 0; $i < $nblines; $i++) {
258  if (empty($object->lines[$i]->fk_product)) {
259  continue;
260  }
261 
262  $objphoto->fetch($object->lines[$i]->fk_product);
263  //var_dump($objphoto->ref);exit;
264  if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
265  $pdir[0] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/";
266  $pdir[1] = get_exdir(0, 0, 0, 0, $objphoto, 'product').dol_sanitizeFileName($objphoto->ref).'/';
267  } else {
268  $pdir[0] = get_exdir(0, 0, 0, 0, $objphoto, 'product'); // default
269  $pdir[1] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/"; // alternative
270  }
271 
272  $arephoto = false;
273  $realpath = '';
274  foreach ($pdir as $midir) {
275  if (!$arephoto) {
276  if ($conf->entity != $objphoto->entity) {
277  $dir = $conf->product->multidir_output[$objphoto->entity].'/'.$midir; //Check repertories of current entities
278  } else {
279  $dir = $conf->product->dir_output.'/'.$midir; //Check repertory of the current product
280  }
281  foreach ($objphoto->liste_photos($dir, 1) as $key => $obj) {
282  if (!getDolGlobalInt('CAT_HIGH_QUALITY_IMAGES')) { // If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo
283  if ($obj['photo_vignette']) {
284  $filename = $obj['photo_vignette'];
285  } else {
286  $filename = $obj['photo'];
287  }
288  } else {
289  $filename = $obj['photo'];
290  }
291 
292  $realpath = $dir.$filename;
293  $arephoto = true;
294  $this->atleastonephoto = true;
295  }
296  }
297  }
298 
299  if ($realpath && $arephoto) {
300  $realpatharray[$i] = $realpath;
301  }
302  }
303  }
304 
305  if (count($realpatharray) == 0) {
306  $this->posxpicture = $this->posxtva;
307  }
308 
309  if ($conf->propal->multidir_output[$conf->entity]) {
310  $object->fetch_thirdparty();
311 
312  $deja_regle = 0;
313 
314  // Definition of $dir and $file
315  if ($object->specimen) {
316  $dir = $conf->propal->multidir_output[$conf->entity];
317  $file = $dir."/SPECIMEN.pdf";
318  } else {
319  $objectref = dol_sanitizeFileName($object->ref);
320  $dir = $conf->propal->multidir_output[$object->entity]."/".$objectref;
321  $file = $dir."/".$objectref.".pdf";
322  }
323 
324  if (!file_exists($dir)) {
325  if (dol_mkdir($dir) < 0) {
326  $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
327  return 0;
328  }
329  }
330 
331  if (file_exists($dir)) {
332  // Add pdfgeneration hook
333  if (!is_object($hookmanager)) {
334  include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
335  $hookmanager = new HookManager($this->db);
336  }
337  $hookmanager->initHooks(array('pdfgeneration'));
338  $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
339  global $action;
340  $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
341 
342  // Set nblines with the new content of lines after hook
343  $nblines = count($object->lines);
344  //$nbpayments = count($object->getListOfPayments());
345 
346  // Create pdf instance
347  $pdf = pdf_getInstance($this->format);
348  $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
349  $pdf->SetAutoPageBreak(1, 0);
350 
351  if (class_exists('TCPDF')) {
352  $pdf->setPrintHeader(false);
353  $pdf->setPrintFooter(false);
354  }
355  $pdf->SetFont(pdf_getPDFFont($outputlangs));
356  // Set path to the background PDF File
357  if (!empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) {
358  $logodir = $conf->mycompany->dir_output;
359  if (!empty($conf->mycompany->multidir_output[$object->entity])) {
360  $logodir = $conf->mycompany->multidir_output[$object->entity];
361  }
362  $pagecount = $pdf->setSourceFile($logodir.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND);
363  $tplidx = $pdf->importPage(1);
364  }
365 
366  $pdf->Open();
367  $pagenb = 0;
368  $pdf->SetDrawColor(128, 128, 128);
369 
370  $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
371  $pdf->SetSubject($outputlangs->transnoentities("PdfCommercialProposalTitle"));
372  $pdf->SetCreator("Dolibarr ".DOL_VERSION);
373  $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
374  $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfCommercialProposalTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
375  if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
376  $pdf->SetCompression(false);
377  }
378 
379  $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
380 
381  // Set $this->atleastonediscount if you have at least one discount
382  for ($i = 0; $i < $nblines; $i++) {
383  if ($object->lines[$i]->remise_percent) {
384  $this->atleastonediscount++;
385  }
386  }
387  if (empty($this->atleastonediscount)) {
388  $delta = ($this->postotalht - $this->posxdiscount);
389  $this->posxpicture += $delta;
390  $this->posxtva += $delta;
391  $this->posxup += $delta;
392  $this->posxqty += $delta;
393  $this->posxunit += $delta;
394  $this->posxdiscount += $delta;
395  // post of fields after are not modified, stay at same position
396  }
397 
398  // New page
399  $pdf->AddPage();
400  if (!empty($tplidx)) {
401  $pdf->useTemplate($tplidx);
402  }
403  $pagenb++;
404 
405  $heightforinfotot = 40; // Height reserved to output the info and total part
406  $heightforsignature = empty($conf->global->PROPAL_DISABLE_SIGNATURE) ? (pdfGetHeightForHtmlContent($pdf, $outputlangs->transnoentities("ProposalCustomerSignature")) + 10) : 0;
407  $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
408  $heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin)
409  if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)) {
410  $heightforfooter += 6;
411  }
412  //print $heightforinfotot + $heightforsignature + $heightforfreetext + $heightforfooter;exit;
413 
414  $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis);
415  $pdf->SetFont('', '', $default_font_size - 1);
416  $pdf->MultiCell(0, 3, ''); // Set interline to 3
417  $pdf->SetTextColor(0, 0, 0);
418 
419 
420  $tab_top = 90 + $top_shift;
421  $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
422 
423  // Incoterm
424  $height_incoterms = 0;
425  if (isModEnabled('incoterm')) {
426  $desc_incoterms = $object->getIncotermsForPDF();
427  if ($desc_incoterms) {
428  $tab_top -= 2;
429 
430  $pdf->SetFont('', '', $default_font_size - 1);
431  $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($desc_incoterms), 0, 1);
432  $nexY = $pdf->GetY();
433  $height_incoterms = $nexY - $tab_top;
434 
435  // Rect takes a length in 3rd parameter
436  $pdf->SetDrawColor(192, 192, 192);
437  $pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_incoterms + 1);
438 
439  $tab_top = $nexY + 6;
440  $height_incoterms += 4;
441  }
442  }
443 
444  // Displays notes
445  $notetoshow = empty($object->note_public) ? '' : $object->note_public;
446  if (!empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE)) {
447  // Get first sale rep
448  if (is_object($object->thirdparty)) {
449  $salereparray = $object->thirdparty->getSalesRepresentatives($user);
450  $salerepobj = new User($this->db);
451  $salerepobj->fetch($salereparray[0]['id']);
452  if (!empty($salerepobj->signature)) {
453  $notetoshow = dol_concatdesc($notetoshow, $salerepobj->signature);
454  }
455  }
456  }
457  // Extrafields in note
458  $extranote = $this->getExtrafieldsInHtml($object, $outputlangs);
459  if (!empty($extranote)) {
460  $notetoshow = dol_concatdesc($notetoshow, $extranote);
461  }
462  if (!empty($conf->global->MAIN_ADD_CREATOR_IN_NOTE) && $object->user_author_id > 0) {
463  $tmpuser = new User($this->db);
464  $tmpuser->fetch($object->user_author_id);
465 
466 
467  $creator_info = $langs->trans("CaseFollowedBy").' '.$tmpuser->getFullName($langs);
468  if ($tmpuser->email) $creator_info .= ', '.$langs->trans("EMail").': '.$tmpuser->email;
469  if ($tmpuser->office_phone) $creator_info .= ', '.$langs->trans("Phone").': '.$tmpuser->office_phone;
470 
471  $notetoshow = dol_concatdesc($notetoshow, $creator_info);
472  }
473 
474  if ($notetoshow) {
475  $tab_top -= 2;
476 
477  $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
478  complete_substitutions_array($substitutionarray, $outputlangs, $object);
479  $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
480  $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);
481 
482  $pdf->SetFont('', '', $default_font_size - 1);
483  $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($notetoshow), 0, 1);
484  $nexY = $pdf->GetY();
485  $height_note = $nexY - $tab_top;
486 
487  // Rect takes a length in 3rd parameter
488  $pdf->SetDrawColor(192, 192, 192);
489  $pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_note + 1);
490 
491  $tab_top = $nexY + 6;
492  }
493 
494  $iniY = $tab_top + 7;
495  $curY = $tab_top + 7;
496  $nexY = $tab_top + 7;
497 
498  // Loop on each lines
499  for ($i = 0; $i < $nblines; $i++) {
500  $curY = $nexY;
501  $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
502  $pdf->SetTextColor(0, 0, 0);
503 
504  // Define size of image if we need it
505  $imglinesize = array();
506  if (!empty($realpatharray[$i])) {
507  $imglinesize = pdf_getSizeForImage($realpatharray[$i]);
508  }
509 
510  $pdf->setTopMargin($tab_top_newpage);
511  $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext + $heightforsignature + $heightforinfotot); // The only function to edit the bottom margin of current page to set it.
512  $pageposbefore = $pdf->getPage();
513 
514  $showpricebeforepagebreak = 1;
515  $posYAfterImage = 0;
516  $posYAfterDescription = 0;
517 
518  // We start with Photo of product line
519  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
520  $pdf->AddPage('', '', true);
521  if (!empty($tplidx)) {
522  $pdf->useTemplate($tplidx);
523  }
524  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
525  $this->_pagehead($pdf, $object, 0, $outputlangs);
526  }
527  $pdf->setPage($pageposbefore + 1);
528 
529  $curY = $tab_top_newpage;
530 
531  // Allows data in the first page if description is long enough to break in multiples pages
532  if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {
533  $showpricebeforepagebreak = 1;
534  } else {
535  $showpricebeforepagebreak = 0;
536  }
537  }
538 
539  if (isset($imglinesize['width']) && isset($imglinesize['height'])) {
540  $curX = $this->posxpicture - 1;
541  $pdf->Image($realpatharray[$i], $curX + (($this->posxtva - $this->posxpicture - $imglinesize['width']) / 2), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi
542  // $pdf->Image does not increase value return by getY, so we save it manually
543  $posYAfterImage = $curY + $imglinesize['height'];
544  }
545 
546  // Description of product line
547  $curX = $this->posxdesc - 1;
548 
549  $pdf->startTransaction();
550  pdf_writelinedesc($pdf, $object, $i, $outputlangs, $this->posxpicture - $curX, 3, $curX, $curY, $hideref, $hidedesc);
551  $pageposafter = $pdf->getPage();
552  if ($pageposafter > $pageposbefore) { // There is a pagebreak
553  $pdf->rollbackTransaction(true);
554  $pageposafter = $pageposbefore;
555  //print $pageposafter.'-'.$pageposbefore;exit;
556  $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
557  pdf_writelinedesc($pdf, $object, $i, $outputlangs, $this->posxpicture - $curX, 3, $curX, $curY, $hideref, $hidedesc);
558 
559  $pageposafter = $pdf->getPage();
560  $posyafter = $pdf->GetY();
561  //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit;
562  if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforsignature + $heightforinfotot))) { // There is no space left for total+free text
563  if ($i == ($nblines - 1)) { // No more lines, and no space left to show total, so we create a new page
564  $pdf->AddPage('', '', true);
565  if (!empty($tplidx)) {
566  $pdf->useTemplate($tplidx);
567  }
568  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
569  $this->_pagehead($pdf, $object, 0, $outputlangs);
570  }
571  $pdf->setPage($pageposafter + 1);
572  }
573  } else {
574  // We found a page break
575 
576  // Allows data in the first page if description is long enough to break in multiples pages
577  if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {
578  $showpricebeforepagebreak = 1;
579  } else {
580  $showpricebeforepagebreak = 0;
581  }
582  }
583  } else // No pagebreak
584  {
585  $pdf->commitTransaction();
586  }
587  $posYAfterDescription = $pdf->GetY();
588 
589  $nexY = $pdf->GetY();
590  $pageposafter = $pdf->getPage();
591 
592  $pdf->setPage($pageposbefore);
593  $pdf->setTopMargin($this->marge_haute);
594  $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
595 
596  // We suppose that a too long description or photo were moved completely on next page
597  if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
598  $pdf->setPage($pageposafter);
599  $curY = $tab_top_newpage;
600  }
601 
602  $pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par defaut
603 
604  // VAT Rate
605  if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
606  $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
607  $pdf->SetXY($this->posxtva - 5, $curY);
608  $pdf->MultiCell($this->posxup - $this->posxtva + 4, 3, $vat_rate, 0, 'R');
609  }
610 
611  // Unit price before discount
612  $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);
613  $pdf->SetXY($this->posxup, $curY);
614  $pdf->MultiCell($this->posxqty - $this->posxup - 0.8, 3, $up_excl_tax, 0, 'R', 0);
615 
616  // Quantity
617  $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
618  $pdf->SetXY($this->posxqty, $curY);
619  $pdf->MultiCell($this->posxunit - $this->posxqty - 0.8, 4, $qty, 0, 'R'); // Enough for 6 chars
620 
621  // Unit
622  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
623  $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager);
624  $pdf->SetXY($this->posxunit, $curY);
625  $pdf->MultiCell($this->posxdiscount - $this->posxunit - 0.8, 4, $unit, 0, 'L');
626  }
627 
628  // Discount on line
629  $pdf->SetXY($this->posxdiscount, $curY);
630  if ($object->lines[$i]->remise_percent) {
631  $pdf->SetXY($this->posxdiscount - 2, $curY);
632  $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);
633  $pdf->MultiCell($this->postotalht - $this->posxdiscount + 2, 3, $remise_percent, 0, 'R');
634  }
635 
636  // Total HT line
637  $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails);
638  $pdf->SetXY($this->postotalht, $curY);
639  $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->postotalht, 3, $total_excl_tax, 0, 'R', 0);
640 
641  // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva
642  if (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) {
643  $tvaligne = $object->lines[$i]->multicurrency_total_tva;
644  } else {
645  $tvaligne = $object->lines[$i]->total_tva;
646  }
647 
648  $localtax1ligne = $object->lines[$i]->total_localtax1;
649  $localtax2ligne = $object->lines[$i]->total_localtax2;
650  $localtax1_rate = $object->lines[$i]->localtax1_tx;
651  $localtax2_rate = $object->lines[$i]->localtax2_tx;
652  $localtax1_type = $object->lines[$i]->localtax1_type;
653  $localtax2_type = $object->lines[$i]->localtax2_type;
654 
655  // TODO remise_percent is an obsolete field for object parent
656  /*if ($object->remise_percent) {
657  $tvaligne -= ($tvaligne * $object->remise_percent) / 100;
658  }
659  if ($object->remise_percent) {
660  $localtax1ligne -= ($localtax1ligne * $object->remise_percent) / 100;
661  }
662  if ($object->remise_percent) {
663  $localtax2ligne -= ($localtax2ligne * $object->remise_percent) / 100;
664  }*/
665 
666  $vatrate = (string) $object->lines[$i]->tva_tx;
667 
668  // Retrieve type from database for backward compatibility with old records
669  if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined
670  && (!empty($localtax1_rate) || !empty($localtax2_rate))) { // and there is local tax
671  $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $object->thirdparty, $mysoc);
672  $localtax1_type = isset($localtaxtmp_array[0]) ? $localtaxtmp_array[0] : '';
673  $localtax2_type = isset($localtaxtmp_array[2]) ? $localtaxtmp_array[2] : '';
674  }
675 
676  // retrieve global local tax
677  if ($localtax1_type && $localtax1ligne != 0) {
678  if (empty($this->localtax1[$localtax1_type][$localtax1_rate])) {
679  $this->localtax1[$localtax1_type][$localtax1_rate] = $localtax1ligne;
680  } else {
681  $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne;
682  }
683  }
684  if ($localtax2_type && $localtax2ligne != 0) {
685  if (empty($this->localtax2[$localtax2_type][$localtax2_rate])) {
686  $this->localtax2[$localtax2_type][$localtax2_rate] = $localtax2ligne;
687  } else {
688  $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne;
689  }
690  }
691 
692  if (($object->lines[$i]->info_bits & 0x01) == 0x01) {
693  $vatrate .= '*';
694  }
695 
696  // Fill $this->tva and $this->tva_array
697  if (!isset($this->tva[$vatrate])) {
698  $this->tva[$vatrate] = 0;
699  }
700  $this->tva[$vatrate] += $tvaligne;
701  $vatcode = $object->lines[$i]->vat_src_code;
702  if (empty($this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'])) {
703  $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] = 0;
704  }
705  $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')] = array('vatrate'=>$vatrate, 'vatcode'=>$vatcode, 'amount'=> $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] + $tvaligne);
706 
707  if ($posYAfterImage > $posYAfterDescription) {
708  $nexY = $posYAfterImage;
709  }
710 
711  // Add line
712  if (!empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblines - 1)) {
713  $pdf->setPage($pageposafter);
714  $pdf->SetLineStyle(array('dash'=>'1,1', 'color'=>array(80, 80, 80)));
715  //$pdf->SetDrawColor(190,190,200);
716  $pdf->line($this->marge_gauche, $nexY + 1, $this->page_largeur - $this->marge_droite, $nexY + 1);
717  $pdf->SetLineStyle(array('dash'=>0));
718  }
719 
720  $nexY += 2; // Add space between lines
721 
722  // Detect if some page were added automatically and output _tableau for past pages
723  while ($pagenb < $pageposafter) {
724  $pdf->setPage($pagenb);
725  if ($pagenb == 1) {
726  $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
727  } else {
728  $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
729  }
730  $this->_pagefoot($pdf, $object, $outputlangs, 1);
731  $pagenb++;
732  $pdf->setPage($pagenb);
733  $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
734  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
735  $this->_pagehead($pdf, $object, 0, $outputlangs);
736  }
737  if (!empty($tplidx)) {
738  $pdf->useTemplate($tplidx);
739  }
740  }
741  if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) {
742  if ($pagenb == 1) {
743  $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
744  } else {
745  $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
746  }
747  $this->_pagefoot($pdf, $object, $outputlangs, 1);
748  // New page
749  $pdf->AddPage();
750  if (!empty($tplidx)) {
751  $pdf->useTemplate($tplidx);
752  }
753  $pagenb++;
754  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
755  $this->_pagehead($pdf, $object, 0, $outputlangs);
756  }
757  }
758  }
759 
760  // Show square
761  if ($pagenb == 1) {
762  $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code);
763  $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter + 1;
764  } else {
765  $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code);
766  $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter + 1;
767  }
768 
769  // Affiche zone infos
770  $posy = $this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs);
771 
772  // Affiche zone totaux
773  $posy = $this->_tableau_tot($pdf, $object, 0, $bottomlasttab, $outputlangs);
774 
775  // Affiche zone versements
776  /*
777  if ($deja_regle || $amount_credit_notes_included || $amount_deposits_included)
778  {
779  $posy=$this->_tableau_versements($pdf, $object, $posy, $outputlangs);
780  }
781  */
782 
783  // Customer signature area
784  if (empty($conf->global->PROPAL_DISABLE_SIGNATURE)) {
785  $posy = $this->_signature_area($pdf, $object, $posy, $outputlangs);
786  }
787 
788  // Pied de page
789  $this->_pagefoot($pdf, $object, $outputlangs);
790  if (method_exists($pdf, 'AliasNbPages')) {
791  $pdf->AliasNbPages();
792  }
793 
794  //If propal merge product PDF is active
795  if (!empty($conf->global->PRODUIT_PDF_MERGE_PROPAL)) {
796  require_once DOL_DOCUMENT_ROOT.'/product/class/propalmergepdfproduct.class.php';
797 
798  $already_merged = array();
799  foreach ($object->lines as $line) {
800  if (!empty($line->fk_product) && !(in_array($line->fk_product, $already_merged))) {
801  // Find the desire PDF
802  $filetomerge = new Propalmergepdfproduct($this->db);
803 
804  if (getDolGlobalInt('MAIN_MULTILANGS')) {
805  $filetomerge->fetch_by_product($line->fk_product, $outputlangs->defaultlang);
806  } else {
807  $filetomerge->fetch_by_product($line->fk_product);
808  }
809 
810  $already_merged[] = $line->fk_product;
811 
812  $product = new Product($this->db);
813  $product->fetch($line->fk_product);
814 
815  if ($product->entity != $conf->entity) {
816  $entity_product_file = $product->entity;
817  } else {
818  $entity_product_file = $conf->entity;
819  }
820 
821  // If PDF is selected and file is not empty
822  if (count($filetomerge->lines) > 0) {
823  foreach ($filetomerge->lines as $linefile) {
824  if (!empty($linefile->id) && !empty($linefile->file_name)) {
825  if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
826  if (isModEnabled("product")) {
827  $filetomerge_dir = $conf->product->multidir_output[$entity_product_file].'/'.get_exdir($product->id, 2, 0, 0, $product, 'product').$product->id."/photos";
828  } elseif (isModEnabled("service")) {
829  $filetomerge_dir = $conf->service->multidir_output[$entity_product_file].'/'.get_exdir($product->id, 2, 0, 0, $product, 'product').$product->id."/photos";
830  }
831  } else {
832  if (isModEnabled("product")) {
833  $filetomerge_dir = $conf->product->multidir_output[$entity_product_file].'/'.get_exdir(0, 0, 0, 0, $product, 'product');
834  } elseif (isModEnabled("service")) {
835  $filetomerge_dir = $conf->service->multidir_output[$entity_product_file].'/'.get_exdir(0, 0, 0, 0, $product, 'product');
836  }
837  }
838 
839  dol_syslog(get_class($this).':: upload_dir='.$filetomerge_dir, LOG_DEBUG);
840 
841  $infile = $filetomerge_dir.'/'.$linefile->file_name;
842  if (file_exists($infile) && is_readable($infile)) {
843  $pagecount = $pdf->setSourceFile($infile);
844  for ($i = 1; $i <= $pagecount; $i++) {
845  $tplIdx = $pdf->importPage($i);
846  if ($tplIdx !== false) {
847  $s = $pdf->getTemplatesize($tplIdx);
848  $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
849  $pdf->useTemplate($tplIdx);
850  } else {
851  setEventMessages(null, array($infile.' cannot be added, probably protected PDF'), 'warnings');
852  }
853  }
854  }
855  }
856  }
857  }
858  }
859  }
860  }
861 
862  $pdf->Close();
863 
864  $pdf->Output($file, 'F');
865 
866  //Add pdfgeneration hook
867  $hookmanager->initHooks(array('pdfgeneration'));
868  $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
869  global $action;
870  $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
871  if ($reshook < 0) {
872  $this->error = $hookmanager->error;
873  $this->errors = $hookmanager->errors;
874  }
875 
876  dolChmod($file);
877 
878  $this->result = array('fullpath'=>$file);
879 
880  return 1; // No error
881  } else {
882  $this->error = $langs->trans("ErrorCanNotCreateDir", $dir);
883  return 0;
884  }
885  } else {
886  $this->error = $langs->trans("ErrorConstantNotDefined", "PROP_OUTPUTDIR");
887  return 0;
888  }
889  }
890 
891  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
892  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
902  protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs)
903  {
904  // phpcs:enable
905  return 1;
906  }
907 
908  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
909  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
919  protected function _tableau_info(&$pdf, $object, $posy, $outputlangs)
920  {
921  // phpcs:enable
922  global $conf, $mysoc;
923  $default_font_size = pdf_getPDFFontSize($outputlangs);
924 
925  $pdf->SetFont('', '', $default_font_size - 1);
926 
927  $diffsizetitle = (empty($conf->global->PDF_DIFFSIZE_TITLE) ? 3 : $conf->global->PDF_DIFFSIZE_TITLE);
928 
929  // If France, show VAT mention if not applicable
930  if ($this->emetteur->country_code == 'FR' && empty($mysoc->tva_assuj)) {
931  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
932  $pdf->SetXY($this->marge_gauche, $posy);
933  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0);
934 
935  $posy = $pdf->GetY() + 4;
936  }
937 
938  $posxval = 52;
939  if (!empty($conf->global->MAIN_PDF_DELIVERY_DATE_TEXT)) {
940  $displaydate = "daytext";
941  } else {
942  $displaydate = "day";
943  }
944 
945  // Show shipping date
946  if (!empty($object->delivery_date)) {
947  $outputlangs->load("sendings");
948  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
949  $pdf->SetXY($this->marge_gauche, $posy);
950  $titre = $outputlangs->transnoentities("DateDeliveryPlanned").':';
951  $pdf->MultiCell(80, 4, $titre, 0, 'L');
952  $pdf->SetFont('', '', $default_font_size -$diffsizetitle);
953  $pdf->SetXY($posxval, $posy);
954  $dlp = dol_print_date($object->delivery_date, $displaydate, false, $outputlangs, true);
955  $pdf->MultiCell(80, 4, $dlp, 0, 'L');
956 
957  $posy = $pdf->GetY() + 1;
958  } elseif ($object->availability_code || $object->availability) { // Show availability conditions
959  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
960  $pdf->SetXY($this->marge_gauche, $posy);
961  $titre = $outputlangs->transnoentities("AvailabilityPeriod").':';
962  $pdf->MultiCell(80, 4, $titre, 0, 'L');
963  $pdf->SetTextColor(0, 0, 0);
964  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
965  $pdf->SetXY($posxval, $posy);
966  $lib_availability = $outputlangs->transnoentities("AvailabilityType".$object->availability_code) != ('AvailabilityType'.$object->availability_code) ? $outputlangs->transnoentities("AvailabilityType".$object->availability_code) : $outputlangs->convToOutputCharset($object->availability);
967  $lib_availability = str_replace('\n', "\n", $lib_availability);
968  $pdf->MultiCell(80, 4, $lib_availability, 0, 'L');
969 
970  $posy = $pdf->GetY() + 1;
971  }
972 
973  // Show delivery mode
974  if (empty($conf->global->PROPOSAL_PDF_HIDE_DELIVERYMODE) && $object->shipping_method_id > 0) {
975  $outputlangs->load("sendings");
976 
977  $shipping_method_id = $object->shipping_method_id;
978  if (!empty($conf->global->SOCIETE_ASK_FOR_SHIPPING_METHOD) && !empty($this->emetteur->shipping_method_id)) {
979  $shipping_method_id = $this->emetteur->shipping_method_id;
980  }
981  $shipping_method_code = dol_getIdFromCode($this->db, $shipping_method_id, 'c_shipment_mode', 'rowid', 'code');
982  $shipping_method_label = dol_getIdFromCode($this->db, $shipping_method_id, 'c_shipment_mode', 'rowid', 'libelle');
983 
984  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
985  $pdf->SetXY($this->marge_gauche, $posy);
986  $titre = $outputlangs->transnoentities("SendingMethod").':';
987  $pdf->MultiCell(43, 4, $titre, 0, 'L');
988 
989  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
990  $pdf->SetXY($posxval, $posy);
991  $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;
992  $lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
993  $pdf->MultiCell(67, 4, $lib_condition_paiement, 0, 'L');
994 
995  $posy = $pdf->GetY() + 1;
996  }
997 
998  // Show payments conditions
999  if (empty($conf->global->PROPOSAL_PDF_HIDE_PAYMENTTERM) && $object->cond_reglement_code) {
1000  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1001  $pdf->SetXY($this->marge_gauche, $posy);
1002  $titre = $outputlangs->transnoentities("PaymentConditions").':';
1003  $pdf->MultiCell(43, 4, $titre, 0, 'L');
1004 
1005  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1006  $pdf->SetXY($posxval, $posy);
1007  $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);
1008  $lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
1009  if ($object->deposit_percent > 0) {
1010  $lib_condition_paiement = str_replace('__DEPOSIT_PERCENT__', $object->deposit_percent, $lib_condition_paiement);
1011  }
1012  $pdf->MultiCell(67, 4, $lib_condition_paiement, 0, 'L');
1013 
1014  $posy = $pdf->GetY() + 3;
1015  }
1016 
1017  if (empty($conf->global->PROPOSAL_PDF_HIDE_PAYMENTMODE)) {
1018  // Show payment mode
1019  if ($object->mode_reglement_code
1020  && $object->mode_reglement_code != 'CHQ'
1021  && $object->mode_reglement_code != 'VIR') {
1022  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1023  $pdf->SetXY($this->marge_gauche, $posy);
1024  $titre = $outputlangs->transnoentities("PaymentMode").':';
1025  $pdf->MultiCell(80, 5, $titre, 0, 'L');
1026  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1027  $pdf->SetXY($posxval, $posy);
1028  $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);
1029  $pdf->MultiCell(80, 5, $lib_mode_reg, 0, 'L');
1030 
1031  $posy = $pdf->GetY() + 2;
1032  }
1033 
1034  // Show payment mode CHQ
1035  if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ') {
1036  // Si mode reglement non force ou si force a CHQ
1037  if (getDolGlobalInt('FACTURE_CHQ_NUMBER')) {
1038  if ($conf->global->FACTURE_CHQ_NUMBER > 0) {
1039  $account = new Account($this->db);
1040  $account->fetch(getDolGlobalInt('FACTURE_CHQ_NUMBER'));
1041 
1042  $pdf->SetXY($this->marge_gauche, $posy);
1043  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1044  $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $account->proprio), 0, 'L', 0);
1045  $posy = $pdf->GetY() + 1;
1046 
1047  if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) {
1048  $pdf->SetXY($this->marge_gauche, $posy);
1049  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1050  $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0);
1051  $posy = $pdf->GetY() + 2;
1052  }
1053  }
1054  if ($conf->global->FACTURE_CHQ_NUMBER == -1) {
1055  $pdf->SetXY($this->marge_gauche, $posy);
1056  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1057  $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $this->emetteur->name), 0, 'L', 0);
1058  $posy = $pdf->GetY() + 1;
1059 
1060  if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) {
1061  $pdf->SetXY($this->marge_gauche, $posy);
1062  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1063  $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0);
1064  $posy = $pdf->GetY() + 2;
1065  }
1066  }
1067  }
1068  }
1069 
1070  // If payment mode not forced or forced to VIR, show payment with BAN
1071  if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') {
1072  if (!empty($object->fk_account) || !empty($object->fk_bank) || getDolGlobalInt('FACTURE_RIB_NUMBER')) {
1073  $bankid = (empty($object->fk_account) ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account);
1074  if (!empty($object->fk_bank)) {
1075  $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank
1076  }
1077  $account = new Account($this->db);
1078  $account->fetch($bankid);
1079 
1080  $curx = $this->marge_gauche;
1081  $cury = $posy;
1082 
1083  $posy = pdf_bank($pdf, $outputlangs, $curx, $cury, $account, 0, $default_font_size);
1084 
1085  $posy += 2;
1086  }
1087  }
1088  }
1089 
1090  return $posy;
1091  }
1092 
1093  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1094  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1106  protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis = null)
1107  {
1108  // phpcs:enable
1109  global $conf, $mysoc;
1110  $default_font_size = pdf_getPDFFontSize($outputlangs);
1111 
1112  $tab2_top = $posy;
1113  $tab2_hl = 4;
1114  $pdf->SetFont('', '', $default_font_size - 1);
1115 
1116  // Total table
1117  $col1x = 120;
1118  $col2x = 170;
1119  if ($this->page_largeur < 210) { // To work with US executive format
1120  $col2x -= 20;
1121  }
1122  $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
1123 
1124  $useborder = 0;
1125  $index = 0;
1126 
1127  // Total HT
1128  $pdf->SetFillColor(255, 255, 255);
1129  $pdf->SetXY($col1x, $tab2_top);
1130  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1);
1131 
1132  $total_ht = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht);
1133  $pdf->SetXY($col2x, $tab2_top);
1134  $pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + (!empty($object->remise) ? $object->remise : 0), 0, $outputlangs), 0, 'R', 1);
1135 
1136  // Show VAT by rates and total
1137  $pdf->SetFillColor(248, 248, 248);
1138 
1139  $total_ttc = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
1140 
1141  $this->atleastoneratenotnull = 0;
1142  if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) {
1143  $tvaisnull = ((!empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false);
1144  if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull) {
1145  // Nothing to do
1146  } else {
1147  //Local tax 1 before VAT
1148  //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1149  //{
1150  foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1151  if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1152  continue;
1153  }
1154 
1155  foreach ($localtax_rate as $tvakey => $tvaval) {
1156  if ($tvakey != 0) { // On affiche pas taux 0
1157  //$this->atleastoneratenotnull++;
1158 
1159  $index++;
1160  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1161 
1162  $tvacompl = '';
1163  if (preg_match('/\*/', $tvakey)) {
1164  $tvakey = str_replace('*', '', $tvakey);
1165  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1166  }
1167  $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).' ';
1168  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1169  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1170 
1171  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1172  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1173  }
1174  }
1175  }
1176  //}
1177  //Local tax 2 before VAT
1178  //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1179  //{
1180  foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1181  if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1182  continue;
1183  }
1184 
1185  foreach ($localtax_rate as $tvakey => $tvaval) {
1186  if ($tvakey != 0) { // On affiche pas taux 0
1187  //$this->atleastoneratenotnull++;
1188 
1189 
1190 
1191  $index++;
1192  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1193 
1194  $tvacompl = '';
1195  if (preg_match('/\*/', $tvakey)) {
1196  $tvakey = str_replace('*', '', $tvakey);
1197  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1198  }
1199  $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' ';
1200  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1201  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1202 
1203  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1204  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1205  }
1206  }
1207  }
1208  //}
1209 
1210  // VAT
1211  foreach ($this->tva_array as $tvakey => $tvaval) {
1212  if ($tvakey != 0) { // On affiche pas taux 0
1213  $this->atleastoneratenotnull++;
1214 
1215  $index++;
1216  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1217 
1218  $tvacompl = '';
1219  if (preg_match('/\*/', $tvakey)) {
1220  $tvakey = str_replace('*', '', $tvakey);
1221  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1222  }
1223  $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalVAT", $mysoc->country_code) : '');
1224  $totalvat .= ' ';
1225  if (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'rateonly') {
1226  $totalvat .= vatrate($tvaval['vatrate'], 1).$tvacompl;
1227  } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'codeonly') {
1228  $totalvat .= ($tvaval['vatcode'] ? $tvaval['vatcode'] : vatrate($tvaval['vatrate'], 1)).$tvacompl;
1229  } else {
1230  $totalvat .= vatrate($tvaval['vatrate'], 1).($tvaval['vatcode'] ? ' ('.$tvaval['vatcode'].')' : '').$tvacompl;
1231  }
1232  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1233 
1234  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1235  $pdf->MultiCell($largcol2, $tab2_hl, price(price2num($tvaval['amount'], 'MT'), 0, $outputlangs), 0, 'R', 1);
1236  }
1237  }
1238 
1239  //Local tax 1 after VAT
1240  //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1241  //{
1242  foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1243  if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1244  continue;
1245  }
1246 
1247  foreach ($localtax_rate as $tvakey => $tvaval) {
1248  if ($tvakey != 0) { // On affiche pas taux 0
1249  //$this->atleastoneratenotnull++;
1250 
1251  $index++;
1252  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1253 
1254  $tvacompl = '';
1255  if (preg_match('/\*/', $tvakey)) {
1256  $tvakey = str_replace('*', '', $tvakey);
1257  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1258  }
1259  $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).' ';
1260 
1261  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1262  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1263  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1264  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1265  }
1266  }
1267  }
1268  //}
1269  //Local tax 2 after VAT
1270  //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1271  //{
1272  foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1273  if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1274  continue;
1275  }
1276 
1277  foreach ($localtax_rate as $tvakey => $tvaval) {
1278  // retrieve global local tax
1279  if ($tvakey != 0) { // On affiche pas taux 0
1280  //$this->atleastoneratenotnull++;
1281 
1282  $index++;
1283  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1284 
1285  $tvacompl = '';
1286  if (preg_match('/\*/', $tvakey)) {
1287  $tvakey = str_replace('*', '', $tvakey);
1288  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1289  }
1290  $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' ';
1291 
1292  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1293  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1294 
1295  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1296  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1297  }
1298  }
1299  }
1300  //}
1301 
1302  // Total TTC
1303  $index++;
1304  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1305  $pdf->SetTextColor(0, 0, 60);
1306  $pdf->SetFillColor(224, 224, 224);
1307  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1);
1308 
1309  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1310  $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', 1);
1311  }
1312  }
1313 
1314  $pdf->SetTextColor(0, 0, 0);
1315 
1316  /*
1317  $resteapayer = $object->total_ttc - $deja_regle;
1318  if (!empty($object->paye)) $resteapayer=0;
1319  */
1320 
1321  if ($deja_regle > 0) {
1322  $index++;
1323 
1324  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1325  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid"), 0, 'L', 0);
1326 
1327  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1328  $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', 0);
1329 
1330  /*
1331  if ($object->close_code == 'discount_vat')
1332  {
1333  $index++;
1334  $pdf->SetFillColor(255,255,255);
1335 
1336  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1337  $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("EscompteOfferedShort"), $useborder, 'L', 1);
1338 
1339  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1340  $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle, 0, $outputlangs), $useborder, 'R', 1);
1341 
1342  $resteapayer=0;
1343  }
1344  */
1345 
1346  $index++;
1347  $pdf->SetTextColor(0, 0, 60);
1348  $pdf->SetFillColor(224, 224, 224);
1349  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1350  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1);
1351 
1352  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1353  $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1);
1354 
1355  $pdf->SetFont('', '', $default_font_size - 1);
1356  $pdf->SetTextColor(0, 0, 0);
1357  }
1358 
1359  $index++;
1360  return ($tab2_top + ($tab2_hl * $index));
1361  }
1362 
1363  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1377  protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '')
1378  {
1379  global $conf;
1380 
1381  // Force to disable hidetop and hidebottom
1382  $hidebottom = 0;
1383  if ($hidetop) {
1384  $hidetop = -1;
1385  }
1386 
1387  $currency = !empty($currency) ? $currency : $conf->currency;
1388  $default_font_size = pdf_getPDFFontSize($outputlangs);
1389 
1390  // Amount in (at tab_top - 1)
1391  $pdf->SetTextColor(0, 0, 0);
1392  $pdf->SetFont('', '', $default_font_size - 2);
1393 
1394  if (empty($hidetop)) {
1395  $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
1396  $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
1397  $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
1398 
1399  //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
1400  if (!empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) {
1401  $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite - $this->marge_gauche, 5, 'F', null, explode(',', $conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR));
1402  }
1403  }
1404 
1405  $pdf->SetDrawColor(128, 128, 128);
1406  $pdf->SetFont('', '', $default_font_size - 1);
1407 
1408  // Output Rect
1409  $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
1410 
1411  if (empty($hidetop)) {
1412  $pdf->line($this->marge_gauche, $tab_top + 5, $this->page_largeur - $this->marge_droite, $tab_top + 5); // line takes a position y in 2nd parameter and 4th parameter
1413 
1414  $pdf->SetXY($this->posxdesc - 1, $tab_top + 1);
1415  $pdf->MultiCell(108, 2, $outputlangs->transnoentities("Designation"), '', 'L');
1416  }
1417 
1418  if (!empty($conf->global->MAIN_GENERATE_PROPOSALS_WITH_PICTURE)) {
1419  $pdf->line($this->posxpicture - 1, $tab_top, $this->posxpicture - 1, $tab_top + $tab_height);
1420  if (empty($hidetop)) {
1421  //$pdf->SetXY($this->posxpicture-1, $tab_top+1);
1422  //$pdf->MultiCell($this->posxtva-$this->posxpicture-1,2, $outputlangs->transnoentities("Photo"),'','C');
1423  }
1424  }
1425 
1426  if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
1427  $pdf->line($this->posxtva - 1, $tab_top, $this->posxtva - 1, $tab_top + $tab_height);
1428  if (empty($hidetop)) {
1429  // Not do -3 and +3 instead of -1 -1 to have more space for text 'Sales tax'
1430  $pdf->SetXY($this->posxtva - 3, $tab_top + 1);
1431  $pdf->MultiCell($this->posxup - $this->posxtva + 3, 2, $outputlangs->transnoentities("VAT"), '', 'C');
1432  }
1433  }
1434 
1435  $pdf->line($this->posxup - 1, $tab_top, $this->posxup - 1, $tab_top + $tab_height);
1436  if (empty($hidetop)) {
1437  $pdf->SetXY($this->posxup - 1, $tab_top + 1);
1438  $pdf->MultiCell($this->posxqty - $this->posxup - 1, 2, $outputlangs->transnoentities("PriceUHT"), '', 'C');
1439  }
1440 
1441  $pdf->line($this->posxqty - 1, $tab_top, $this->posxqty - 1, $tab_top + $tab_height);
1442  if (empty($hidetop)) {
1443  $pdf->SetXY($this->posxqty - 1, $tab_top + 1);
1444  $pdf->MultiCell($this->posxunit - $this->posxqty - 1, 2, $outputlangs->transnoentities("Qty"), '', 'C');
1445  }
1446 
1447  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1448  $pdf->line($this->posxunit - 1, $tab_top, $this->posxunit - 1, $tab_top + $tab_height);
1449  if (empty($hidetop)) {
1450  $pdf->SetXY($this->posxunit - 1, $tab_top + 1);
1451  $pdf->MultiCell(
1452  $this->posxdiscount - $this->posxunit - 1,
1453  2,
1454  $outputlangs->transnoentities("Unit"),
1455  '',
1456  'C'
1457  );
1458  }
1459  }
1460 
1461  $pdf->line($this->posxdiscount - 1, $tab_top, $this->posxdiscount - 1, $tab_top + $tab_height);
1462  if (empty($hidetop)) {
1463  if ($this->atleastonediscount) {
1464  $pdf->SetXY($this->posxdiscount - 1, $tab_top + 1);
1465  $pdf->MultiCell($this->postotalht - $this->posxdiscount + 1, 2, $outputlangs->transnoentities("ReductionShort"), '', 'C');
1466  }
1467  }
1468  if ($this->atleastonediscount) {
1469  $pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height);
1470  }
1471  if (empty($hidetop)) {
1472  $pdf->SetXY($this->postotalht - 1, $tab_top + 1);
1473  $pdf->MultiCell(30, 2, $outputlangs->transnoentities("TotalHTShort"), '', 'C');
1474  }
1475  }
1476 
1477  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1488  protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null)
1489  {
1490  global $conf, $langs;
1491 
1492  $ltrdirection = 'L';
1493  if ($outputlangs->trans("DIRECTION") == 'rtl') $ltrdirection = 'R';
1494 
1495  // Load traductions files required by page
1496  $outputlangs->loadLangs(array("main", "propal", "companies", "bills"));
1497 
1498  $default_font_size = pdf_getPDFFontSize($outputlangs);
1499 
1500  pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
1501 
1502  $pdf->SetTextColor(0, 0, 60);
1503  $pdf->SetFont('', 'B', $default_font_size + 3);
1504 
1505  $w = 100;
1506 
1507  $posy = $this->marge_haute;
1508  $posx = $this->page_largeur - $this->marge_droite - $w;
1509 
1510  $pdf->SetXY($this->marge_gauche, $posy);
1511 
1512  // Logo
1513  if (!getDolGlobalInt('PDF_DISABLE_MYCOMPANY_LOGO')) {
1514  if ($this->emetteur->logo) {
1515  $logodir = $conf->mycompany->dir_output;
1516  if (!empty($conf->mycompany->multidir_output[$object->entity])) {
1517  $logodir = $conf->mycompany->multidir_output[$object->entity];
1518  }
1519  if (!getDolGlobalInt('MAIN_PDF_USE_LARGE_LOGO')) {
1520  $logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
1521  } else {
1522  $logo = $logodir.'/logos/'.$this->emetteur->logo;
1523  }
1524  if (is_readable($logo)) {
1525  $height = pdf_getHeightForLogo($logo);
1526  $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
1527  } else {
1528  $pdf->SetTextColor(200, 0, 0);
1529  $pdf->SetFont('', 'B', $default_font_size - 2);
1530  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
1531  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
1532  }
1533  } else {
1534  $text = $this->emetteur->name;
1535  $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);
1536  }
1537  }
1538 
1539  $pdf->SetFont('', 'B', $default_font_size + 3);
1540  $pdf->SetXY($posx, $posy);
1541  $pdf->SetTextColor(0, 0, 60);
1542  $title = $outputlangs->transnoentities("PdfCommercialProposalTitle");
1543  $title .= ' '.$outputlangs->convToOutputCharset($object->ref);
1544  if ($object->statut == $object::STATUS_DRAFT) {
1545  $pdf->SetTextColor(128, 0, 0);
1546  $title .= ' - '.$outputlangs->transnoentities("NotValidated");
1547  }
1548  $pdf->MultiCell(100, 4, $title, '', 'R');
1549 
1550  $pdf->SetFont('', 'B', $default_font_size);
1551 
1552  /*
1553  $posy += 5;
1554  $pdf->SetXY($posx, $posy);
1555  $pdf->SetTextColor(0, 0, 60);
1556  $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Ref")." : ".$outputlangs->convToOutputCharset($object->ref), '', 'R');
1557  */
1558 
1559  $posy += 3;
1560  $pdf->SetFont('', '', $default_font_size - 2);
1561 
1562  if ($object->ref_client) {
1563  $posy += 4;
1564  $pdf->SetXY($posx, $posy);
1565  $pdf->SetTextColor(0, 0, 60);
1566  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R');
1567  }
1568 
1569  if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) {
1570  $object->fetch_projet();
1571  if (!empty($object->project->ref)) {
1572  $posy += 3;
1573  $pdf->SetXY($posx, $posy);
1574  $pdf->SetTextColor(0, 0, 60);
1575  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->project->title), '', 'R');
1576  }
1577  }
1578 
1579  if (!empty($conf->global->PDF_SHOW_PROJECT)) {
1580  $object->fetch_projet();
1581  if (!empty($object->project->ref)) {
1582  $outputlangs->load("projects");
1583  $posy += 3;
1584  $pdf->SetXY($posx, $posy);
1585  $pdf->SetTextColor(0, 0, 60);
1586  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefProject")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R');
1587  }
1588  }
1589 
1590  if (!empty($conf->global->MAIN_PDF_DATE_TEXT)) {
1591  $displaydate = "daytext";
1592  } else {
1593  $displaydate = "day";
1594  }
1595 
1596  //$posy += 4;
1597  $posy = $pdf->getY();
1598  $pdf->SetXY($posx, $posy);
1599  $pdf->SetTextColor(0, 0, 60);
1600  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("DatePropal")." : ".dol_print_date($object->date, $displaydate, false, $outputlangs, true), '', 'R');
1601 
1602  $posy += 4;
1603  $pdf->SetXY($posx, $posy);
1604  $pdf->SetTextColor(0, 0, 60);
1605  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("DateEndPropal")." : ".dol_print_date($object->fin_validite, $displaydate, false, $outputlangs, true), '', 'R');
1606 
1607  if (empty($conf->global->MAIN_PDF_HIDE_CUSTOMER_CODE) && $object->thirdparty->code_client) {
1608  $posy += 4;
1609  $pdf->SetXY($posx, $posy);
1610  $pdf->SetTextColor(0, 0, 60);
1611  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R');
1612  }
1613 
1614  // Get contact
1615  if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) {
1616  $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1617  if (count($arrayidcontact) > 0) {
1618  $usertmp = new User($this->db);
1619  $usertmp->fetch($arrayidcontact[0]);
1620  $posy += 4;
1621  $pdf->SetXY($posx, $posy);
1622  $pdf->SetTextColor(0, 0, 60);
1623  $pdf->MultiCell(100, 3, $langs->trans("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
1624  }
1625  }
1626 
1627  $posy += 2;
1628 
1629  $top_shift = 0;
1630  // Show list of linked objects
1631  $current_y = $pdf->getY();
1632  $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size);
1633  if ($current_y < $pdf->getY()) {
1634  $top_shift = $pdf->getY() - $current_y;
1635  }
1636 
1637  if ($showaddress) {
1638  // Sender properties
1639  $carac_emetteur = '';
1640  // Add internal contact of object if defined
1641  $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1642  if (count($arrayidcontact) > 0) {
1643  $object->fetch_user($arrayidcontact[0]);
1644  $labelbeforecontactname = ($outputlangs->transnoentities("FromContactName") != 'FromContactName' ? $outputlangs->transnoentities("FromContactName") : $outputlangs->transnoentities("Name"));
1645  $carac_emetteur .= ($carac_emetteur ? "\n" : '').$labelbeforecontactname." ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs));
1646  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ' (' : '';
1647  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && !empty($object->user->office_phone)) ? $object->user->office_phone : '';
1648  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ', ' : '';
1649  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT') && !empty($object->user->email)) ? $object->user->email : '';
1650  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ')' : '';
1651  $carac_emetteur .= "\n";
1652  }
1653 
1654  $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
1655 
1656  // Show sender
1657  $posy = 42 + $top_shift;
1658  $posx = $this->marge_gauche;
1659  if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1660  $posx = $this->page_largeur - $this->marge_droite - 80;
1661  }
1662  $hautcadre = 40;
1663 
1664  // Show sender frame
1665  if (empty($conf->global->MAIN_PDF_NO_SENDER_FRAME)) {
1666  $pdf->SetTextColor(0, 0, 0);
1667  $pdf->SetFont('', '', $default_font_size - 2);
1668  $pdf->SetXY($posx, $posy - 5);
1669  $pdf->MultiCell(80, 5, $outputlangs->transnoentities("BillFrom"), 0, $ltrdirection);
1670  $pdf->SetXY($posx, $posy);
1671  $pdf->SetFillColor(230, 230, 230);
1672  $pdf->MultiCell(82, $hautcadre, "", 0, 'R', 1);
1673  $pdf->SetTextColor(0, 0, 60);
1674  }
1675 
1676  // Show company name
1677  if (empty($conf->global->MAIN_PDF_HIDE_SENDER_NAME)) {
1678  $pdf->SetXY($posx + 2, $posy + 3);
1679  $pdf->SetFont('', 'B', $default_font_size);
1680  $pdf->MultiCell(80, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, $ltrdirection);
1681  $posy = $pdf->getY();
1682  }
1683 
1684  // Show sender information
1685  $pdf->SetXY($posx + 2, $posy);
1686  $pdf->SetFont('', '', $default_font_size - 1);
1687  $pdf->MultiCell(80, 4, $carac_emetteur, 0, $ltrdirection);
1688 
1689 
1690  // If CUSTOMER contact defined, we use it
1691  $usecontact = false;
1692  $arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
1693  if (count($arrayidcontact) > 0) {
1694  $usecontact = true;
1695  $result = $object->fetch_contact($arrayidcontact[0]);
1696  }
1697 
1698  // Recipient name
1699  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)))) {
1700  $thirdparty = $object->contact;
1701  } else {
1702  $thirdparty = $object->thirdparty;
1703  }
1704 
1705  $carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);
1706 
1707  $mode = 'target';
1708  $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), $usecontact, $mode, $object);
1709 
1710  // Show recipient
1711  $widthrecbox = 100;
1712  if ($this->page_largeur < 210) {
1713  $widthrecbox = 84; // To work with US executive format
1714  }
1715  $posy = 42 + $top_shift;
1716  $posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
1717  if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1718  $posx = $this->marge_gauche;
1719  }
1720 
1721  // Show recipient frame
1722  if (empty($conf->global->MAIN_PDF_NO_RECIPENT_FRAME)) {
1723  $pdf->SetTextColor(0, 0, 0);
1724  $pdf->SetFont('', '', $default_font_size - 2);
1725  $pdf->SetXY($posx + 2, $posy - 5);
1726  $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo"), 0, $ltrdirection);
1727  $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
1728  }
1729 
1730  // Show recipient name
1731  $pdf->SetXY($posx + 2, $posy + 3);
1732  $pdf->SetFont('', 'B', $default_font_size);
1733  $pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, $ltrdirection);
1734 
1735  $posy = $pdf->getY();
1736 
1737  // Show recipient information
1738  $pdf->SetFont('', '', $default_font_size - 1);
1739  $pdf->SetXY($posx + 2, $posy);
1740  $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, $ltrdirection);
1741  }
1742 
1743  $pdf->SetTextColor(0, 0, 0);
1744  return $top_shift;
1745  }
1746 
1747  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1757  protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
1758  {
1759  $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0);
1760  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);
1761  }
1762 
1763  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1764  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1774  protected function _signature_area(&$pdf, $object, $posy, $outputlangs)
1775  {
1776  // phpcs:enable
1777  global $conf;
1778  $default_font_size = pdf_getPDFFontSize($outputlangs);
1779  $tab_top = $posy + 4;
1780  $tab_hl = 4;
1781 
1782  $posx = 120;
1783  $largcol = ($this->page_largeur - $this->marge_droite - $posx);
1784  $useborder = 0;
1785  $index = 0;
1786  // Total HT
1787  $pdf->SetFillColor(255, 255, 255);
1788  $pdf->SetXY($posx, $tab_top);
1789  $pdf->SetFont('', '', $default_font_size - 2);
1790  $pdf->MultiCell($largcol, $tab_hl, $outputlangs->transnoentities("ProposalCustomerSignature"), 0, 'L', 1);
1791 
1792  $pdf->SetXY($posx, $tab_top + $tab_hl);
1793  $pdf->MultiCell($largcol, $tab_hl * 3, '', 1, 'R');
1794  if (!empty($conf->global->MAIN_PDF_PROPAL_USE_ELECTRONIC_SIGNING)) {
1795  $pdf->addEmptySignatureAppearance($posx, $tab_top + $tab_hl, $largcol, $tab_hl * 3);
1796  }
1797 
1798  return ($tab_hl * 7);
1799  }
1800 }
Class to manage bank accounts.
printRect($pdf, $x, $y, $l, $h, $hidetop=0, $hidebottom=0)
Rect pdf.
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 Azur.
_tableau_info(&$pdf, $object, $posy, $outputlangs)
Show miscellaneous information (payment mode, payment term, ...)
__construct($db)
Constructor.
_pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis=null)
Show top header of page.
_signature_area(&$pdf, $object, $posy, $outputlangs)
Show area for the customer to sign.
_tableau_versements(&$pdf, $object, $posy, $outputlangs)
Show payments table.
_tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='')
Show table for lines.
write_file($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0)
Function to build pdf onto disk.
_pagefoot(&$pdf, $object, $outputlangs, $hidefreetext=0)
Show footer of page.
_tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis=null)
Show total to pay.
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.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
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_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:2520
pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line total excluding tax.
Definition: pdf.lib.php:2275
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_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_getHeightForLogo($logo, $url=false)
Return height to use for Logo onto PDF.
Definition: pdf.lib.php:314
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_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_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_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($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
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