dolibarr  x.y.z
pdf_crabe.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-2014 Juanjo Menent <jmenent@2byte.es>
6  * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
7  * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr>
8  * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
9  * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
10  * Copyright (C) 2017-2018 Ferran Marcet <fmarcet@2byte.es>
11  * Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
12  * Copyright (C) 2022 Anthony Berton <anthony.berton@bb2a.fr>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program. If not, see <https://www.gnu.org/licenses/>.
26  * or see https://www.gnu.org/
27  */
28 
35 require_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php';
36 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
38 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
39 require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
40 
41 
46 {
50  public $db;
51 
55  public $name;
56 
60  public $description;
61 
65  public $update_main_doc_field;
66 
70  public $type;
71 
76  public $phpmin = array(7, 0);
77 
82  public $version = 'dolibarr';
83 
87  public $page_largeur;
88 
92  public $page_hauteur;
93 
97  public $format;
98 
102  public $marge_gauche;
103 
107  public $marge_droite;
108 
112  public $marge_haute;
113 
117  public $marge_basse;
118 
123  public $emetteur;
124 
128  public $situationinvoice;
129 
133  public $posxprogress;
134 
135 
141  public function __construct($db)
142  {
143  global $conf, $langs, $mysoc;
144 
145  // Translations
146  $langs->loadLangs(array("main", "bills"));
147 
148  $this->db = $db;
149  $this->name = "crabe";
150  $this->description = $langs->trans('PDFCrabeDescription');
151  $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template
152 
153  // Dimension page
154  $this->type = 'pdf';
155  $formatarray = pdf_getFormat();
156  $this->page_largeur = $formatarray['width'];
157  $this->page_hauteur = $formatarray['height'];
158  $this->format = array($this->page_largeur, $this->page_hauteur);
159  $this->marge_gauche = getDolGlobalInt('MAIN_PDF_MARGIN_LEFT', 10);
160  $this->marge_droite = getDolGlobalInt('MAIN_PDF_MARGIN_RIGHT', 10);
161  $this->marge_haute = getDolGlobalInt('MAIN_PDF_MARGIN_TOP', 10);
162  $this->marge_basse = getDolGlobalInt('MAIN_PDF_MARGIN_BOTTOM', 10);
163 
164  $this->option_logo = 1; // Display logo
165  $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION
166  $this->option_modereg = 1; // Display payment mode
167  $this->option_condreg = 1; // Display payment terms
168  $this->option_multilang = 1; // Available in several languages
169  $this->option_escompte = 1; // Displays if there has been a discount
170  $this->option_credit_note = 1; // Support credit notes
171  $this->option_freetext = 1; // Support add of a personalised text
172  $this->option_draft_watermark = 1; // Support add of a watermark on drafts
173  $this->watermark = '';
174 
175  // Get source company
176  $this->emetteur = $mysoc;
177  if (empty($this->emetteur->country_code)) {
178  $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined
179  }
180 
181  // Define position of columns
182  $this->posxdesc = $this->marge_gauche + 1;
183  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
184  $this->posxtva = 101;
185  $this->posxup = 118;
186  $this->posxqty = 135;
187  $this->posxunit = 151;
188  } else {
189  $this->posxtva = 110;
190  $this->posxup = 126;
191  $this->posxqty = 145;
192  $this->posxunit = 162;
193  }
194  $this->posxprogress = 151; // Only displayed for situation invoices
195  $this->posxdiscount = 162;
196  $this->posxprogress = 174;
197  $this->postotalht = 174;
198  if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) || !empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
199  $this->posxtva = $this->posxup;
200  }
201  $this->posxpicture = $this->posxtva - (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH) ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH); // width of images
202  if ($this->page_largeur < 210) { // To work with US executive format
203  $this->posxpicture -= 20;
204  $this->posxtva -= 20;
205  $this->posxup -= 20;
206  $this->posxqty -= 20;
207  $this->posxunit -= 20;
208  $this->posxdiscount -= 20;
209  $this->posxprogress -= 20;
210  $this->postotalht -= 20;
211  }
212 
213  $this->tva = array();
214  $this->tva_array = array();
215  $this->localtax1 = array();
216  $this->localtax2 = array();
217  $this->atleastoneratenotnull = 0;
218  $this->atleastonediscount = 0;
219  $this->situationinvoice = false;
220  }
221 
222 
223  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
235  public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
236  {
237  // phpcs:enable
238  global $user, $langs, $conf, $mysoc, $hookmanager, $nblines;
239 
240  dol_syslog("write_file outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null'));
241 
242  if (!is_object($outputlangs)) {
243  $outputlangs = $langs;
244  }
245  // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
246  if (!empty($conf->global->MAIN_USE_FPDF)) {
247  $outputlangs->charset_output = 'ISO-8859-1';
248  }
249 
250  // Load translation files required by the page
251  $outputlangs->loadLangs(array("main", "bills", "products", "dict", "companies"));
252 
253  // Show Draft Watermark
254  if ($object->statut == $object::STATUS_DRAFT && (!empty($conf->global->FACTURE_DRAFT_WATERMARK))) {
255  $this->watermark = $conf->global->FACTURE_DRAFT_WATERMARK;
256  }
257 
258  global $outputlangsbis;
259  $outputlangsbis = null;
260  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) {
261  $outputlangsbis = new Translate('', $conf);
262  $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE);
263  $outputlangsbis->loadLangs(array("main", "bills", "products", "dict", "companies"));
264  }
265 
266  $nblines = count($object->lines);
267 
268  // Loop on each lines to detect if there is at least one image to show
269  $realpatharray = array();
270  if (!empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE)) {
271  for ($i = 0; $i < $nblines; $i++) {
272  if (empty($object->lines[$i]->fk_product)) {
273  continue;
274  }
275 
276  $objphoto = new Product($this->db);
277  $objphoto->fetch($object->lines[$i]->fk_product);
278 
279  $pdir = get_exdir($object->lines[$i]->fk_product, 2, 0, 0, $objphoto, 'product').$object->lines[$i]->fk_product."/photos/";
280  $dir = $conf->product->dir_output.'/'.$pdir;
281 
282  $realpath = '';
283  foreach ($objphoto->liste_photos($dir, 1) as $key => $obj) {
284  $filename = $obj['photo'];
285  //if ($obj['photo_vignette']) $filename='thumbs/'.$obj['photo_vignette'];
286  $realpath = $dir.$filename;
287  break;
288  }
289 
290  if ($realpath) {
291  $realpatharray[$i] = $realpath;
292  }
293  }
294  }
295  if (count($realpatharray) == 0) {
296  $this->posxpicture = $this->posxtva;
297  }
298 
299  if ($conf->facture->dir_output) {
300  $object->fetch_thirdparty();
301 
302  $deja_regle = $object->getSommePaiement((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? 1 : 0);
303  $amount_credit_notes_included = $object->getSumCreditNotesUsed((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? 1 : 0);
304  $amount_deposits_included = $object->getSumDepositsUsed((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? 1 : 0);
305 
306  // Definition of $dir and $file
307  if ($object->specimen) {
308  $dir = empty($conf->facture->multidir_output[$conf->entity]) ? $conf->facture->dir_output : $conf->facture->multidir_output[$conf->entity];
309  $file = $dir."/SPECIMEN.pdf";
310  } else {
311  $objectref = dol_sanitizeFileName($object->ref);
312  $dir = (empty($conf->facture->multidir_output[$conf->entity]) ? $conf->facture->dir_output : $conf->facture->multidir_output[$conf->entity])."/".$objectref;
313  $file = $dir."/".$objectref.".pdf";
314  }
315  if (!file_exists($dir)) {
316  if (dol_mkdir($dir) < 0) {
317  $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
318  return 0;
319  }
320  }
321 
322  if (file_exists($dir)) {
323  // Add pdfgeneration hook
324  if (!is_object($hookmanager)) {
325  include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
326  $hookmanager = new HookManager($this->db);
327  }
328  $hookmanager->initHooks(array('pdfgeneration'));
329  $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
330  global $action;
331  $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
332 
333  // Set nblines with the new facture lines content after hook
334  $nblines = count($object->lines);
335  $nbpayments = count($object->getListOfPayments());
336 
337  // Create pdf instance
338  $pdf = pdf_getInstance($this->format);
339  $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
340  $pdf->SetAutoPageBreak(1, 0);
341 
342  $heightforinfotot = 50 + (4 * $nbpayments); // Height reserved to output the info and total part and payment part
343  if ($heightforinfotot > 220) {
344  $heightforinfotot = 220;
345  }
346  $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
347  $heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin)
348  if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)) {
349  $heightforfooter += 6;
350  }
351 
352  if (class_exists('TCPDF')) {
353  $pdf->setPrintHeader(false);
354  $pdf->setPrintFooter(false);
355  }
356  $pdf->SetFont(pdf_getPDFFont($outputlangs));
357 
358  // Set path to the background PDF File
359  if (!empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) {
360  $logodir = $conf->mycompany->dir_output;
361  if (!empty($conf->mycompany->multidir_output[$object->entity])) {
362  $logodir = $conf->mycompany->multidir_output[$object->entity];
363  }
364  $pagecount = $pdf->setSourceFile($logodir.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND);
365  $tplidx = $pdf->importPage(1);
366  }
367 
368  $pdf->Open();
369  $pagenb = 0;
370  $pdf->SetDrawColor(128, 128, 128);
371 
372  $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
373  $pdf->SetSubject($outputlangs->transnoentities("PdfInvoiceTitle"));
374  $pdf->SetCreator("Dolibarr ".DOL_VERSION);
375  $pdf->SetAuthor($mysoc->name.($user->id > 0 ? ' - '.$outputlangs->convToOutputCharset($user->getFullName($outputlangs)) : ''));
376  $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfInvoiceTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
377  if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
378  $pdf->SetCompression(false);
379  }
380 
381  // Set certificate
382  $cert = empty($user->conf->CERTIFICATE_CRT) ? '' : $user->conf->CERTIFICATE_CRT;
383  $certprivate = empty($user->conf->CERTIFICATE_CRT_PRIVATE) ? '' : $user->conf->CERTIFICATE_CRT_PRIVATE;
384  // If user has no certificate, we try to take the company one
385  if (!$cert) {
386  $cert = empty($conf->global->CERTIFICATE_CRT) ? '' : $conf->global->CERTIFICATE_CRT;
387  }
388  if (!$certprivate) {
389  $certprivate = empty($conf->global->CERTIFICATE_CRT_PRIVATE) ? '' : $conf->global->CERTIFICATE_CRT_PRIVATE;
390  }
391  // If a certificate is found
392  if ($cert) {
393  $info = array(
394  'Name' => $this->emetteur->name,
395  'Location' => getCountry($this->emetteur->country_code, 0),
396  'Reason' => 'INVOICE',
397  'ContactInfo' => $this->emetteur->email
398  );
399  $pdf->setSignature($cert, $certprivate, $this->emetteur->name, '', 2, $info);
400  }
401 
402  $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
403 
404  // Set $this->atleastonediscount if you have at least one discount
405  for ($i = 0; $i < $nblines; $i++) {
406  if ($object->lines[$i]->remise_percent) {
407  $this->atleastonediscount++;
408  }
409  }
410  if (empty($this->atleastonediscount)) { // retrieve space not used by discount
411  $delta = ($this->posxprogress - $this->posxdiscount);
412  $this->posxpicture += $delta;
413  $this->posxtva += $delta;
414  $this->posxup += $delta;
415  $this->posxqty += $delta;
416  $this->posxunit += $delta;
417  $this->posxdiscount += $delta;
418  // post of fields after are not modified, stay at same position
419  }
420 
421  $progress_width = 0;
422  // Situation invoice handling
423  if ($object->situation_cycle_ref && empty($conf->global->MAIN_PDF_HIDE_SITUATION)) {
424  $this->situationinvoice = true;
425  $progress_width = 10;
426  $this->posxpicture -= $progress_width;
427  $this->posxtva -= $progress_width;
428  $this->posxup -= $progress_width;
429  $this->posxqty -= $progress_width;
430  $this->posxunit -= $progress_width;
431  $this->posxdiscount -= $progress_width;
432  $this->posxprogress -= $progress_width;
433  }
434 
435  // New page
436  $pdf->AddPage();
437  if (!empty($tplidx)) {
438  $pdf->useTemplate($tplidx);
439  }
440  $pagenb++;
441 
442  // Output header (logo, ref and address blocks). This is first call for first page.
443  $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs);
444  $pdf->SetFont('', '', $default_font_size - 1);
445  $pdf->MultiCell(0, 3, ''); // Set interline to 3
446  $pdf->SetTextColor(0, 0, 0);
447 
448  // $pdf->GetY() here can't be used. It is bottom of the second addresse box but first one may be higher
449 
450  // $tab_top is y where we must continue content (90 = 42 + 48: 42 is height of logo and ref, 48 is address blocks)
451  $tab_top = 90 + $top_shift; // top_shift is an addition for linked objects or addons (0 in most cases)
452  $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
453 
454  // You can add more thing under header here, if you increase $extra_under_address_shift too.
455  $extra_under_address_shift = 0;
456  $qrcodestring = '';
457  if (!empty($conf->global->INVOICE_ADD_ZATCA_QR_CODE)) {
458  $qrcodestring = $object->buildZATCAQRString();
459  } elseif (!empty($conf->global->INVOICE_ADD_SWISS_QR_CODE)) {
460  $qrcodestring = $object->buildSwitzerlandQRString();
461  }
462  if ($qrcodestring) {
463  $qrcodecolor = array('25', '25', '25');
464  // set style for QR-code
465  $styleQr = array(
466  'border' => false,
467  'padding' => 0,
468  'fgcolor' => $qrcodecolor,
469  'bgcolor' => false, //array(255,255,255)
470  'module_width' => 1, // width of a single module in points
471  'module_height' => 1 // height of a single module in points
472  );
473  $pdf->write2DBarcode($qrcodestring, 'QRCODE,M', $this->marge_gauche, $tab_top - 5, 25, 25, $styleQr, 'N');
474  $extra_under_address_shift += 25;
475  }
476 
477  // Call hook printUnderHeaderPDFline
478  $parameters = array(
479  'object' => $object,
480  'i' => $i,
481  'pdf' =>& $pdf,
482  'outputlangs' => $outputlangs,
483  'hidedetails' => $hidedetails
484  );
485  $reshook = $hookmanager->executeHooks('printUnderHeaderPDFline', $parameters, $this); // Note that $object may have been modified by hook
486  if (!empty($hookmanager->resArray['extra_under_address_shift'])) {
487  $extra_under_address_shift += $hookmanager->resArray['extra_under_header_shift'];
488  }
489 
490  $tab_top += $extra_under_address_shift;
491  $tab_top_newpage += 0;
492 
493  // Incoterm
494  $height_incoterms = 0;
495  if (isModEnabled('incoterm')) {
496  $desc_incoterms = $object->getIncotermsForPDF();
497  if ($desc_incoterms) {
498  $tab_top -= 2;
499 
500  $pdf->SetFont('', '', $default_font_size - 1);
501  $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($desc_incoterms), 0, 1);
502  $nexY = $pdf->GetY();
503  $height_incoterms = $nexY - $tab_top;
504 
505  // Rect takes a length in 3rd parameter
506  $pdf->SetDrawColor(192, 192, 192);
507  $pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_incoterms + 1);
508 
509  $tab_top = $nexY + 6;
510  }
511  }
512 
513  // Display notes
514  $notetoshow = empty($object->note_public) ? '' : $object->note_public;
515  if (!empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE)) {
516  // Get first sale rep
517  if (is_object($object->thirdparty)) {
518  $salereparray = $object->thirdparty->getSalesRepresentatives($user);
519  $salerepobj = new User($this->db);
520  $salerepobj->fetch($salereparray[0]['id']);
521  if (!empty($salerepobj->signature)) {
522  $notetoshow = dol_concatdesc($notetoshow, $salerepobj->signature);
523  }
524  }
525  }
526  // Extrafields in note
527  $extranote = $this->getExtrafieldsInHtml($object, $outputlangs);
528  if (!empty($extranote)) {
529  $notetoshow = dol_concatdesc($notetoshow, $extranote);
530  }
531  if ($notetoshow) {
532  $tab_top -= 2;
533 
534  $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
535  complete_substitutions_array($substitutionarray, $outputlangs, $object);
536 
537  $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
538  $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);
539 
540  $pdf->SetFont('', '', $default_font_size - 1);
541  $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($notetoshow), 0, 1);
542  $nexY = $pdf->GetY();
543  $height_note = $nexY - $tab_top;
544 
545  // Rect takes a length in 3rd parameter
546  $pdf->SetDrawColor(192, 192, 192);
547  $pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_note + 1);
548 
549  $tab_top = $nexY + 6;
550  }
551 
552  $iniY = $tab_top + 7;
553  $curY = $tab_top + 7;
554  $nexY = $tab_top + 7;
555 
556  // Loop on each lines
557  for ($i = 0; $i < $nblines; $i++) {
558  $curY = $nexY;
559  $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
560  $pdf->SetTextColor(0, 0, 0);
561 
562  // Define size of image if we need it
563  $imglinesize = array();
564  if (!empty($realpatharray[$i])) {
565  $imglinesize = pdf_getSizeForImage($realpatharray[$i]);
566  }
567 
568  $pdf->setTopMargin($tab_top_newpage);
569  $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext + $heightforinfotot); // The only function to edit the bottom margin of current page to set it.
570  $pageposbefore = $pdf->getPage();
571 
572  $showpricebeforepagebreak = 1;
573  $posYAfterImage = 0;
574  $posYAfterDescription = 0;
575 
576  // We start with Photo of product line
577  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
578  $pdf->AddPage('', '', true);
579  if (!empty($tplidx)) {
580  $pdf->useTemplate($tplidx);
581  }
582  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
583  $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs);
584  $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
585  }
586  $pdf->setPage($pageposbefore + 1);
587 
588  $curY = $tab_top_newpage;
589 
590  // Allows data in the first page if description is long enough to break in multiples pages
591  if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {
592  $showpricebeforepagebreak = 1;
593  } else {
594  $showpricebeforepagebreak = 0;
595  }
596  }
597 
598  if (isset($imglinesize['width']) && isset($imglinesize['height'])) {
599  $curX = $this->posxpicture - 1;
600  $pdf->Image($realpatharray[$i], $curX + (($this->posxtva - $this->posxpicture - $imglinesize['width']) / 2), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi
601  // $pdf->Image does not increase value return by getY, so we save it manually
602  $posYAfterImage = $curY + $imglinesize['height'];
603  }
604 
605  // Description of product line
606  $curX = $this->posxdesc - 1;
607 
608  $pdf->startTransaction();
609  pdf_writelinedesc($pdf, $object, $i, $outputlangs, $this->posxpicture - $curX - $progress_width, 3, $curX, $curY, $hideref, $hidedesc);
610  $pageposafter = $pdf->getPage();
611  if ($pageposafter > $pageposbefore) { // There is a pagebreak
612  $pdf->rollbackTransaction(true);
613  $pageposafter = $pageposbefore;
614  //print $pageposafter.'-'.$pageposbefore;exit;
615  $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
616  pdf_writelinedesc($pdf, $object, $i, $outputlangs, $this->posxpicture - $curX - $progress_width, 3, $curX, $curY, $hideref, $hidedesc);
617  $pageposafter = $pdf->getPage();
618  $posyafter = $pdf->GetY();
619  //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit;
620  if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) { // There is no space left for total+free text
621  if ($i == ($nblines - 1)) { // No more lines, and no space left to show total, so we create a new page
622  $pdf->AddPage('', '', true);
623  if (!empty($tplidx)) {
624  $pdf->useTemplate($tplidx);
625  }
626  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
627  $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs);
628  $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
629  }
630  $pdf->setPage($pageposafter + 1);
631  }
632  } else {
633  // We found a page break
634 
635  // Allows data in the first page if description is long enough to break in multiples pages
636  if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {
637  $showpricebeforepagebreak = 1;
638  } else {
639  $showpricebeforepagebreak = 0;
640  }
641  }
642  } else // No pagebreak
643  {
644  $pdf->commitTransaction();
645  }
646  $posYAfterDescription = $pdf->GetY();
647 
648  $nexY = $pdf->GetY();
649  $pageposafter = $pdf->getPage();
650  $pdf->setPage($pageposbefore);
651  $pdf->setTopMargin($this->marge_haute);
652  $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
653 
654  // We suppose that a too long description or photo were moved completely on next page
655  if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
656  $pdf->setPage($pageposafter);
657  $curY = $tab_top_newpage;
658  }
659 
660  $pdf->SetFont('', '', $default_font_size - 1); // We reposition the default font
661 
662  // VAT Rate
663  if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
664  $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
665  $pdf->SetXY($this->posxtva - 5, $curY);
666  $pdf->MultiCell($this->posxup - $this->posxtva + 4, 3, $vat_rate, 0, 'R');
667  }
668 
669  // Unit price before discount
670  $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);
671  $pdf->SetXY($this->posxup, $curY);
672  $pdf->MultiCell($this->posxqty - $this->posxup - 0.8, 3, $up_excl_tax, 0, 'R', 0);
673 
674  // Quantity
675  $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
676  $pdf->SetXY($this->posxqty, $curY);
677  $pdf->MultiCell($this->posxunit - $this->posxqty - 0.8, 4, $qty, 0, 'R'); // Enough for 6 chars
678 
679  // Unit
680  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
681  $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager);
682  $pdf->SetXY($this->posxunit, $curY);
683  $pdf->MultiCell($this->posxdiscount - $this->posxunit - 0.8, 4, $unit, 0, 'L');
684  }
685 
686  // Discount on line
687  if ($object->lines[$i]->remise_percent) {
688  $pdf->SetXY($this->posxdiscount - 2, $curY);
689  $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);
690  $pdf->MultiCell($this->posxprogress - $this->posxdiscount + 2, 3, $remise_percent, 0, 'R');
691  }
692 
693  // Situation progress
694  if ($this->situationinvoice) {
695  $progress = pdf_getlineprogress($object, $i, $outputlangs, $hidedetails);
696  $pdf->SetXY($this->posxprogress, $curY);
697  $pdf->MultiCell($this->postotalht - $this->posxprogress + 1, 3, $progress, 0, 'R');
698  }
699 
700  // Total HT line
701  $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails);
702  $pdf->SetXY($this->postotalht, $curY);
703  $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->postotalht, 3, $total_excl_tax, 0, 'R', 0);
704 
705 
706  $sign = 1;
707  if (isset($object->type) && $object->type == 2 && !empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) {
708  $sign = -1;
709  }
710  // Collection of totals by value of VAT in $this->tva["taux"]=total_tva
711  $prev_progress = $object->lines[$i]->get_prev_progress($object->id);
712  if ($prev_progress > 0 && !empty($object->lines[$i]->situation_percent)) { // Compute progress from previous situation
713  if (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) {
714  $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent;
715  } else {
716  $tvaligne = $sign * $object->lines[$i]->total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent;
717  }
718  } else {
719  if (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) {
720  $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva;
721  } else {
722  $tvaligne = $sign * $object->lines[$i]->total_tva;
723  }
724  }
725 
726  $localtax1ligne = $object->lines[$i]->total_localtax1;
727  $localtax2ligne = $object->lines[$i]->total_localtax2;
728  $localtax1_rate = $object->lines[$i]->localtax1_tx;
729  $localtax2_rate = $object->lines[$i]->localtax2_tx;
730  $localtax1_type = $object->lines[$i]->localtax1_type;
731  $localtax2_type = $object->lines[$i]->localtax2_type;
732 
733  if ($object->remise_percent) {
734  $tvaligne -= ($tvaligne * $object->remise_percent) / 100;
735  }
736  if ($object->remise_percent) {
737  $localtax1ligne -= ($localtax1ligne * $object->remise_percent) / 100;
738  }
739  if ($object->remise_percent) {
740  $localtax2ligne -= ($localtax2ligne * $object->remise_percent) / 100;
741  }
742 
743  $vatrate = (string) $object->lines[$i]->tva_tx;
744 
745  // Retrieve type from database for backward compatibility with old records
746  if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined
747  && (!empty($localtax1_rate) || !empty($localtax2_rate))) { // and there is local tax
748  $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $object->thirdparty, $mysoc);
749  $localtax1_type = isset($localtaxtmp_array[0]) ? $localtaxtmp_array[0] : '';
750  $localtax2_type = isset($localtaxtmp_array[2]) ? $localtaxtmp_array[2] : '';
751  }
752 
753  // retrieve global local tax
754  if ($localtax1_type && $localtax1ligne != 0) {
755  if (empty($this->localtax1[$localtax1_type][$localtax1_rate])) {
756  $this->localtax1[$localtax1_type][$localtax1_rate] = $localtax1ligne;
757  } else {
758  $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne;
759  }
760  }
761  if ($localtax2_type && $localtax2ligne != 0) {
762  if (empty($this->localtax2[$localtax2_type][$localtax2_rate])) {
763  $this->localtax2[$localtax2_type][$localtax2_rate] = $localtax2ligne;
764  } else {
765  $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne;
766  }
767  }
768 
769  if (($object->lines[$i]->info_bits & 0x01) == 0x01) {
770  $vatrate .= '*';
771  }
772 
773  // Fill $this->tva and $this->tva_array
774  if (!isset($this->tva[$vatrate])) {
775  $this->tva[$vatrate] = 0;
776  }
777  $this->tva[$vatrate] += $tvaligne; // ->tva is abandonned, we use now ->tva_array that is more complete
778  $vatcode = $object->lines[$i]->vat_src_code;
779  if (empty($this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'])) {
780  $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] = 0;
781  }
782  $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')] = array('vatrate'=>$vatrate, 'vatcode'=>$vatcode, 'amount'=> $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] + $tvaligne);
783 
784  if ($posYAfterImage > $posYAfterDescription) {
785  $nexY = $posYAfterImage;
786  }
787 
788  // Add line
789  if (!empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblines - 1)) {
790  $pdf->setPage($pageposafter);
791  $pdf->SetLineStyle(array('dash'=>'1,1', 'color'=>array(80, 80, 80)));
792  //$pdf->SetDrawColor(190,190,200);
793  $pdf->line($this->marge_gauche, $nexY + 1, $this->page_largeur - $this->marge_droite, $nexY + 1);
794  $pdf->SetLineStyle(array('dash'=>0));
795  }
796 
797  $nexY += 2; // Add space between lines
798 
799  // Detect if some page were added automatically and output _tableau for past pages
800  while ($pagenb < $pageposafter) {
801  $pdf->setPage($pagenb);
802  if ($pagenb == 1) {
803  $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
804  } else {
805  $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
806  }
807  $this->_pagefoot($pdf, $object, $outputlangs, 1);
808  $pagenb++;
809  $pdf->setPage($pagenb);
810  $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
811  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
812  $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs);
813  $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
814  }
815  if (!empty($tplidx)) {
816  $pdf->useTemplate($tplidx);
817  }
818  }
819  if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) {
820  if ($pagenb == 1) {
821  $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
822  } else {
823  $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
824  }
825  $this->_pagefoot($pdf, $object, $outputlangs, 1);
826  // New page
827  $pdf->AddPage();
828  if (!empty($tplidx)) {
829  $pdf->useTemplate($tplidx);
830  }
831  $pagenb++;
832  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
833  $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs);
834  $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
835  }
836  }
837  }
838 
839  // Show square
840  if ($pagenb == 1) {
841  $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code);
842  $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
843  } else {
844  $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code);
845  $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
846  }
847  dol_syslog("bottomlasttab=".$bottomlasttab." this->page_hauteur=".$this->page_hauteur." heightforinfotot=".$heightforinfotot." heightforfreetext=".$heightforfreetext." heightforfooter=".$heightforfooter);
848 
849  // Display info area
850  $posy = $this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs, $outputlangsbis);
851 
852  // Display total area
853  $posy = $this->_tableau_tot($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs, $outputlangsbis);
854 
855  // Display Payments area
856  if (($deja_regle || $amount_credit_notes_included || $amount_deposits_included) && empty($conf->global->INVOICE_NO_PAYMENT_DETAILS)) {
857  $posy = $this->_tableau_versements($pdf, $object, $posy, $outputlangs, $heightforfooter);
858  }
859 
860  // Pagefoot
861  $this->_pagefoot($pdf, $object, $outputlangs);
862  if (method_exists($pdf, 'AliasNbPages')) {
863  $pdf->AliasNbPages();
864  }
865 
866  $pdf->Close();
867 
868  $pdf->Output($file, 'F');
869 
870  // Add pdfgeneration hook
871  $hookmanager->initHooks(array('pdfgeneration'));
872  $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
873  global $action;
874  $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
875  if ($reshook < 0) {
876  $this->error = $hookmanager->error;
877  $this->errors = $hookmanager->errors;
878  }
879 
880  if (!empty($conf->global->MAIN_UMASK)) {
881  @chmod($file, octdec($conf->global->MAIN_UMASK));
882  }
883 
884  $this->result = array('fullpath'=>$file);
885 
886  return 1; // No error
887  } else {
888  $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
889  return 0;
890  }
891  } else {
892  $this->error = $langs->transnoentities("ErrorConstantNotDefined", "FAC_OUTPUTDIR");
893  return 0;
894  }
895  }
896 
897 
898  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
899  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
910  protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs, $heightforfooter = 0)
911  {
912  // phpcs:enable
913  global $conf;
914 
915  $sign = 1;
916  if ($object->type == 2 && !empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) {
917  $sign = -1;
918  }
919 
920  $current_page = $pdf->getPage();
921  $tab3_posx = 120;
922  $tab3_top = $posy + 8;
923  $tab3_width = 80;
924  $tab3_height = 4;
925  if ($this->page_largeur < 210) { // To work with US executive format
926  $tab3_posx -= 15;
927  }
928 
929  $default_font_size = pdf_getPDFFontSize($outputlangs);
930 
931  $this->_tableau_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top, $tab3_width, $tab3_height);
932 
933  $y = 0;
934 
935  $pdf->SetFont('', '', $default_font_size - 4);
936 
937 
938  // Loop on each discount available (deposits and credit notes and excess of payment included)
939  $sql = "SELECT re.rowid, re.amount_ht, re.multicurrency_amount_ht, re.amount_tva, re.multicurrency_amount_tva, re.amount_ttc, re.multicurrency_amount_ttc,";
940  $sql .= " re.description, re.fk_facture_source,";
941  $sql .= " f.type, f.datef";
942  $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture as f";
943  $sql .= " WHERE re.fk_facture_source = f.rowid AND re.fk_facture = ".((int) $object->id);
944  $resql = $this->db->query($sql);
945  if ($resql) {
946  $num = $this->db->num_rows($resql);
947  $i = 0;
948  $invoice = new Facture($this->db);
949  while ($i < $num) {
950  $y += 3;
951  if ($tab3_top + $y >= ($this->page_hauteur - $heightforfooter)) {
952  $y = 0;
953  $current_page++;
954  $pdf->AddPage('', '', true);
955  if (!empty($tplidx)) {
956  $pdf->useTemplate($tplidx);
957  }
958  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
959  $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs);
960  $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
961  }
962  $pdf->setPage($current_page);
963  $this->_tableau_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top + $y - 3, $tab3_width, $tab3_height);
964  }
965 
966  $obj = $this->db->fetch_object($resql);
967 
968  if ($obj->type == 2) {
969  $text = $outputlangs->transnoentities("CreditNote");
970  } elseif ($obj->type == 3) {
971  $text = $outputlangs->transnoentities("Deposit");
972  } elseif ($obj->type == 0) {
973  $text = $outputlangs->transnoentities("ExcessReceived");
974  } else {
975  $text = $outputlangs->transnoentities("UnknownType");
976  }
977 
978  $invoice->fetch($obj->fk_facture_source);
979 
980  $pdf->SetXY($tab3_posx, $tab3_top + $y);
981  $pdf->MultiCell(20, 3, dol_print_date($this->db->jdate($obj->datef), 'day', false, $outputlangs, true), 0, 'L', 0);
982  $pdf->SetXY($tab3_posx + 21, $tab3_top + $y);
983  $pdf->MultiCell(20, 3, price((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $obj->multicurrency_amount_ttc : $obj->amount_ttc, 0, $outputlangs), 0, 'L', 0);
984  $pdf->SetXY($tab3_posx + 40, $tab3_top + $y);
985  $pdf->MultiCell(20, 3, $text, 0, 'L', 0);
986  $pdf->SetXY($tab3_posx + 58, $tab3_top + $y);
987  $pdf->MultiCell(20, 3, $invoice->ref, 0, 'L', 0);
988 
989  $pdf->line($tab3_posx, $tab3_top + $y + 3, $tab3_posx + $tab3_width, $tab3_top + $y + 3);
990 
991  $i++;
992  }
993  } else {
994  $this->error = $this->db->lasterror();
995  return -1;
996  }
997 
998  // Loop on each payment
999  // TODO Call getListOfPaymentsgetListOfPayments instead of hard coded sql
1000  $sql = "SELECT p.datep as date, p.fk_paiement, p.num_paiement as num, pf.amount as amount, pf.multicurrency_amount,";
1001  $sql .= " cp.code";
1002  $sql .= " FROM ".MAIN_DB_PREFIX."paiement_facture as pf, ".MAIN_DB_PREFIX."paiement as p";
1003  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as cp ON p.fk_paiement = cp.id";
1004  $sql .= " WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = ".((int) $object->id);
1005  //$sql.= " WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = 1";
1006  $sql .= " ORDER BY p.datep";
1007 
1008  $resql = $this->db->query($sql);
1009  if ($resql) {
1010  $num = $this->db->num_rows($resql);
1011  $i = 0;
1012  while ($i < $num) {
1013  $y += 3;
1014  if ($tab3_top + $y >= ($this->page_hauteur - $heightforfooter)) {
1015  $y = 0;
1016  $current_page++;
1017  $pdf->AddPage('', '', true);
1018  if (!empty($tplidx)) {
1019  $pdf->useTemplate($tplidx);
1020  }
1021  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
1022  $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs);
1023  $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
1024  }
1025  $pdf->setPage($current_page);
1026  $this->_tableau_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top + $y - 3, $tab3_width, $tab3_height);
1027  }
1028 
1029  $row = $this->db->fetch_object($resql);
1030 
1031  $pdf->SetXY($tab3_posx, $tab3_top + $y);
1032  $pdf->MultiCell(20, 3, dol_print_date($this->db->jdate($row->date), 'day', false, $outputlangs, true), 0, 'L', 0);
1033  $pdf->SetXY($tab3_posx + 21, $tab3_top + $y);
1034  $pdf->MultiCell(20, 3, price($sign * ((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $row->multicurrency_amount : $row->amount), 0, $outputlangs), 0, 'L', 0);
1035  $pdf->SetXY($tab3_posx + 40, $tab3_top + $y);
1036  $oper = $outputlangs->transnoentitiesnoconv("PaymentTypeShort".$row->code);
1037 
1038  $pdf->MultiCell(20, 3, $oper, 0, 'L', 0);
1039  $pdf->SetXY($tab3_posx + 58, $tab3_top + $y);
1040  $pdf->MultiCell(30, 3, $row->num, 0, 'L', 0);
1041 
1042  $pdf->line($tab3_posx, $tab3_top + $y + 3, $tab3_posx + $tab3_width, $tab3_top + $y + 3);
1043 
1044  $i++;
1045  }
1046 
1047  return $tab3_top + $y + 3;
1048  } else {
1049  $this->error = $this->db->lasterror();
1050  return -1;
1051  }
1052  }
1053 
1054  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1055  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1069  protected function _tableau_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top, $tab3_width, $tab3_height)
1070  {
1071  // phpcs:enable
1072  $title = $outputlangs->transnoentities("PaymentsAlreadyDone");
1073  if ($object->type == 2) {
1074  $title = $outputlangs->transnoentities("PaymentsBackAlreadyDone");
1075  }
1076 
1077  $pdf->SetFont('', '', $default_font_size - 3);
1078  $pdf->SetXY($tab3_posx, $tab3_top - 4);
1079  $pdf->MultiCell(60, 3, $title, 0, 'L', 0);
1080 
1081  $pdf->line($tab3_posx, $tab3_top, $tab3_posx + $tab3_width, $tab3_top);
1082 
1083  $pdf->SetFont('', '', $default_font_size - 4);
1084  $pdf->SetXY($tab3_posx, $tab3_top);
1085  $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Payment"), 0, 'L', 0);
1086  $pdf->SetXY($tab3_posx + 21, $tab3_top);
1087  $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Amount"), 0, 'L', 0);
1088  $pdf->SetXY($tab3_posx + 40, $tab3_top);
1089  $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Type"), 0, 'L', 0);
1090  $pdf->SetXY($tab3_posx + 58, $tab3_top);
1091  $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Num"), 0, 'L', 0);
1092 
1093  $pdf->line($tab3_posx, $tab3_top - 1 + $tab3_height, $tab3_posx + $tab3_width, $tab3_top - 1 + $tab3_height);
1094  }
1095 
1096  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1097  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1108  protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlangsbis)
1109  {
1110  // phpcs:enable
1111  global $conf, $mysoc;
1112 
1113  $default_font_size = pdf_getPDFFontSize($outputlangs);
1114 
1115  $pdf->SetFont('', '', $default_font_size - 1);
1116 
1117  // If France, show VAT mention if not applicable
1118  if ($this->emetteur->country_code == 'FR' && empty($mysoc->tva_assuj)) {
1119  $pdf->SetFont('', 'B', $default_font_size - 2);
1120  $pdf->SetXY($this->marge_gauche, $posy);
1121  if ($mysoc->forme_juridique_code == 92) {
1122  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoiceAsso"), 0, 'L', 0);
1123  } else {
1124  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0);
1125  }
1126 
1127  $posy = $pdf->GetY() + 4;
1128  }
1129 
1130  $posxval = 52;
1131 
1132  // Show payments conditions
1133  if ($object->type != 2 && ($object->cond_reglement_code || $object->cond_reglement)) {
1134  $pdf->SetFont('', 'B', $default_font_size - 2);
1135  $pdf->SetXY($this->marge_gauche, $posy);
1136  $titre = $outputlangs->transnoentities("PaymentConditions").':';
1137  $pdf->MultiCell(43, 4, $titre, 0, 'L');
1138 
1139  $pdf->SetFont('', '', $default_font_size - 2);
1140  $pdf->SetXY($posxval, $posy);
1141  $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);
1142  $lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
1143  $pdf->MultiCell(67, 4, $lib_condition_paiement, 0, 'L');
1144 
1145  $posy = $pdf->GetY() + 3; // We need spaces for 2 lines payment conditions
1146  }
1147 
1148  if ($object->type != 2) {
1149  // Check a payment mode is defined
1150  if (empty($object->mode_reglement_code)
1151  && empty($conf->global->FACTURE_CHQ_NUMBER)
1152  && !getDolGlobalInt('FACTURE_RIB_NUMBER')) {
1153  $this->error = $outputlangs->transnoentities("ErrorNoPaiementModeConfigured");
1154  } elseif (($object->mode_reglement_code == 'CHQ' && empty($conf->global->FACTURE_CHQ_NUMBER) && empty($object->fk_account) && empty($object->fk_bank))
1155  || ($object->mode_reglement_code == 'VIR' && !getDolGlobalInt('FACTURE_RIB_NUMBER') && empty($object->fk_account) && empty($object->fk_bank))) {
1156  // Avoid having any valid PDF with setup that is not complete
1157  $outputlangs->load("errors");
1158 
1159  $pdf->SetXY($this->marge_gauche, $posy);
1160  $pdf->SetTextColor(200, 0, 0);
1161  $pdf->SetFont('', 'B', $default_font_size - 2);
1162  $this->error = $outputlangs->transnoentities("ErrorPaymentModeDefinedToWithoutSetup", $object->mode_reglement_code);
1163  $pdf->MultiCell(80, 3, $this->error, 0, 'L', 0);
1164  $pdf->SetTextColor(0, 0, 0);
1165 
1166  $posy = $pdf->GetY() + 1;
1167  }
1168 
1169  // Show payment mode
1170  if (!empty($object->mode_reglement_code)
1171  && $object->mode_reglement_code != 'CHQ'
1172  && $object->mode_reglement_code != 'VIR') {
1173  $pdf->SetFont('', 'B', $default_font_size - 2);
1174  $pdf->SetXY($this->marge_gauche, $posy);
1175  $titre = $outputlangs->transnoentities("PaymentMode").':';
1176  $pdf->MultiCell(80, 5, $titre, 0, 'L');
1177 
1178  $pdf->SetFont('', '', $default_font_size - 2);
1179  $pdf->SetXY($posxval, $posy);
1180  $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);
1181  //#21654: add account number used for the debit
1182  if ($object->mode_reglement_code == "PRE") {
1183  require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
1184  $bac = new CompanyBankAccount($this->db);
1185  $bac->fetch(0, $object->thirdparty->id);
1186  $iban= $bac->iban.(($bac->iban && $bac->bic) ? ' / ' : '').$bac->bic;
1187  $lib_mode_reg .= $outputlangs->trans("PaymentTypePREdetails", dol_trunc($iban, 6, 'right', 'UTF-8', 1));
1188  }
1189  $pdf->MultiCell(80, 5, $lib_mode_reg, 0, 'L');
1190 
1191  $posy = $pdf->GetY();
1192  }
1193 
1194  // Show if Option VAT debit option is on also if transmitter is french
1195  // Decret n°2099-1299 2022-10-07
1196  // French mention : "Option pour le paiement de la taxe d'après les débits"
1197  if ($this->emetteur->country_code == 'FR') {
1198  if (isset($conf->global->TAX_MODE) && $conf->global->TAX_MODE == 1) {
1199  $pdf->SetXY($this->marge_gauche, $posy);
1200  $pdf->writeHTMLCell(80, 5, '', '', $outputlangs->transnoentities("MentionVATDebitOptionIsOn"), 0, 1);
1201 
1202  $posy = $pdf->GetY() + 1;
1203  }
1204  }
1205 
1206  // Show online payment link
1207  if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CB' || $object->mode_reglement_code == 'VAD') {
1208  $useonlinepayment = 0;
1209  if (!empty($conf->global->PDF_SHOW_LINK_TO_ONLINE_PAYMENT)) {
1210  if (isModEnabled('paypal')) {
1211  $useonlinepayment++;
1212  }
1213  if (isModEnabled('stripe')) {
1214  $useonlinepayment++;
1215  }
1216  if (isModEnabled('paybox')) {
1217  $useonlinepayment++;
1218  }
1219  }
1220 
1221  if ($object->statut != Facture::STATUS_DRAFT && $useonlinepayment) {
1222  require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
1223  global $langs;
1224 
1225  $langs->loadLangs(array('payment', 'paybox', 'stripe'));
1226  $servicename = $langs->transnoentities('Online');
1227  $paiement_url = getOnlinePaymentUrl('', 'invoice', $object->ref, '', '', '');
1228  $linktopay = $langs->trans("ToOfferALinkForOnlinePayment", $servicename).' <a href="'.$paiement_url.'">'.$outputlangs->transnoentities("ClickHere").'</a>';
1229 
1230  $pdf->SetXY($this->marge_gauche, $posy);
1231  $pdf->writeHTMLCell(80, 5, '', '', dol_htmlentitiesbr($linktopay), 0, 1);
1232 
1233  $posy = $pdf->GetY() + 1;
1234  }
1235  }
1236 
1237  // Show payment mode CHQ
1238  if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ') {
1239  // If payment mode unregulated or payment mode forced to CHQ
1240  if (!empty($conf->global->FACTURE_CHQ_NUMBER)) {
1241  $diffsizetitle = (empty($conf->global->PDF_DIFFSIZE_TITLE) ? 3 : $conf->global->PDF_DIFFSIZE_TITLE);
1242 
1243  if ($conf->global->FACTURE_CHQ_NUMBER > 0) {
1244  $account = new Account($this->db);
1245  $account->fetch($conf->global->FACTURE_CHQ_NUMBER);
1246 
1247  $pdf->SetXY($this->marge_gauche, $posy);
1248  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1249  $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $account->proprio), 0, 'L', 0);
1250  $posy = $pdf->GetY() + 1;
1251 
1252  if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) {
1253  $pdf->SetXY($this->marge_gauche, $posy);
1254  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1255  $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0);
1256  $posy = $pdf->GetY() + 2;
1257  }
1258  }
1259  if ($conf->global->FACTURE_CHQ_NUMBER == -1) {
1260  $pdf->SetXY($this->marge_gauche, $posy);
1261  $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1262  $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $this->emetteur->name), 0, 'L', 0);
1263  $posy = $pdf->GetY() + 1;
1264 
1265  if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) {
1266  $pdf->SetXY($this->marge_gauche, $posy);
1267  $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1268  $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0);
1269  $posy = $pdf->GetY() + 2;
1270  }
1271  }
1272  }
1273  }
1274 
1275  // If payment mode not forced or forced to VIR, show payment with BAN
1276  if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') {
1277  if ($object->fk_account > 0 || $object->fk_bank > 0 || getDolGlobalInt('FACTURE_RIB_NUMBER')) {
1278  $bankid = ($object->fk_account <= 0 ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account);
1279  if ($object->fk_bank > 0) {
1280  $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank
1281  }
1282  $account = new Account($this->db);
1283  $account->fetch($bankid);
1284 
1285  $curx = $this->marge_gauche;
1286  $cury = $posy;
1287 
1288  $posy = pdf_bank($pdf, $outputlangs, $curx, $cury, $account, 0, $default_font_size);
1289 
1290  $posy += 2;
1291  }
1292  }
1293  }
1294 
1295  return $posy;
1296  }
1297 
1298 
1299  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1300  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1312  protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis)
1313  {
1314  // phpcs:enable
1315  global $conf, $mysoc, $hookmanager;
1316 
1317  $sign = 1;
1318  if ($object->type == 2 && !empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) {
1319  $sign = -1;
1320  }
1321 
1322  $default_font_size = pdf_getPDFFontSize($outputlangs);
1323 
1324  $outputlangsbis = null;
1325  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) {
1326  $outputlangsbis = new Translate('', $conf);
1327  $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE);
1328  $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal"));
1329  $default_font_size--;
1330  }
1331 
1332  $tab2_top = $posy;
1333  $tab2_hl = 4;
1334  $pdf->SetFont('', '', $default_font_size - 1);
1335 
1336  // Total table
1337  $col1x = 120;
1338  $col2x = 170;
1339  if ($this->page_largeur < 210) { // To work with US executive format
1340  $col1x -= 15;
1341  $col2x -= 10;
1342  }
1343  $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
1344 
1345  $useborder = 0;
1346  $index = 0;
1347 
1348  // Total HT
1349  $pdf->SetFillColor(255, 255, 255);
1350  $pdf->SetXY($col1x, $tab2_top);
1351  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities(empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) ? "TotalHT" : "Total").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities(empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) ? "TotalHT" : "Total") : ''), 0, 'L', 1);
1352 
1353  $total_ht = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht);
1354  $pdf->SetXY($col2x, $tab2_top);
1355  $pdf->MultiCell($largcol2, $tab2_hl, price($sign * ($total_ht + (!empty($object->remise) ? $object->remise : 0)), 0, $outputlangs), 0, 'R', 1);
1356 
1357  // Show VAT by rates and total
1358  $pdf->SetFillColor(248, 248, 248);
1359 
1360  $total_ttc = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
1361 
1362  $this->atleastoneratenotnull = 0;
1363  if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) {
1364  $tvaisnull = ((!empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false);
1365  if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull) {
1366  // Nothing to do
1367  } else {
1368  // FIXME amount of vat not supported with multicurrency
1369 
1370  //Local tax 1 before VAT
1371  //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1372  //{
1373  foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1374  if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1375  continue;
1376  }
1377 
1378  foreach ($localtax_rate as $tvakey => $tvaval) {
1379  if ($tvakey != 0) { // On affiche pas taux 0
1380  //$this->atleastoneratenotnull++;
1381 
1382  $index++;
1383  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1384 
1385  $tvacompl = '';
1386  if (preg_match('/\*/', $tvakey)) {
1387  $tvakey = str_replace('*', '', $tvakey);
1388  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1389  }
1390 
1391  $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : '');
1392  $totalvat .= ' ';
1393  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1394  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1395 
1396  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1397  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1398  }
1399  }
1400  }
1401  //}
1402  //Local tax 2 before VAT
1403  //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1404  //{
1405  foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1406  if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1407  continue;
1408  }
1409 
1410  foreach ($localtax_rate as $tvakey => $tvaval) {
1411  if ($tvakey != 0) { // On affiche pas taux 0
1412  //$this->atleastoneratenotnull++;
1413 
1414  $index++;
1415  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1416 
1417  $tvacompl = '';
1418  if (preg_match('/\*/', $tvakey)) {
1419  $tvakey = str_replace('*', '', $tvakey);
1420  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1421  }
1422  $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : '');
1423  $totalvat .= ' ';
1424  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1425  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1426 
1427  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1428  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1429  }
1430  }
1431  }
1432 
1433  //}
1434 
1435  // VAT
1436  foreach ($this->tva_array as $tvakey => $tvaval) {
1437  if ($tvakey != 0) { // On affiche pas taux 0
1438  $this->atleastoneratenotnull++;
1439 
1440  $index++;
1441  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1442 
1443  $tvacompl = '';
1444  if (preg_match('/\*/', $tvakey)) {
1445  $tvakey = str_replace('*', '', $tvakey);
1446  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1447  }
1448  $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalVAT", $mysoc->country_code) : '');
1449  $totalvat .= ' ';
1450  if (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'rateonly') {
1451  $totalvat .= vatrate($tvaval['vatrate'], 1).$tvacompl;
1452  } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'codeonly') {
1453  $totalvat .= $tvaval['vatcode'].$tvacompl;
1454  } else {
1455  $totalvat .= vatrate($tvaval['vatrate'], 1).($tvaval['vatcode'] ? ' ('.$tvaval['vatcode'].')' : '').$tvacompl;
1456  }
1457  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1458 
1459  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1460  $pdf->MultiCell($largcol2, $tab2_hl, price(price2num($tvaval['amount'], 'MT'), 0, $outputlangs), 0, 'R', 1);
1461  }
1462  }
1463 
1464  //Local tax 1 after VAT
1465  //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1466  //{
1467  foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1468  if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1469  continue;
1470  }
1471 
1472  foreach ($localtax_rate as $tvakey => $tvaval) {
1473  if ($tvakey != 0) { // On affiche pas taux 0
1474  //$this->atleastoneratenotnull++;
1475 
1476  $index++;
1477  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1478 
1479  $tvacompl = '';
1480  if (preg_match('/\*/', $tvakey)) {
1481  $tvakey = str_replace('*', '', $tvakey);
1482  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1483  }
1484  $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).' ';
1485  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1486 
1487  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1488  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1489  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1490  }
1491  }
1492  }
1493  //}
1494  //Local tax 2 after VAT
1495  //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1496  //{
1497  foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1498  if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1499  continue;
1500  }
1501 
1502  foreach ($localtax_rate as $tvakey => $tvaval) {
1503  //$this->atleastoneratenotnull++;
1504 
1505  $index++;
1506  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1507 
1508  $tvacompl = '';
1509  if (preg_match('/\*/', $tvakey)) {
1510  $tvakey = str_replace('*', '', $tvakey);
1511  $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1512  }
1513  $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' ';
1514 
1515  $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1516  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1517 
1518  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1519  $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1520  }
1521  }
1522  //}
1523 
1524  // Revenue stamp
1525  if (price2num($object->revenuestamp) != 0) {
1526  $index++;
1527  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1528  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RevenueStamp"), $useborder, 'L', 1);
1529 
1530  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1531  $pdf->MultiCell($largcol2, $tab2_hl, price($sign * $object->revenuestamp), $useborder, 'R', 1);
1532  }
1533 
1534  // Total TTC
1535  $index++;
1536  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1537  $pdf->SetTextColor(0, 0, 60);
1538  $pdf->SetFillColor(224, 224, 224);
1539  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1);
1540 
1541  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1542  $pdf->MultiCell($largcol2, $tab2_hl, price($sign * $total_ttc, 0, $outputlangs), $useborder, 'R', 1);
1543 
1544  // Retained warranty
1545  if ($object->displayRetainedWarranty()) {
1546  $pdf->SetTextColor(40, 40, 40);
1547  $pdf->SetFillColor(255, 255, 255);
1548 
1549  $retainedWarranty = $object->getRetainedWarrantyAmount();
1550  $billedWithRetainedWarranty = $object->total_ttc - $retainedWarranty;
1551 
1552  // Billed - retained warranty
1553  $index++;
1554  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1555  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("ToPayOn", dol_print_date($object->date_lim_reglement, 'day')), $useborder, 'L', 1);
1556 
1557  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1558  $pdf->MultiCell($largcol2, $tab2_hl, price($billedWithRetainedWarranty), $useborder, 'R', 1);
1559 
1560  // retained warranty
1561  $index++;
1562  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1563 
1564  $retainedWarrantyToPayOn = $outputlangs->transnoentities("RetainedWarranty").' ('.$object->retained_warranty.'%)';
1565  $retainedWarrantyToPayOn .= !empty($object->retained_warranty_date_limit) ? ' '.$outputlangs->transnoentities("toPayOn", dol_print_date($object->retained_warranty_date_limit, 'day')) : '';
1566 
1567  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $retainedWarrantyToPayOn, $useborder, 'L', 1);
1568  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1569  $pdf->MultiCell($largcol2, $tab2_hl, price($retainedWarranty), $useborder, 'R', 1);
1570  }
1571  }
1572  }
1573 
1574  $pdf->SetTextColor(0, 0, 0);
1575  $creditnoteamount = $object->getSumCreditNotesUsed((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? 1 : 0); // Warning, this also include excess received
1576  $depositsamount = $object->getSumDepositsUsed((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? 1 : 0);
1577  //print "x".$creditnoteamount."-".$depositsamount;exit;
1578  $resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT');
1579  if (!empty($object->paye)) {
1580  $resteapayer = 0;
1581  }
1582 
1583  if (($deja_regle > 0 || $creditnoteamount > 0 || $depositsamount > 0) && empty($conf->global->INVOICE_NO_PAYMENT_DETAILS)) {
1584  // Already paid + Deposits
1585  $index++;
1586  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1587  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("Paid"), 0, 'L', 0);
1588  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1589  $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle + $depositsamount, 0, $outputlangs), 0, 'R', 0);
1590 
1591  // Credit note
1592  if ($creditnoteamount) {
1593  $labeltouse = ($outputlangs->transnoentities("CreditNotesOrExcessReceived") != "CreditNotesOrExcessReceived") ? $outputlangs->transnoentities("CreditNotesOrExcessReceived") : $outputlangs->transnoentities("CreditNotes");
1594  $index++;
1595  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1596  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $labeltouse, 0, 'L', 0);
1597  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1598  $pdf->MultiCell($largcol2, $tab2_hl, price($creditnoteamount, 0, $outputlangs), 0, 'R', 0);
1599  }
1600 
1601  // Escompte
1602  if ($object->close_code == Facture::CLOSECODE_DISCOUNTVAT) {
1603  $index++;
1604  $pdf->SetFillColor(255, 255, 255);
1605 
1606  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1607  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("EscompteOfferedShort"), $useborder, 'L', 1);
1608  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1609  $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 0, $outputlangs), $useborder, 'R', 1);
1610 
1611  $resteapayer = 0;
1612  }
1613 
1614  $index++;
1615  $pdf->SetTextColor(0, 0, 60);
1616  $pdf->SetFillColor(224, 224, 224);
1617  $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1618  $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1);
1619  $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1620  $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1);
1621 
1622  $pdf->SetFont('', '', $default_font_size - 1);
1623  $pdf->SetTextColor(0, 0, 0);
1624  }
1625 
1626  $index++;
1627  return ($tab2_top + ($tab2_hl * $index));
1628  }
1629 
1630  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1644  protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '')
1645  {
1646  global $conf;
1647 
1648  // Force to disable hidetop and hidebottom
1649  $hidebottom = 0;
1650  if ($hidetop) {
1651  $hidetop = -1;
1652  }
1653 
1654  $currency = !empty($currency) ? $currency : $conf->currency;
1655  $default_font_size = pdf_getPDFFontSize($outputlangs);
1656 
1657  // Amount in (at tab_top - 1)
1658  $pdf->SetTextColor(0, 0, 0);
1659  $pdf->SetFont('', '', $default_font_size - 2);
1660 
1661  if (empty($hidetop)) {
1662  $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
1663  $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
1664  $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
1665 
1666  //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
1667  if (!empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) {
1668  $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite - $this->marge_gauche, 5, 'F', null, explode(',', $conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR));
1669  }
1670  }
1671 
1672  $pdf->SetDrawColor(128, 128, 128);
1673  $pdf->SetFont('', '', $default_font_size - 1);
1674 
1675  // Output Rect
1676  $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
1677 
1678  if (empty($hidetop)) {
1679  $pdf->line($this->marge_gauche, $tab_top + 5, $this->page_largeur - $this->marge_droite, $tab_top + 5); // line takes a position y in 2nd parameter and 4th parameter
1680 
1681  $pdf->SetXY($this->posxdesc - 1, $tab_top + 1);
1682  $pdf->MultiCell(108, 2, $outputlangs->transnoentities("Designation"), '', 'L');
1683  }
1684 
1685  if (!empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE)) {
1686  $pdf->line($this->posxpicture - 1, $tab_top, $this->posxpicture - 1, $tab_top + $tab_height);
1687  if (empty($hidetop)) {
1688  //$pdf->SetXY($this->posxpicture-1, $tab_top+1);
1689  //$pdf->MultiCell($this->posxtva-$this->posxpicture-1,2, $outputlangs->transnoentities("Photo"),'','C');
1690  }
1691  }
1692 
1693  if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
1694  $pdf->line($this->posxtva - 1, $tab_top, $this->posxtva - 1, $tab_top + $tab_height);
1695  if (empty($hidetop)) {
1696  $pdf->SetXY($this->posxtva - 3, $tab_top + 1);
1697  $pdf->MultiCell($this->posxup - $this->posxtva + 3, 2, $outputlangs->transnoentities("VAT"), '', 'C');
1698  }
1699  }
1700 
1701  $pdf->line($this->posxup - 1, $tab_top, $this->posxup - 1, $tab_top + $tab_height);
1702  if (empty($hidetop)) {
1703  $pdf->SetXY($this->posxup - 1, $tab_top + 1);
1704  $pdf->MultiCell($this->posxqty - $this->posxup - 1, 2, $outputlangs->transnoentities("PriceUHT"), '', 'C');
1705  }
1706 
1707  $pdf->line($this->posxqty - 1, $tab_top, $this->posxqty - 1, $tab_top + $tab_height);
1708  if (empty($hidetop)) {
1709  $pdf->SetXY($this->posxqty - 1, $tab_top + 1);
1710  $pdf->MultiCell($this->posxunit - $this->posxqty - 1, 2, $outputlangs->transnoentities("Qty"), '', 'C');
1711  }
1712 
1713  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1714  $pdf->line($this->posxunit - 1, $tab_top, $this->posxunit - 1, $tab_top + $tab_height);
1715  if (empty($hidetop)) {
1716  $pdf->SetXY($this->posxunit - 1, $tab_top + 1);
1717  $pdf->MultiCell($this->posxdiscount - $this->posxunit - 1, 2, $outputlangs->transnoentities("Unit"), '', 'C');
1718  }
1719  }
1720 
1721  if ($this->atleastonediscount) {
1722  $pdf->line($this->posxdiscount - 1, $tab_top, $this->posxdiscount - 1, $tab_top + $tab_height);
1723  if (empty($hidetop)) {
1724  $pdf->SetXY($this->posxdiscount - 1, $tab_top + 1);
1725  $pdf->MultiCell($this->posxprogress - $this->posxdiscount + 1, 2, $outputlangs->transnoentities("ReductionShort"), '', 'C');
1726  }
1727  }
1728 
1729  if ($this->situationinvoice) {
1730  $pdf->line($this->posxprogress - 1, $tab_top, $this->posxprogress - 1, $tab_top + $tab_height);
1731  if (empty($hidetop)) {
1732  $pdf->SetXY($this->posxprogress, $tab_top + 1);
1733  $pdf->MultiCell($this->postotalht - $this->posxprogress, 2, $outputlangs->transnoentities("ProgressShort"), '', 'C');
1734  }
1735  }
1736 
1737  $pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height);
1738  if (empty($hidetop)) {
1739  $pdf->SetXY($this->postotalht - 1, $tab_top + 1);
1740  $pdf->MultiCell(30, 2, $outputlangs->transnoentities("TotalHT"), '', 'C');
1741  }
1742  }
1743 
1744  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1755  protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null)
1756  {
1757  global $conf, $langs;
1758 
1759  $ltrdirection = 'L';
1760  if ($outputlangs->trans("DIRECTION") == 'rtl') $ltrdirection = 'R';
1761 
1762  // Load traductions files required by page
1763  $outputlangs->loadLangs(array("main", "bills", "propal", "companies"));
1764 
1765  $default_font_size = pdf_getPDFFontSize($outputlangs);
1766 
1767  pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
1768 
1769  $pdf->SetTextColor(0, 0, 60);
1770  $pdf->SetFont('', 'B', $default_font_size + 3);
1771 
1772  $w = 110;
1773 
1774  $posy = $this->marge_haute;
1775  $posx = $this->page_largeur - $this->marge_droite - $w;
1776 
1777  $pdf->SetXY($this->marge_gauche, $posy);
1778 
1779  // Logo
1780  if (!getDolGlobalInt('PDF_DISABLE_MYCOMPANY_LOGO')) {
1781  if ($this->emetteur->logo) {
1782  $logodir = $conf->mycompany->dir_output;
1783  if (!empty($conf->mycompany->multidir_output[$object->entity])) {
1784  $logodir = $conf->mycompany->multidir_output[$object->entity];
1785  }
1786  if (!getDolGlobalInt('MAIN_PDF_USE_LARGE_LOGO')) {
1787  $logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
1788  } else {
1789  $logo = $logodir.'/logos/'.$this->emetteur->logo;
1790  }
1791  if (is_readable($logo)) {
1792  $height = pdf_getHeightForLogo($logo);
1793  $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
1794  } else {
1795  $pdf->SetTextColor(200, 0, 0);
1796  $pdf->SetFont('', 'B', $default_font_size - 2);
1797  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
1798  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
1799  }
1800  } else {
1801  $text = $this->emetteur->name;
1802  $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);
1803  }
1804  }
1805 
1806  $pdf->SetFont('', 'B', $default_font_size + 3);
1807  $pdf->SetXY($posx, $posy);
1808  $pdf->SetTextColor(0, 0, 60);
1809  $title = $outputlangs->transnoentities("PdfInvoiceTitle");
1810  if ($object->type == 1) {
1811  $title = $outputlangs->transnoentities("InvoiceReplacement");
1812  }
1813  if ($object->type == 2) {
1814  $title = $outputlangs->transnoentities("InvoiceAvoir");
1815  }
1816  if ($object->type == 3) {
1817  $title = $outputlangs->transnoentities("InvoiceDeposit");
1818  }
1819  if ($object->type == 4) {
1820  $title = $outputlangs->transnoentities("InvoiceProForma");
1821  }
1822  if ($this->situationinvoice) {
1823  $title = $outputlangs->transnoentities("PDFInvoiceSituation");
1824  }
1825  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {
1826  $title .= ' - ';
1827  if ($object->type == 0) {
1828  if ($this->situationinvoice) {
1829  $title .= $outputlangsbis->transnoentities("PDFInvoiceSituation");
1830  }
1831  $title .= $outputlangsbis->transnoentities("PdfInvoiceTitle");
1832  } elseif ($object->type == 1) {
1833  $title .= $outputlangsbis->transnoentities("InvoiceReplacement");
1834  } elseif ($object->type == 2) {
1835  $title .= $outputlangsbis->transnoentities("InvoiceAvoir");
1836  } elseif ($object->type == 3) {
1837  $title .= $outputlangsbis->transnoentities("InvoiceDeposit");
1838  } elseif ($object->type == 4) {
1839  $title .= $outputlangsbis->transnoentities("InvoiceProForma");
1840  }
1841  }
1842  $title .= ' '.$outputlangs->convToOutputCharset($object->ref);
1843  if ($object->statut == $object::STATUS_DRAFT) {
1844  $pdf->SetTextColor(128, 0, 0);
1845  $title .= ' - '.$outputlangs->transnoentities("NotValidated");
1846  }
1847 
1848  $pdf->MultiCell($w, 3, $title, '', 'R');
1849 
1850  $pdf->SetFont('', 'B', $default_font_size);
1851 
1852  /*
1853  $posy += 5;
1854  $pdf->SetXY($posx, $posy);
1855  $pdf->SetTextColor(0, 0, 60);
1856  $textref = $outputlangs->transnoentities("Ref")." : ".$outputlangs->convToOutputCharset($object->ref);
1857  if ($object->statut == $object::STATUS_DRAFT) {
1858  $pdf->SetTextColor(128, 0, 0);
1859  $textref .= ' - '.$outputlangs->transnoentities("NotValidated");
1860  }
1861  $pdf->MultiCell($w, 4, $textref, '', 'R');*/
1862 
1863  $posy += 3;
1864  $pdf->SetFont('', '', $default_font_size - 2);
1865 
1866  if ($object->ref_client) {
1867  $posy += 4;
1868  $pdf->SetXY($posx, $posy);
1869  $pdf->SetTextColor(0, 0, 60);
1870  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R');
1871  }
1872 
1873  if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) {
1874  $object->fetch_projet();
1875  if (!empty($object->project->ref)) {
1876  $posy += 3;
1877  $pdf->SetXY($posx, $posy);
1878  $pdf->SetTextColor(0, 0, 60);
1879  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->project->title), '', 'R');
1880  }
1881  }
1882 
1883  if (!empty($conf->global->PDF_SHOW_PROJECT)) {
1884  $object->fetch_projet();
1885  if (!empty($object->project->ref)) {
1886  $outputlangs->load("projects");
1887  $posy += 3;
1888  $pdf->SetXY($posx, $posy);
1889  $pdf->SetTextColor(0, 0, 60);
1890  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefProject")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R');
1891  }
1892  }
1893 
1894  $objectidnext = $object->getIdReplacingInvoice('validated');
1895  if ($object->type == 0 && $objectidnext) {
1896  $objectreplacing = new Facture($this->db);
1897  $objectreplacing->fetch($objectidnext);
1898 
1899  $posy += 3;
1900  $pdf->SetXY($posx, $posy);
1901  $pdf->SetTextColor(0, 0, 60);
1902  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ReplacementByInvoice").' : '.$outputlangs->convToOutputCharset($objectreplacing->ref), '', 'R');
1903  }
1904  if ($object->type == 1) {
1905  $objectreplaced = new Facture($this->db);
1906  $objectreplaced->fetch($object->fk_facture_source);
1907 
1908  $posy += 4;
1909  $pdf->SetXY($posx, $posy);
1910  $pdf->SetTextColor(0, 0, 60);
1911  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ReplacementInvoice").' : '.$outputlangs->convToOutputCharset($objectreplaced->ref), '', 'R');
1912  }
1913  if ($object->type == 2 && !empty($object->fk_facture_source)) {
1914  $objectreplaced = new Facture($this->db);
1915  $objectreplaced->fetch($object->fk_facture_source);
1916 
1917  $posy += 3;
1918  $pdf->SetXY($posx, $posy);
1919  $pdf->SetTextColor(0, 0, 60);
1920  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CorrectionInvoice").' : '.$outputlangs->convToOutputCharset($objectreplaced->ref), '', 'R');
1921  }
1922 
1923  $posy += 4;
1924  $pdf->SetXY($posx, $posy);
1925  $pdf->SetTextColor(0, 0, 60);
1926  $title = $outputlangs->transnoentities("DateInvoice");
1927  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {
1928  $title .= ' - '.$outputlangsbis->transnoentities("DateInvoice");
1929  }
1930  $pdf->MultiCell($w, 3, $title." : ".dol_print_date($object->date, "day", false, $outputlangs, true), '', 'R');
1931 
1932  if (!empty($conf->global->INVOICE_POINTOFTAX_DATE)) {
1933  $posy += 4;
1934  $pdf->SetXY($posx, $posy);
1935  $pdf->SetTextColor(0, 0, 60);
1936  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("DatePointOfTax")." : ".dol_print_date($object->date_pointoftax, "day", false, $outputlangs), '', 'R');
1937  }
1938 
1939  if ($object->type != 2) {
1940  $posy += 3;
1941  $pdf->SetXY($posx, $posy);
1942  $pdf->SetTextColor(0, 0, 60);
1943  $title = $outputlangs->transnoentities("DateDue");
1944  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {
1945  $title .= ' - '.$outputlangsbis->transnoentities("DateDue");
1946  }
1947  $pdf->MultiCell($w, 3, $title." : ".dol_print_date($object->date_lim_reglement, "day", false, $outputlangs, true), '', 'R');
1948  }
1949 
1950  if (empty($conf->global->MAIN_PDF_HIDE_CUSTOMER_CODE) && $object->thirdparty->code_client) {
1951  $posy += 3;
1952  $pdf->SetXY($posx, $posy);
1953  $pdf->SetTextColor(0, 0, 60);
1954  $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R');
1955  }
1956 
1957  // Get contact
1958  if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) {
1959  $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1960  if (count($arrayidcontact) > 0) {
1961  $usertmp = new User($this->db);
1962  $usertmp->fetch($arrayidcontact[0]);
1963  $posy += 4;
1964  $pdf->SetXY($posx, $posy);
1965  $pdf->SetTextColor(0, 0, 60);
1966  $pdf->MultiCell($w, 3, $langs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
1967  }
1968  }
1969 
1970  $posy += 1;
1971 
1972  $top_shift = 0;
1973  // Show list of linked objects
1974  $current_y = $pdf->getY();
1975  $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size);
1976  if ($current_y < $pdf->getY()) {
1977  $top_shift = $pdf->getY() - $current_y;
1978  }
1979 
1980  if ($showaddress) {
1981  // Sender properties
1982  $carac_emetteur = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
1983 
1984  // Show sender
1985  $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42;
1986  $posy += $top_shift;
1987  $posx = $this->marge_gauche;
1988  if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1989  $posx = $this->page_largeur - $this->marge_droite - 80;
1990  }
1991 
1992  $hautcadre = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 38 : 40;
1993  $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 82;
1994 
1995 
1996  // Show sender frame
1997  if (empty($conf->global->MAIN_PDF_NO_SENDER_FRAME)) {
1998  $pdf->SetTextColor(0, 0, 0);
1999  $pdf->SetFont('', '', $default_font_size - 2);
2000  $pdf->SetXY($posx, $posy - 5);
2001  $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillFrom"), 0, $ltrdirection);
2002  $pdf->SetXY($posx, $posy);
2003  $pdf->SetFillColor(230, 230, 230);
2004  $pdf->MultiCell($widthrecbox, $hautcadre, "", 0, 'R', 1);
2005  $pdf->SetTextColor(0, 0, 60);
2006  }
2007 
2008  // Show sender name
2009  if (empty($conf->global->MAIN_PDF_HIDE_SENDER_NAME)) {
2010  $pdf->SetXY($posx + 2, $posy + 3);
2011  $pdf->SetFont('', 'B', $default_font_size);
2012  $pdf->MultiCell($widthrecbox - 2, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, $ltrdirection);
2013  $posy = $pdf->getY();
2014  }
2015 
2016  // Show sender information
2017  $pdf->SetXY($posx + 2, $posy);
2018  $pdf->SetFont('', '', $default_font_size - 1);
2019  $pdf->MultiCell($widthrecbox - 2, 4, $carac_emetteur, 0, $ltrdirection);
2020 
2021 
2022  // If BILLING contact defined on invoice, we use it
2023  $usecontact = false;
2024  $arrayidcontact = $object->getIdContact('external', 'BILLING');
2025  if (count($arrayidcontact) > 0) {
2026  $usecontact = true;
2027  $result = $object->fetch_contact($arrayidcontact[0]);
2028  }
2029 
2030  // Recipient name
2031  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)))) {
2032  $thirdparty = $object->contact;
2033  } else {
2034  $thirdparty = $object->thirdparty;
2035  }
2036 
2037  $carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);
2038 
2039  $mode = 'target';
2040  $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), $usecontact, $mode, $object);
2041 
2042  // Show recipient
2043  $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100;
2044  if ($this->page_largeur < 210) {
2045  $widthrecbox = 84; // To work with US executive format
2046  }
2047  $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42;
2048  $posy += $top_shift;
2049  $posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
2050  if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
2051  $posx = $this->marge_gauche;
2052  }
2053 
2054  // Show recipient frame
2055  if (empty($conf->global->MAIN_PDF_NO_RECIPENT_FRAME)) {
2056  $pdf->SetTextColor(0, 0, 0);
2057  $pdf->SetFont('', '', $default_font_size - 2);
2058  $pdf->SetXY($posx + 2, $posy - 5);
2059  $pdf->MultiCell($widthrecbox - 2, 5, $outputlangs->transnoentities("BillTo"), 0, $ltrdirection);
2060  $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
2061  }
2062 
2063  // Show recipient name
2064  $pdf->SetXY($posx + 2, $posy + 3);
2065  $pdf->SetFont('', 'B', $default_font_size);
2066  $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_name, 0, $ltrdirection);
2067 
2068  $posy = $pdf->getY();
2069 
2070  // Show recipient information
2071  $pdf->SetFont('', '', $default_font_size - 1);
2072  $pdf->SetXY($posx + 2, $posy);
2073  $pdf->MultiCell($widthrecbox - 2, 4, $carac_client, 0, $ltrdirection);
2074 
2075  // Show shipping address
2076  if (getDolGlobalInt('INVOICE_SHOW_SHIPPING_ADDRESS')) {
2077  $idaddressshipping = $object->getIdContact('external', 'SHIPPING');
2078 
2079  if (!empty($idaddressshipping)) {
2080  $contactshipping = $object->fetch_Contact($idaddressshipping[0]);
2081  $object->fetch_thirdparty($object->contact->fk_soc);
2082  $carac_client_name_shipping=pdfBuildThirdpartyName($object->contact, $outputlangs);
2083  $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, $object->contact, $usecontact, 'target', $object);
2084  } else {
2085  $carac_client_name_shipping=pdfBuildThirdpartyName($object->thirdparty, $outputlangs);
2086  $carac_client_shipping=pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'target', $object);
2087  }
2088  if (!empty($carac_client_shipping) && (isset($object->contact->socid) && $object->contact->socid != $object->socid)) {
2089  $posy += $hautcadre;
2090 
2091  // Show shipping frame
2092  $pdf->SetXY($posx + 2, $posy - 5);
2093  $pdf->SetFont('', '', $default_font_size - 2);
2094  $pdf->MultiCell($widthrecbox, '', $langs->trans('ShippingTo'), 0, 'L', 0);
2095  $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
2096 
2097  // Show shipping name
2098  $pdf->SetXY($posx + 2, $posy + 3);
2099  $pdf->SetFont('', 'B', $default_font_size);
2100  $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_name_shipping, '', 'L');
2101 
2102  $posy = $pdf->getY();
2103 
2104  // Show shipping information
2105  $pdf->SetXY($posx+2, $posy);
2106  $pdf->SetFont('', '', $default_font_size - 1);
2107  $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_shipping, '', 'L');
2108  $top_shift += $hautcadre;
2109  }
2110  }
2111  }
2112 
2113  $pdf->SetTextColor(0, 0, 0);
2114  return $top_shift;
2115  }
2116 
2117  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
2127  protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
2128  {
2129  $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0);
2130  return pdf_pagefoot($pdf, $outputlangs, 'INVOICE_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext, $this->page_largeur, $this->watermark);
2131  }
2132 }
Class to manage bank accounts.
printRect($pdf, $x, $y, $l, $h, $hidetop=0, $hidebottom=0)
Rect pdf.
Class to manage bank accounts description of third parties.
Class to manage invoices.
const STATUS_DRAFT
Draft status.
Class to manage hooks.
Parent class of invoice document generators.
Class to manage products or services.
Class to manage translations.
Class to manage Dolibarr users.
Definition: user.class.php:45
Class to generate the customer invoice PDF with template Crabe.
__construct($db)
Constructor.
_pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis=null)
Show top header of page.
_tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='')
Show table for lines.
_tableau_versements(&$pdf, $object, $posy, $outputlangs, $heightforfooter=0)
Show payments table.
_pagefoot(&$pdf, $object, $outputlangs, $hidefreetext=0)
Show footer of page.
_tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlangsbis)
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_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top, $tab3_width, $tab3_height)
Function _tableau_versements_header.
_tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis)
Show total to pay.
getCountry($searchkey, $withcode='', $dbtouse=0, $outputlangs='', $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:745
print *****$script_file(".$version.") pid cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
if(!function_exists('dolEscapeXML')) convertBackOfficeMediasLinksToPublicLinks($notetoshow)
Convert links to local wrapper to medias files into a string into a public external URL readable on i...
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
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_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
pdf_getSizeForImage($realpath)
Return dimensions to use for images onto PDF checking that width and height are not higher than maxim...
Definition: pdf.lib.php: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_writelinedesc(&$pdf, $object, $i, $outputlangs, $w, $h, $posx, $posy, $hideref=0, $hidedesc=0, $issupplierline=0)
Output line description into PDF.
Definition: pdf.lib.php:1354
pdf_getHeightForLogo($logo, $url=false)
Return height to use for Logo onto PDF.
Definition: pdf.lib.php:313
pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_basse, $marge_gauche, $page_hauteur, $object, $showdetails=0, $hidefreetext=0, $page_largeur=0, $watermark='')
Show footer of page for PDF generation.
Definition: pdf.lib.php:996
pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line unit price excluding tax.
Definition: pdf.lib.php:1877
pdf_getlineprogress($object, $i, $outputlangs, $hidedetails=0, $hookmanager=null)
Return line percent.
Definition: pdf.lib.php:2209
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