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