dolibarr  17.0.4
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 && (!empty($conf->global->COMMANDE_DRAFT_WATERMARK))) {
225  $this->watermark = $conf->global->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  $diffsizetitle = (empty($conf->global->PDF_DIFFSIZE_TITLE) ? 3 : $conf->global->PDF_DIFFSIZE_TITLE);
950 
951  // If France, show VAT mention if not applicable
952  if ($this->emetteur->country_code == 'FR' && empty($mysoc->tva_assuj)) {
953  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
954  $pdf->SetXY($this->marge_gauche, $posy);
955  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0);
956 
957  $posy = $pdf->GetY() + 4;
958  }
959 
960  $posxval = 52;
961 
962  $diffsizetitle = (empty($conf->global->PDF_DIFFSIZE_TITLE) ? 3 : $conf->global->PDF_DIFFSIZE_TITLE);
963 
964  // Show payments conditions
965  if ($object->cond_reglement_code || $object->cond_reglement) {
966  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
967  $pdf->SetXY($this->marge_gauche, $posy);
968  $titre = $outputlangs->transnoentities("PaymentConditions").':';
969  $pdf->MultiCell(43, 4, $titre, 0, 'L');
970 
971  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
972  $pdf->SetXY($posxval, $posy);
973  $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);
974  $lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
975  if ($object->deposit_percent > 0) {
976  $lib_condition_paiement = str_replace('__DEPOSIT_PERCENT__', $object->deposit_percent, $lib_condition_paiement);
977  }
978  $pdf->MultiCell(67, 4, $lib_condition_paiement, 0, 'L');
979 
980  $posy = $pdf->GetY() + 3;
981  }
982 
983  // Check a payment mode is defined
984  /* Not used with orders
985  if (empty($object->mode_reglement_code)
986  && ! $conf->global->FACTURE_CHQ_NUMBER
987  && ! $conf->global->FACTURE_RIB_NUMBER)
988  {
989  $pdf->SetXY($this->marge_gauche, $posy);
990  $pdf->SetTextColor(200,0,0);
991  $pdf->SetFont('','B', $default_font_size - 2);
992  $pdf->MultiCell(80, 3, $outputlangs->transnoentities("ErrorNoPaiementModeConfigured"),0,'L',0);
993  $pdf->SetTextColor(0,0,0);
994 
995  $posy=$pdf->GetY()+1;
996  }
997  */
998  /* TODO
999  else if (!empty($object->availability_code))
1000  {
1001  $pdf->SetXY($this->marge_gauche, $posy);
1002  $pdf->SetTextColor(200,0,0);
1003  $pdf->SetFont('','B', $default_font_size - 2);
1004  $pdf->MultiCell(80, 3, $outputlangs->transnoentities("AvailabilityPeriod").': '.,0,'L',0);
1005  $pdf->SetTextColor(0,0,0);
1006 
1007  $posy=$pdf->GetY()+1;
1008  }*/
1009 
1010  // Show planed date of delivery
1011  if (!empty($object->delivery_date)) {
1012  $outputlangs->load("sendings");
1013  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1014  $pdf->SetXY($this->marge_gauche, $posy);
1015  $titre = $outputlangs->transnoentities("DateDeliveryPlanned").':';
1016  $pdf->MultiCell(80, 4, $titre, 0, 'L');
1017  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1018  $pdf->SetXY($posxval, $posy);
1019  $dlp = dol_print_date($object->delivery_date, "daytext", false, $outputlangs, true);
1020  $pdf->MultiCell(80, 4, $dlp, 0, 'L');
1021 
1022  $posy = $pdf->GetY() + 1;
1023  } elseif ($object->availability_code || $object->availability) { // Show availability conditions
1024  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1025  $pdf->SetXY($this->marge_gauche, $posy);
1026  $titre = $outputlangs->transnoentities("AvailabilityPeriod").':';
1027  $pdf->MultiCell(80, 4, $titre, 0, 'L');
1028  $pdf->SetTextColor(0, 0, 0);
1029  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1030  $pdf->SetXY($posxval, $posy);
1031  $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 : '');
1032  $lib_availability = str_replace('\n', "\n", $lib_availability);
1033  $pdf->MultiCell(80, 4, $lib_availability, 0, 'L');
1034 
1035  $posy = $pdf->GetY() + 1;
1036  }
1037 
1038  // Show payment mode
1039  if ($object->mode_reglement_code
1040  && $object->mode_reglement_code != 'CHQ'
1041  && $object->mode_reglement_code != 'VIR') {
1042  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1043  $pdf->SetXY($this->marge_gauche, $posy);
1044  $titre = $outputlangs->transnoentities("PaymentMode").':';
1045  $pdf->MultiCell(80, 5, $titre, 0, 'L');
1046 
1047  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1048  $pdf->SetXY($posxval, $posy);
1049  $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);
1050  $pdf->MultiCell(80, 5, $lib_mode_reg, 0, 'L');
1051 
1052  $posy = $pdf->GetY() + 2;
1053  }
1054 
1055  // Show payment mode CHQ
1056  if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ') {
1057  // Si mode reglement non force ou si force a CHQ
1058  if (!empty($conf->global->FACTURE_CHQ_NUMBER)) {
1059  if ($conf->global->FACTURE_CHQ_NUMBER > 0) {
1060  $account = new Account($this->db);
1061  $account->fetch($conf->global->FACTURE_CHQ_NUMBER);
1062 
1063  $pdf->SetXY($this->marge_gauche, $posy);
1064  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1065  $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $account->proprio), 0, 'L', 0);
1066  $posy = $pdf->GetY() + 1;
1067 
1068  if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) {
1069  $pdf->SetXY($this->marge_gauche, $posy);
1070  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1071  $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0);
1072  $posy = $pdf->GetY() + 2;
1073  }
1074  }
1075  if ($conf->global->FACTURE_CHQ_NUMBER == -1) {
1076  $pdf->SetXY($this->marge_gauche, $posy);
1077  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1078  $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $this->emetteur->name), 0, 'L', 0);
1079  $posy = $pdf->GetY() + 1;
1080 
1081  if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) {
1082  $pdf->SetXY($this->marge_gauche, $posy);
1083  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1084  $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0);
1085  $posy = $pdf->GetY() + 2;
1086  }
1087  }
1088  }
1089  }
1090 
1091  // If payment mode not forced or forced to VIR, show payment with BAN
1092  if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') {
1093  if ($object->fk_account > 0 || $object->fk_bank > 0 || getDolGlobalInt('FACTURE_RIB_NUMBER')) {
1094  $bankid = ($object->fk_account <= 0 ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account);
1095  if ($object->fk_bank > 0) {
1096  $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank
1097  }
1098  $account = new Account($this->db);
1099  $account->fetch($bankid);
1100 
1101  $curx = $this->marge_gauche;
1102  $cury = $posy;
1103 
1104  $posy = pdf_bank($pdf, $outputlangs, $curx, $cury, $account, 0, $default_font_size);
1105 
1106  $posy += 2;
1107  }
1108  }
1109 
1110  return $posy;
1111  }
1112 
1113 
1125  protected function drawTotalTable(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis = null)
1126  {
1127  global $conf, $mysoc, $hookmanager;
1128 
1129  $default_font_size = pdf_getPDFFontSize($outputlangs);
1130 
1131  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) {
1132  $outputlangsbis = new Translate('', $conf);
1133  $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE);
1134  $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal"));
1135  $default_font_size--;
1136  }
1137 
1138  $tab2_top = $posy;
1139  $tab2_hl = 4;
1140  $pdf->SetFont('', '', $default_font_size - 1);
1141 
1142  // Total table
1143  $col1x = 120;
1144  $col2x = 170;
1145  if ($this->page_largeur < 210) { // To work with US executive format
1146  $col2x -= 20;
1147  }
1148  $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
1149 
1150  $useborder = 0;
1151  $index = 0;
1152 
1153  // Total HT
1154  $pdf->SetFillColor(255, 255, 255);
1155  $pdf->SetXY($col1x, $tab2_top + 0);
1156  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("TotalHT") : ''), 0, 'L', 1);
1157  $total_ht = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht);
1158  $pdf->SetXY($col2x, $tab2_top + 0);
1159  $pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + (!empty($object->remise) ? $object->remise : 0), 0, $outputlangs), 0, 'R', 1);
1160 
1161  // Show VAT by rates and total
1162  $pdf->SetFillColor(248, 248, 248);
1163 
1164  $total_ttc = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
1165 
1166  $this->atleastoneratenotnull = 0;
1167  if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) {
1168  $tvaisnull = ((!empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false);
1169  if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull) {
1170  // Nothing to do
1171  } else {
1172  //Local tax 1 before VAT
1173  //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1174  //{
1175  foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1176  if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1177  continue;
1178  }
1179  foreach ($localtax_rate as $tvakey => $tvaval) {
1180  if ($tvakey != 0) { // On affiche pas taux 0
1181  //$this->atleastoneratenotnull++;
1182  $index++;
1183  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1184 
1185  $tvacompl = '';
1186  if (preg_match('/\*/', $tvakey)) {
1187  $tvakey = str_replace('*', '', $tvakey);
1188  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1189  }
1190  $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : '');
1191  $totalvat .= ' ';
1192  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1193  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1194 
1195  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1196  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1197  }
1198  }
1199  }
1200  //}
1201  //Local tax 2 before VAT
1202  //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1203  //{
1204  foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1205  if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1206  continue;
1207  }
1208  foreach ($localtax_rate as $tvakey => $tvaval) {
1209  if ($tvakey != 0) { // On affiche pas taux 0
1210  //$this->atleastoneratenotnull++;
1211 
1212  $index++;
1213  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1214 
1215  $tvacompl = '';
1216  if (preg_match('/\*/', $tvakey)) {
1217  $tvakey = str_replace('*', '', $tvakey);
1218  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1219  }
1220  $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : '');
1221  $totalvat .= ' ';
1222  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1223  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1224 
1225  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1226  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1227  }
1228  }
1229  }
1230  //}
1231 
1232  // VAT
1233  foreach ($this->tva_array as $tvakey => $tvaval) {
1234  if ($tvakey != 0) { // On affiche pas taux 0
1235  $this->atleastoneratenotnull++;
1236 
1237  $index++;
1238  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1239 
1240  $tvacompl = '';
1241  if (preg_match('/\*/', $tvakey)) {
1242  $tvakey = str_replace('*', '', $tvakey);
1243  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1244  }
1245  $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalVAT", $mysoc->country_code) : '');
1246  $totalvat .= ' ';
1247  if (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'rateonly') {
1248  $totalvat .= vatrate($tvaval['vatrate'], 1).$tvacompl;
1249  } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'codeonly') {
1250  $totalvat .= ($tvaval['vatcode'] ? $tvaval['vatcode'] : vatrate($tvaval['vatrate'], 1)).$tvacompl;
1251  } else {
1252  $totalvat .= vatrate($tvaval['vatrate'], 1).($tvaval['vatcode'] ? ' ('.$tvaval['vatcode'].')' : '').$tvacompl;
1253  }
1254  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1255 
1256  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1257  $pdf->MultiCell($largcol2, $tab2_hl, price(price2num($tvaval['amount'], 'MT'), 0, $outputlangs), 0, 'R', 1);
1258  }
1259  }
1260 
1261  //Local tax 1 after VAT
1262  //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1263  //{
1264  foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1265  if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1266  continue;
1267  }
1268 
1269  foreach ($localtax_rate as $tvakey => $tvaval) {
1270  if ($tvakey != 0) { // On affiche pas taux 0
1271  //$this->atleastoneratenotnull++;
1272 
1273  $index++;
1274  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1275 
1276  $tvacompl = '';
1277  if (preg_match('/\*/', $tvakey)) {
1278  $tvakey = str_replace('*', '', $tvakey);
1279  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1280  }
1281  $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : '');
1282  $totalvat .= ' ';
1283  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1284 
1285  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1286  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1287  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1288  }
1289  }
1290  }
1291  //}
1292  //Local tax 2 after VAT
1293  //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1294  //{
1295  foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1296  if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1297  continue;
1298  }
1299 
1300  foreach ($localtax_rate as $tvakey => $tvaval) {
1301  // retrieve global local tax
1302  if ($tvakey != 0) { // On affiche pas taux 0
1303  //$this->atleastoneratenotnull++;
1304 
1305  $index++;
1306  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1307 
1308  $tvacompl = '';
1309  if (preg_match('/\*/', $tvakey)) {
1310  $tvakey = str_replace('*', '', $tvakey);
1311  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1312  }
1313  $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : '');
1314  $totalvat .= ' ';
1315 
1316  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1317  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1318 
1319  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1320  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1321  }
1322  }
1323  }
1324  //}
1325 
1326  // Total TTC
1327  $index++;
1328  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1329  $pdf->SetTextColor(0, 0, 60);
1330  $pdf->SetFillColor(224, 224, 224);
1331  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalTTC", $mysoc->country_code) : ''), $useborder, 'L', 1);
1332 
1333  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1334  $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', 1);
1335  }
1336  }
1337 
1338  $pdf->SetTextColor(0, 0, 0);
1339 
1340  $creditnoteamount = 0;
1341  $depositsamount = 0;
1342  //$creditnoteamount=$object->getSumCreditNotesUsed();
1343  //$depositsamount=$object->getSumDepositsUsed();
1344  //print "x".$creditnoteamount."-".$depositsamount;exit;
1345  $resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT');
1346  if (!empty($object->paye)) {
1347  $resteapayer = 0;
1348  }
1349 
1350  if ($deja_regle > 0) {
1351  // Already paid + Deposits
1352  $index++;
1353 
1354  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1355  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("AlreadyPaid") : ''), 0, 'L', 0);
1356  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1357  $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', 0);
1358 
1359  $index++;
1360  $pdf->SetTextColor(0, 0, 60);
1361  $pdf->SetFillColor(224, 224, 224);
1362  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1363  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("RemainderToPay") : ''), $useborder, 'L', 1);
1364 
1365  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1366  $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1);
1367 
1368  $pdf->SetFont('', '', $default_font_size - 1);
1369  $pdf->SetTextColor(0, 0, 0);
1370  }
1371 
1372  $index++;
1373  return ($tab2_top + ($tab2_hl * $index));
1374  }
1375 
1376  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1391  protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '', $outputlangsbis = null)
1392  {
1393  global $conf;
1394 
1395  // Force to disable hidetop and hidebottom
1396  $hidebottom = 0;
1397  if ($hidetop) {
1398  $hidetop = -1;
1399  }
1400 
1401  $currency = !empty($currency) ? $currency : $conf->currency;
1402  $default_font_size = pdf_getPDFFontSize($outputlangs);
1403 
1404  // Amount in (at tab_top - 1)
1405  $pdf->SetTextColor(0, 0, 0);
1406  $pdf->SetFont('', '', $default_font_size - 2);
1407 
1408  if (empty($hidetop)) {
1409  $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
1410  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {
1411  $titre .= ' - '.$outputlangsbis->transnoentities("AmountInCurrency", $outputlangsbis->transnoentitiesnoconv("Currency".$currency));
1412  }
1413 
1414  $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
1415  $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
1416 
1417  //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
1418  if (!empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) {
1419  $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));
1420  }
1421  }
1422 
1423  $pdf->SetDrawColor(128, 128, 128);
1424  $pdf->SetFont('', '', $default_font_size - 1);
1425 
1426  // Output Rect
1427  $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
1428 
1429 
1430  $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop);
1431 
1432  if (empty($hidetop)) {
1433  $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
1434  }
1435  }
1436 
1437  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1438  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1450  protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null, $titlekey = "PdfOrderTitle")
1451  {
1452  // phpcs:enable
1453  global $conf, $langs, $hookmanager;
1454 
1455  $ltrdirection = 'L';
1456  if ($outputlangs->trans("DIRECTION") == 'rtl') $ltrdirection = 'R';
1457 
1458  // Load traductions files required by page
1459  $outputlangs->loadLangs(array("main", "bills", "propal", "orders", "companies"));
1460 
1461  $default_font_size = pdf_getPDFFontSize($outputlangs);
1462 
1463  pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
1464 
1465  $pdf->SetTextColor(0, 0, 60);
1466  $pdf->SetFont('', 'B', $default_font_size + 3);
1467 
1468  $w = 100;
1469 
1470  $posy = $this->marge_haute;
1471  $posx = $this->page_largeur - $this->marge_droite - $w;
1472 
1473  $pdf->SetXY($this->marge_gauche, $posy);
1474 
1475  // Logo
1476  if (empty($conf->global->PDF_DISABLE_MYCOMPANY_LOGO)) {
1477  if ($this->emetteur->logo) {
1478  $logodir = $conf->mycompany->dir_output;
1479  if (!empty($conf->mycompany->multidir_output[$object->entity])) {
1480  $logodir = $conf->mycompany->multidir_output[$object->entity];
1481  }
1482  if (empty($conf->global->MAIN_PDF_USE_LARGE_LOGO)) {
1483  $logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
1484  } else {
1485  $logo = $logodir.'/logos/'.$this->emetteur->logo;
1486  }
1487  if (is_readable($logo)) {
1488  $height = pdf_getHeightForLogo($logo);
1489  $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
1490  } else {
1491  $pdf->SetTextColor(200, 0, 0);
1492  $pdf->SetFont('', 'B', $default_font_size - 2);
1493  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
1494  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
1495  }
1496  } else {
1497  $text = $this->emetteur->name;
1498  $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
1499  }
1500  }
1501 
1502  $pdf->SetFont('', 'B', $default_font_size + 3);
1503  $pdf->SetXY($posx, $posy);
1504  $pdf->SetTextColor(0, 0, 60);
1505  $title = $outputlangs->transnoentities($titlekey);
1506  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {
1507  $title .= ' - ';
1508  $title .= $outputlangsbis->transnoentities($titlekey);
1509  }
1510  $title .= ' '.$outputlangs->convToOutputCharset($object->ref);
1511  if ($object->statut == $object::STATUS_DRAFT) {
1512  $pdf->SetTextColor(128, 0, 0);
1513  $title .= ' - '.$outputlangs->transnoentities("NotValidated");
1514  }
1515 
1516  $pdf->MultiCell($w, 3, $title, '', 'R');
1517 
1518  $pdf->SetFont('', 'B', $default_font_size);
1519 
1520  /*
1521  $posy += 5;
1522  $pdf->SetXY($posx, $posy);
1523  $pdf->SetTextColor(0, 0, 60);
1524  $textref = $outputlangs->transnoentities("Ref")." : ".$outputlangs->convToOutputCharset($object->ref);
1525  if ($object->statut == $object::STATUS_DRAFT) {
1526  $pdf->SetTextColor(128, 0, 0);
1527  $textref .= ' - '.$outputlangs->transnoentities("NotValidated");
1528  }
1529  $pdf->MultiCell($w, 4, $textref, '', 'R');
1530  */
1531 
1532  $posy += 3;
1533  $pdf->SetFont('', '', $default_font_size - 2);
1534 
1535  if ($object->ref_client) {
1536  $posy += 4;
1537  $pdf->SetXY($posx, $posy);
1538  $pdf->SetTextColor(0, 0, 60);
1539  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".dol_trunc($outputlangs->convToOutputCharset($object->ref_client), 65), '', 'R');
1540  }
1541 
1542  if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) {
1543  $object->fetch_projet();
1544  if (!empty($object->project->ref)) {
1545  $posy += 3;
1546  $pdf->SetXY($posx, $posy);
1547  $pdf->SetTextColor(0, 0, 60);
1548  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->project->title), '', 'R');
1549  }
1550  }
1551 
1552  if (!empty($conf->global->PDF_SHOW_PROJECT)) {
1553  $object->fetch_projet();
1554  if (!empty($object->project->ref)) {
1555  $outputlangs->load("projects");
1556  $posy += 3;
1557  $pdf->SetXY($posx, $posy);
1558  $pdf->SetTextColor(0, 0, 60);
1559  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefProject")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R');
1560  }
1561  }
1562 
1563  $posy += 4;
1564 
1565  $pdf->SetXY($posx, $posy);
1566  $pdf->SetTextColor(0, 0, 60);
1567  $title = $outputlangs->transnoentities("OrderDate");
1568  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {
1569  $title .= ' - '.$outputlangsbis->transnoentities("DateInvoice");
1570  }
1571  $pdf->MultiCell($w, 3, $title." : ".dol_print_date($object->date, "day", false, $outputlangs, true), '', 'R');
1572 
1573  if (empty($conf->global->MAIN_PDF_HIDE_CUSTOMER_CODE) && !empty($object->thirdparty->code_client)) {
1574  $posy += 4;
1575  $pdf->SetXY($posx, $posy);
1576  $pdf->SetTextColor(0, 0, 60);
1577  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R');
1578  }
1579 
1580  // Get contact
1581  if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) {
1582  $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1583  if (count($arrayidcontact) > 0) {
1584  $usertmp = new User($this->db);
1585  $usertmp->fetch($arrayidcontact[0]);
1586  $posy += 4;
1587  $pdf->SetXY($posx, $posy);
1588  $pdf->SetTextColor(0, 0, 60);
1589  $pdf->MultiCell($w, 3, $langs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
1590  }
1591  }
1592 
1593  $posy += 2;
1594 
1595  $top_shift = 0;
1596  // Show list of linked objects
1597  $current_y = $pdf->getY();
1598  $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size);
1599  if ($current_y < $pdf->getY()) {
1600  $top_shift = $pdf->getY() - $current_y;
1601  }
1602 
1603  if ($showaddress) {
1604  // Sender properties
1605  $carac_emetteur = '';
1606  // Add internal contact of proposal if defined
1607  $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1608  if (count($arrayidcontact) > 0) {
1609  $object->fetch_user($arrayidcontact[0]);
1610  $labelbeforecontactname = ($outputlangs->transnoentities("FromContactName") != 'FromContactName' ? $outputlangs->transnoentities("FromContactName") : $outputlangs->transnoentities("Name"));
1611  $carac_emetteur .= ($carac_emetteur ? "\n" : '').$labelbeforecontactname." ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs))."\n";
1612  }
1613 
1614  $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
1615 
1616  // Show sender
1617  $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42;
1618  $posy += $top_shift;
1619  $posx = $this->marge_gauche;
1620  if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1621  $posx = $this->page_largeur - $this->marge_droite - 80;
1622  }
1623 
1624  $hautcadre = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 38 : 40;
1625  $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 82;
1626 
1627 
1628  // Show sender frame
1629  if (empty($conf->global->MAIN_PDF_NO_SENDER_FRAME)) {
1630  $pdf->SetTextColor(0, 0, 0);
1631  $pdf->SetFont('', '', $default_font_size - 2);
1632  $pdf->SetXY($posx, $posy - 5);
1633  $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillFrom"), 0, $ltrdirection);
1634  $pdf->SetXY($posx, $posy);
1635  $pdf->SetFillColor(230, 230, 230);
1636  $pdf->MultiCell($widthrecbox, $hautcadre, "", 0, 'R', 1);
1637  $pdf->SetTextColor(0, 0, 60);
1638  }
1639 
1640  // Show sender name
1641  if (empty($conf->global->MAIN_PDF_HIDE_SENDER_NAME)) {
1642  $pdf->SetXY($posx + 2, $posy + 3);
1643  $pdf->SetFont('', 'B', $default_font_size);
1644  $pdf->MultiCell($widthrecbox - 2, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, $ltrdirection);
1645  $posy = $pdf->getY();
1646  }
1647 
1648  // Show sender information
1649  $pdf->SetXY($posx + 2, $posy);
1650  $pdf->SetFont('', '', $default_font_size - 1);
1651  $pdf->MultiCell($widthrecbox - 2, 4, $carac_emetteur, 0, $ltrdirection);
1652 
1653  // If CUSTOMER contact defined, we use it
1654  $usecontact = false;
1655  $arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
1656  if (count($arrayidcontact) > 0) {
1657  $usecontact = true;
1658  $result = $object->fetch_contact($arrayidcontact[0]);
1659  }
1660 
1661  //Recipient name
1662  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)))) {
1663  $thirdparty = $object->contact;
1664  } else {
1665  $thirdparty = $object->thirdparty;
1666  }
1667 
1668  $carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);
1669 
1670  $mode = 'target';
1671  $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), $usecontact, $mode, $object);
1672 
1673  // Show recipient
1674  $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100;
1675  if ($this->page_largeur < 210) {
1676  $widthrecbox = 84; // To work with US executive format
1677  }
1678  $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42;
1679  $posy += $top_shift;
1680  $posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
1681  if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1682  $posx = $this->marge_gauche;
1683  }
1684 
1685  // Show recipient frame
1686  if (empty($conf->global->MAIN_PDF_NO_RECIPENT_FRAME)) {
1687  $pdf->SetTextColor(0, 0, 0);
1688  $pdf->SetFont('', '', $default_font_size - 2);
1689  $pdf->SetXY($posx + 2, $posy - 5);
1690  $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo"), 0, $ltrdirection);
1691  $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
1692  }
1693 
1694  // Show recipient name
1695  $pdf->SetXY($posx + 2, $posy + 3);
1696  $pdf->SetFont('', 'B', $default_font_size);
1697  $pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, $ltrdirection);
1698 
1699  $posy = $pdf->getY();
1700 
1701  // Show recipient information
1702  $pdf->SetFont('', '', $default_font_size - 1);
1703  $pdf->SetXY($posx + 2, $posy);
1704  $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, $ltrdirection);
1705  }
1706 
1707  $pdf->SetTextColor(0, 0, 0);
1708  return $top_shift;
1709  }
1710 
1711  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1712  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1722  protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
1723  {
1724  // phpcs:enable
1725  $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0);
1726  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);
1727  }
1728 
1729 
1730 
1741  public function defineColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1742  {
1743  global $conf, $hookmanager;
1744 
1745  // Default field style for content
1746  $this->defaultContentsFieldsStyle = array(
1747  'align' => 'R', // R,C,L
1748  'padding' => array(1, 0.5, 1, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1749  );
1750 
1751  // Default field style for content
1752  $this->defaultTitlesFieldsStyle = array(
1753  'align' => 'C', // R,C,L
1754  'padding' => array(0.5, 0, 0.5, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1755  );
1756 
1757  /*
1758  * For exemple
1759  $this->cols['theColKey'] = array(
1760  'rank' => $rank, // int : use for ordering columns
1761  'width' => 20, // the column width in mm
1762  'title' => array(
1763  'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
1764  'label' => ' ', // the final label : used fore final generated text
1765  'align' => 'L', // text alignement : R,C,L
1766  'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1767  ),
1768  'content' => array(
1769  'align' => 'L', // text alignement : R,C,L
1770  'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1771  ),
1772  );
1773  */
1774 
1775  $rank = 0; // do not use negative rank
1776  $this->cols['desc'] = array(
1777  'rank' => $rank,
1778  'width' => false, // only for desc
1779  'status' => true,
1780  'title' => array(
1781  'textkey' => 'Designation', // use lang key is usefull in somme case with module
1782  'align' => 'L',
1783  // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
1784  // 'label' => ' ', // the final label
1785  'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1786  ),
1787  'content' => array(
1788  'align' => 'L',
1789  'padding' => array(1, 0.5, 1, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1790  ),
1791  );
1792 
1793  // Image of product
1794  $rank = $rank + 10;
1795  $this->cols['photo'] = array(
1796  'rank' => $rank,
1797  'width' => (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH) ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH), // in mm
1798  'status' => false,
1799  'title' => array(
1800  'textkey' => 'Photo',
1801  'label' => ' '
1802  ),
1803  'content' => array(
1804  'padding' => array(0, 0, 0, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1805  ),
1806  'border-left' => false, // remove left line separator
1807  );
1808 
1809  if (!empty($conf->global->MAIN_GENERATE_ORDERS_WITH_PICTURE) && !empty($this->atleastonephoto)) {
1810  $this->cols['photo']['status'] = true;
1811  }
1812 
1813  $rank = $rank + 10;
1814  $this->cols['vat'] = array(
1815  'rank' => $rank,
1816  'status' => false,
1817  'width' => 16, // in mm
1818  'title' => array(
1819  'textkey' => 'VAT'
1820  ),
1821  'border-left' => true, // add left line separator
1822  );
1823 
1824  if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
1825  $this->cols['vat']['status'] = true;
1826  }
1827 
1828  $rank = $rank + 10;
1829  $this->cols['subprice'] = array(
1830  'rank' => $rank,
1831  'width' => 19, // in mm
1832  'status' => true,
1833  'title' => array(
1834  'textkey' => 'PriceUHT'
1835  ),
1836  'border-left' => true, // add left line separator
1837  );
1838 
1839  // Adapt dynamically the width of subprice, if text is too long.
1840  $tmpwidth = 0;
1841  $nblines = count($object->lines);
1842  for ($i = 0; $i < $nblines; $i++) {
1843  $tmpwidth2 = dol_strlen(dol_string_nohtmltag(pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails)));
1844  $tmpwidth = max($tmpwidth, $tmpwidth2);
1845  }
1846  if ($tmpwidth > 10) {
1847  $this->cols['subprice']['width'] += (2 * ($tmpwidth - 10));
1848  }
1849 
1850  $rank = $rank + 10;
1851  $this->cols['qty'] = array(
1852  'rank' => $rank,
1853  'width' => 16, // in mm
1854  'status' => true,
1855  'title' => array(
1856  'textkey' => 'Qty'
1857  ),
1858  'border-left' => true, // add left line separator
1859  );
1860 
1861  $rank = $rank + 10;
1862  $this->cols['unit'] = array(
1863  'rank' => $rank,
1864  'width' => 11, // in mm
1865  'status' => false,
1866  'title' => array(
1867  'textkey' => 'Unit'
1868  ),
1869  'border-left' => true, // add left line separator
1870  );
1871  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
1872  $this->cols['unit']['status'] = true;
1873  }
1874 
1875  $rank = $rank + 10;
1876  $this->cols['discount'] = array(
1877  'rank' => $rank,
1878  'width' => 13, // in mm
1879  'status' => false,
1880  'title' => array(
1881  'textkey' => 'ReductionShort'
1882  ),
1883  'border-left' => true, // add left line separator
1884  );
1885  if ($this->atleastonediscount) {
1886  $this->cols['discount']['status'] = true;
1887  }
1888 
1889  $rank = $rank + 1000; // add a big offset to be sure is the last col because default extrafield rank is 100
1890  $this->cols['totalexcltax'] = array(
1891  'rank' => $rank,
1892  'width' => 26, // in mm
1893  'status' => empty($conf->global->PDF_PROPAL_HIDE_PRICE_EXCL_TAX) ? true : false,
1894  'title' => array(
1895  'textkey' => 'TotalHTShort'
1896  ),
1897  'border-left' => true, // add left line separator
1898  );
1899 
1900  $rank = $rank + 1010; // add a big offset to be sure is the last col because default extrafield rank is 100
1901  $this->cols['totalincltax'] = array(
1902  'rank' => $rank,
1903  'width' => 26, // in mm
1904  'status' => empty($conf->global->PDF_PROPAL_SHOW_PRICE_INCL_TAX) ? false : true,
1905  'title' => array(
1906  'textkey' => 'TotalTTCShort'
1907  ),
1908  'border-left' => true, // add left line separator
1909  );
1910 
1911  // Add extrafields cols
1912  if (!empty($object->lines)) {
1913  $line = reset($object->lines);
1914  $this->defineColumnExtrafield($line, $outputlangs, $hidedetails);
1915  }
1916 
1917  $parameters = array(
1918  'object' => $object,
1919  'outputlangs' => $outputlangs,
1920  'hidedetails' => $hidedetails,
1921  'hidedesc' => $hidedesc,
1922  'hideref' => $hideref
1923  );
1924 
1925  $reshook = $hookmanager->executeHooks('defineColumnField', $parameters, $this); // Note that $object may have been modified by hook
1926  if ($reshook < 0) {
1927  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1928  } elseif (empty($reshook)) {
1929  $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys
1930  } else {
1931  $this->cols = $hookmanager->resArray;
1932  }
1933  }
1934 }
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:47
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: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_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:2325
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
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