dolibarr  18.0.6
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  $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1172 
1173  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1174  $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1);
1175  }
1176  }
1177  }
1178  //}
1179  //Local tax 2 before VAT
1180  //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1181  //{
1182  foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1183  if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1184  continue;
1185  }
1186 
1187  foreach ($localtax_rate as $tvakey => $tvaval) {
1188  if ($tvakey != 0) { // On affiche pas taux 0
1189  //$this->atleastoneratenotnull++;
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  $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1204 
1205  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1206  $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1);
1207  }
1208  }
1209  }
1210  //}
1211 
1212  // VAT
1213  foreach ($this->tva_array as $tvakey => $tvaval) {
1214  if ($tvakey != 0) { // On affiche pas taux 0
1215  $this->atleastoneratenotnull++;
1216 
1217  $index++;
1218  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1219 
1220  $tvacompl = '';
1221  if (preg_match('/\*/', $tvakey)) {
1222  $tvakey = str_replace('*', '', $tvakey);
1223  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1224  }
1225  $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalVAT", $mysoc->country_code) : '');
1226  $totalvat .= ' ';
1227  if (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'rateonly') {
1228  $totalvat .= vatrate($tvaval['vatrate'], 1).$tvacompl;
1229  } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'codeonly') {
1230  $totalvat .= ($tvaval['vatcode'] ? $tvaval['vatcode'] : vatrate($tvaval['vatrate'], 1)).$tvacompl;
1231  } else {
1232  $totalvat .= vatrate($tvaval['vatrate'], 1).($tvaval['vatcode'] ? ' ('.$tvaval['vatcode'].')' : '').$tvacompl;
1233  }
1234  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1235 
1236  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1237  $pdf->MultiCell($largcol2, $tab2_hl, price(price2num($tvaval['amount'], 'MT'), 0, $outputlangs), 0, 'R', 1);
1238  }
1239  }
1240 
1241  //Local tax 1 after VAT
1242  //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1243  //{
1244  foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1245  if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1246  continue;
1247  }
1248 
1249  foreach ($localtax_rate as $tvakey => $tvaval) {
1250  if ($tvakey != 0) { // On affiche pas taux 0
1251  //$this->atleastoneratenotnull++;
1252 
1253  $index++;
1254  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1255 
1256  $tvacompl = '';
1257  if (preg_match('/\*/', $tvakey)) {
1258  $tvakey = str_replace('*', '', $tvakey);
1259  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1260  }
1261  $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).' ';
1262 
1263  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1264  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1265 
1266  $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1267 
1268  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1269  $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1);
1270  }
1271  }
1272  }
1273  //}
1274  //Local tax 2 after VAT
1275  //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1276  //{
1277  foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1278  if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1279  continue;
1280  }
1281 
1282  foreach ($localtax_rate as $tvakey => $tvaval) {
1283  // retrieve global local tax
1284  if ($tvakey != 0) { // On affiche pas taux 0
1285  //$this->atleastoneratenotnull++;
1286 
1287  $index++;
1288  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1289 
1290  $tvacompl = '';
1291  if (preg_match('/\*/', $tvakey)) {
1292  $tvakey = str_replace('*', '', $tvakey);
1293  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1294  }
1295  $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' ';
1296 
1297  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1298  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1299 
1300  $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1301 
1302  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1303  $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1);
1304  }
1305  }
1306  }
1307  //}
1308 
1309  // Total TTC
1310  $index++;
1311  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1312  $pdf->SetTextColor(0, 0, 60);
1313  $pdf->SetFillColor(224, 224, 224);
1314  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1);
1315 
1316  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1317  $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', 1);
1318  }
1319  }
1320 
1321  $pdf->SetTextColor(0, 0, 0);
1322 
1323  /*
1324  $resteapayer = $object->total_ttc - $deja_regle;
1325  if (!empty($object->paye)) $resteapayer=0;
1326  */
1327 
1328  if ($deja_regle > 0) {
1329  $index++;
1330 
1331  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1332  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid"), 0, 'L', 0);
1333 
1334  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1335  $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', 0);
1336 
1337  /*
1338  if ($object->close_code == 'discount_vat')
1339  {
1340  $index++;
1341  $pdf->SetFillColor(255,255,255);
1342 
1343  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1344  $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("EscompteOfferedShort"), $useborder, 'L', 1);
1345 
1346  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1347  $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle, 0, $outputlangs), $useborder, 'R', 1);
1348 
1349  $resteapayer=0;
1350  }
1351  */
1352 
1353  $index++;
1354  $pdf->SetTextColor(0, 0, 60);
1355  $pdf->SetFillColor(224, 224, 224);
1356  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1357  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1);
1358 
1359  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1360  $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1);
1361 
1362  $pdf->SetFont('', '', $default_font_size - 1);
1363  $pdf->SetTextColor(0, 0, 0);
1364  }
1365 
1366  $index++;
1367  return ($tab2_top + ($tab2_hl * $index));
1368  }
1369 
1370  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1384  protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '')
1385  {
1386  global $conf;
1387 
1388  // Force to disable hidetop and hidebottom
1389  $hidebottom = 0;
1390  if ($hidetop) {
1391  $hidetop = -1;
1392  }
1393 
1394  $currency = !empty($currency) ? $currency : $conf->currency;
1395  $default_font_size = pdf_getPDFFontSize($outputlangs);
1396 
1397  // Amount in (at tab_top - 1)
1398  $pdf->SetTextColor(0, 0, 0);
1399  $pdf->SetFont('', '', $default_font_size - 2);
1400 
1401  if (empty($hidetop)) {
1402  $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
1403  $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
1404  $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
1405 
1406  //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
1407  if (!empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) {
1408  $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));
1409  }
1410  }
1411 
1412  $pdf->SetDrawColor(128, 128, 128);
1413  $pdf->SetFont('', '', $default_font_size - 1);
1414 
1415  // Output Rect
1416  $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
1417 
1418  if (empty($hidetop)) {
1419  $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
1420 
1421  $pdf->SetXY($this->posxdesc - 1, $tab_top + 1);
1422  $pdf->MultiCell(108, 2, $outputlangs->transnoentities("Designation"), '', 'L');
1423  }
1424 
1425  if (!empty($conf->global->MAIN_GENERATE_PROPOSALS_WITH_PICTURE)) {
1426  $pdf->line($this->posxpicture - 1, $tab_top, $this->posxpicture - 1, $tab_top + $tab_height);
1427  if (empty($hidetop)) {
1428  //$pdf->SetXY($this->posxpicture-1, $tab_top+1);
1429  //$pdf->MultiCell($this->posxtva-$this->posxpicture-1,2, $outputlangs->transnoentities("Photo"),'','C');
1430  }
1431  }
1432 
1433  if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
1434  $pdf->line($this->posxtva - 1, $tab_top, $this->posxtva - 1, $tab_top + $tab_height);
1435  if (empty($hidetop)) {
1436  // Not do -3 and +3 instead of -1 -1 to have more space for text 'Sales tax'
1437  $pdf->SetXY($this->posxtva - 3, $tab_top + 1);
1438  $pdf->MultiCell($this->posxup - $this->posxtva + 3, 2, $outputlangs->transnoentities("VAT"), '', 'C');
1439  }
1440  }
1441 
1442  $pdf->line($this->posxup - 1, $tab_top, $this->posxup - 1, $tab_top + $tab_height);
1443  if (empty($hidetop)) {
1444  $pdf->SetXY($this->posxup - 1, $tab_top + 1);
1445  $pdf->MultiCell($this->posxqty - $this->posxup - 1, 2, $outputlangs->transnoentities("PriceUHT"), '', 'C');
1446  }
1447 
1448  $pdf->line($this->posxqty - 1, $tab_top, $this->posxqty - 1, $tab_top + $tab_height);
1449  if (empty($hidetop)) {
1450  $pdf->SetXY($this->posxqty - 1, $tab_top + 1);
1451  $pdf->MultiCell($this->posxunit - $this->posxqty - 1, 2, $outputlangs->transnoentities("Qty"), '', 'C');
1452  }
1453 
1454  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1455  $pdf->line($this->posxunit - 1, $tab_top, $this->posxunit - 1, $tab_top + $tab_height);
1456  if (empty($hidetop)) {
1457  $pdf->SetXY($this->posxunit - 1, $tab_top + 1);
1458  $pdf->MultiCell(
1459  $this->posxdiscount - $this->posxunit - 1,
1460  2,
1461  $outputlangs->transnoentities("Unit"),
1462  '',
1463  'C'
1464  );
1465  }
1466  }
1467 
1468  $pdf->line($this->posxdiscount - 1, $tab_top, $this->posxdiscount - 1, $tab_top + $tab_height);
1469  if (empty($hidetop)) {
1470  if ($this->atleastonediscount) {
1471  $pdf->SetXY($this->posxdiscount - 1, $tab_top + 1);
1472  $pdf->MultiCell($this->postotalht - $this->posxdiscount + 1, 2, $outputlangs->transnoentities("ReductionShort"), '', 'C');
1473  }
1474  }
1475  if ($this->atleastonediscount) {
1476  $pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height);
1477  }
1478  if (empty($hidetop)) {
1479  $pdf->SetXY($this->postotalht - 1, $tab_top + 1);
1480  $pdf->MultiCell(30, 2, $outputlangs->transnoentities("TotalHTShort"), '', 'C');
1481  }
1482  }
1483 
1484  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1495  protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null)
1496  {
1497  global $conf, $langs;
1498 
1499  $ltrdirection = 'L';
1500  if ($outputlangs->trans("DIRECTION") == 'rtl') $ltrdirection = 'R';
1501 
1502  // Load traductions files required by page
1503  $outputlangs->loadLangs(array("main", "propal", "companies", "bills"));
1504 
1505  $default_font_size = pdf_getPDFFontSize($outputlangs);
1506 
1507  pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
1508 
1509  $pdf->SetTextColor(0, 0, 60);
1510  $pdf->SetFont('', 'B', $default_font_size + 3);
1511 
1512  $w = 100;
1513 
1514  $posy = $this->marge_haute;
1515  $posx = $this->page_largeur - $this->marge_droite - $w;
1516 
1517  $pdf->SetXY($this->marge_gauche, $posy);
1518 
1519  // Logo
1520  if (!getDolGlobalInt('PDF_DISABLE_MYCOMPANY_LOGO')) {
1521  if ($this->emetteur->logo) {
1522  $logodir = $conf->mycompany->dir_output;
1523  if (!empty($conf->mycompany->multidir_output[$object->entity])) {
1524  $logodir = $conf->mycompany->multidir_output[$object->entity];
1525  }
1526  if (!getDolGlobalInt('MAIN_PDF_USE_LARGE_LOGO')) {
1527  $logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
1528  } else {
1529  $logo = $logodir.'/logos/'.$this->emetteur->logo;
1530  }
1531  if (is_readable($logo)) {
1532  $height = pdf_getHeightForLogo($logo);
1533  $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
1534  } else {
1535  $pdf->SetTextColor(200, 0, 0);
1536  $pdf->SetFont('', 'B', $default_font_size - 2);
1537  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
1538  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
1539  }
1540  } else {
1541  $text = $this->emetteur->name;
1542  $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);
1543  }
1544  }
1545 
1546  $pdf->SetFont('', 'B', $default_font_size + 3);
1547  $pdf->SetXY($posx, $posy);
1548  $pdf->SetTextColor(0, 0, 60);
1549  $title = $outputlangs->transnoentities("PdfCommercialProposalTitle");
1550  $title .= ' '.$outputlangs->convToOutputCharset($object->ref);
1551  if ($object->statut == $object::STATUS_DRAFT) {
1552  $pdf->SetTextColor(128, 0, 0);
1553  $title .= ' - '.$outputlangs->transnoentities("NotValidated");
1554  }
1555  $pdf->MultiCell(100, 4, $title, '', 'R');
1556 
1557  $pdf->SetFont('', 'B', $default_font_size);
1558 
1559  /*
1560  $posy += 5;
1561  $pdf->SetXY($posx, $posy);
1562  $pdf->SetTextColor(0, 0, 60);
1563  $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Ref")." : ".$outputlangs->convToOutputCharset($object->ref), '', 'R');
1564  */
1565 
1566  $posy += 3;
1567  $pdf->SetFont('', '', $default_font_size - 2);
1568 
1569  if ($object->ref_client) {
1570  $posy += 4;
1571  $pdf->SetXY($posx, $posy);
1572  $pdf->SetTextColor(0, 0, 60);
1573  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R');
1574  }
1575 
1576  if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) {
1577  $object->fetch_projet();
1578  if (!empty($object->project->ref)) {
1579  $posy += 3;
1580  $pdf->SetXY($posx, $posy);
1581  $pdf->SetTextColor(0, 0, 60);
1582  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->project->title), '', 'R');
1583  }
1584  }
1585 
1586  if (!empty($conf->global->PDF_SHOW_PROJECT)) {
1587  $object->fetch_projet();
1588  if (!empty($object->project->ref)) {
1589  $outputlangs->load("projects");
1590  $posy += 3;
1591  $pdf->SetXY($posx, $posy);
1592  $pdf->SetTextColor(0, 0, 60);
1593  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefProject")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R');
1594  }
1595  }
1596 
1597  if (!empty($conf->global->MAIN_PDF_DATE_TEXT)) {
1598  $displaydate = "daytext";
1599  } else {
1600  $displaydate = "day";
1601  }
1602 
1603  //$posy += 4;
1604  $posy = $pdf->getY();
1605  $pdf->SetXY($posx, $posy);
1606  $pdf->SetTextColor(0, 0, 60);
1607  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("DatePropal")." : ".dol_print_date($object->date, $displaydate, false, $outputlangs, true), '', 'R');
1608 
1609  $posy += 4;
1610  $pdf->SetXY($posx, $posy);
1611  $pdf->SetTextColor(0, 0, 60);
1612  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("DateEndPropal")." : ".dol_print_date($object->fin_validite, $displaydate, false, $outputlangs, true), '', 'R');
1613 
1614  if (empty($conf->global->MAIN_PDF_HIDE_CUSTOMER_CODE) && $object->thirdparty->code_client) {
1615  $posy += 4;
1616  $pdf->SetXY($posx, $posy);
1617  $pdf->SetTextColor(0, 0, 60);
1618  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R');
1619  }
1620 
1621  // Get contact
1622  if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) {
1623  $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1624  if (count($arrayidcontact) > 0) {
1625  $usertmp = new User($this->db);
1626  $usertmp->fetch($arrayidcontact[0]);
1627  $posy += 4;
1628  $pdf->SetXY($posx, $posy);
1629  $pdf->SetTextColor(0, 0, 60);
1630  $pdf->MultiCell(100, 3, $langs->trans("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
1631  }
1632  }
1633 
1634  $posy += 2;
1635 
1636  $top_shift = 0;
1637  // Show list of linked objects
1638  $current_y = $pdf->getY();
1639  $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size);
1640  if ($current_y < $pdf->getY()) {
1641  $top_shift = $pdf->getY() - $current_y;
1642  }
1643 
1644  if ($showaddress) {
1645  // Sender properties
1646  $carac_emetteur = '';
1647  // Add internal contact of object if defined
1648  $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1649  if (count($arrayidcontact) > 0) {
1650  $object->fetch_user($arrayidcontact[0]);
1651  $labelbeforecontactname = ($outputlangs->transnoentities("FromContactName") != 'FromContactName' ? $outputlangs->transnoentities("FromContactName") : $outputlangs->transnoentities("Name"));
1652  $carac_emetteur .= ($carac_emetteur ? "\n" : '').$labelbeforecontactname." ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs));
1653  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ' (' : '';
1654  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && !empty($object->user->office_phone)) ? $object->user->office_phone : '';
1655  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ', ' : '';
1656  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT') && !empty($object->user->email)) ? $object->user->email : '';
1657  $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ')' : '';
1658  $carac_emetteur .= "\n";
1659  }
1660 
1661  $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
1662 
1663  // Show sender
1664  $posy = 42 + $top_shift;
1665  $posx = $this->marge_gauche;
1666  if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1667  $posx = $this->page_largeur - $this->marge_droite - 80;
1668  }
1669  $hautcadre = 40;
1670 
1671  // Show sender frame
1672  if (empty($conf->global->MAIN_PDF_NO_SENDER_FRAME)) {
1673  $pdf->SetTextColor(0, 0, 0);
1674  $pdf->SetFont('', '', $default_font_size - 2);
1675  $pdf->SetXY($posx, $posy - 5);
1676  $pdf->MultiCell(80, 5, $outputlangs->transnoentities("BillFrom"), 0, $ltrdirection);
1677  $pdf->SetXY($posx, $posy);
1678  $pdf->SetFillColor(230, 230, 230);
1679  $pdf->MultiCell(82, $hautcadre, "", 0, 'R', 1);
1680  $pdf->SetTextColor(0, 0, 60);
1681  }
1682 
1683  // Show company name
1684  if (empty($conf->global->MAIN_PDF_HIDE_SENDER_NAME)) {
1685  $pdf->SetXY($posx + 2, $posy + 3);
1686  $pdf->SetFont('', 'B', $default_font_size);
1687  $pdf->MultiCell(80, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, $ltrdirection);
1688  $posy = $pdf->getY();
1689  }
1690 
1691  // Show sender information
1692  $pdf->SetXY($posx + 2, $posy);
1693  $pdf->SetFont('', '', $default_font_size - 1);
1694  $pdf->MultiCell(80, 4, $carac_emetteur, 0, $ltrdirection);
1695 
1696 
1697  // If CUSTOMER contact defined, we use it
1698  $usecontact = false;
1699  $arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
1700  if (count($arrayidcontact) > 0) {
1701  $usecontact = true;
1702  $result = $object->fetch_contact($arrayidcontact[0]);
1703  }
1704 
1705  // Recipient name
1706  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)))) {
1707  $thirdparty = $object->contact;
1708  } else {
1709  $thirdparty = $object->thirdparty;
1710  }
1711 
1712  $carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);
1713 
1714  $mode = 'target';
1715  $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), $usecontact, $mode, $object);
1716 
1717  // Show recipient
1718  $widthrecbox = 100;
1719  if ($this->page_largeur < 210) {
1720  $widthrecbox = 84; // To work with US executive format
1721  }
1722  $posy = 42 + $top_shift;
1723  $posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
1724  if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1725  $posx = $this->marge_gauche;
1726  }
1727 
1728  // Show recipient frame
1729  if (empty($conf->global->MAIN_PDF_NO_RECIPENT_FRAME)) {
1730  $pdf->SetTextColor(0, 0, 0);
1731  $pdf->SetFont('', '', $default_font_size - 2);
1732  $pdf->SetXY($posx + 2, $posy - 5);
1733  $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo"), 0, $ltrdirection);
1734  $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
1735  }
1736 
1737  // Show recipient name
1738  $pdf->SetXY($posx + 2, $posy + 3);
1739  $pdf->SetFont('', 'B', $default_font_size);
1740  $pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, $ltrdirection);
1741 
1742  $posy = $pdf->getY();
1743 
1744  // Show recipient information
1745  $pdf->SetFont('', '', $default_font_size - 1);
1746  $pdf->SetXY($posx + 2, $posy);
1747  $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, $ltrdirection);
1748  }
1749 
1750  $pdf->SetTextColor(0, 0, 0);
1751  return $top_shift;
1752  }
1753 
1754  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1764  protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
1765  {
1766  $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0);
1767  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);
1768  }
1769 
1770  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1771  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1781  protected function _signature_area(&$pdf, $object, $posy, $outputlangs)
1782  {
1783  // phpcs:enable
1784  global $conf;
1785  $default_font_size = pdf_getPDFFontSize($outputlangs);
1786  $tab_top = $posy + 4;
1787  $tab_hl = 4;
1788 
1789  $posx = 120;
1790  $largcol = ($this->page_largeur - $this->marge_droite - $posx);
1791  $useborder = 0;
1792  $index = 0;
1793  // Total HT
1794  $pdf->SetFillColor(255, 255, 255);
1795  $pdf->SetXY($posx, $tab_top);
1796  $pdf->SetFont('', '', $default_font_size - 2);
1797  $pdf->MultiCell($largcol, $tab_hl, $outputlangs->transnoentities("ProposalCustomerSignature"), 0, 'L', 1);
1798 
1799  $pdf->SetXY($posx, $tab_top + $tab_hl);
1800  $pdf->MultiCell($largcol, $tab_hl * 3, '', 1, 'R');
1801  if (!empty($conf->global->MAIN_PDF_PROPAL_USE_ELECTRONIC_SIGNING)) {
1802  $pdf->addEmptySignatureAppearance($posx, $tab_top + $tab_hl, $largcol, $tab_hl * 3);
1803  }
1804 
1805  return ($tab_hl * 7);
1806  }
1807 }
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: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_writelinedesc(&$pdf, $object, $i, $outputlangs, $w, $h, $posx, $posy, $hideref=0, $hidedesc=0, $issupplierline=0)
Output line description into PDF.
Definition: pdf.lib.php:1374
pdf_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: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