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