dolibarr 25.0.0-alpha
pdf_eratosthene.modules.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2004-2014 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2008 Raphael Bertrand <raphael.bertrand@resultic.fr>
5 * Copyright (C) 2010-2013 Juanjo Menent <jmenent@2byte.es>
6 * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
7 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
8 * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
9 * Copyright (C) 2017 Ferran Marcet <fmarcet@2byte.es>
10 * Copyright (C) 2021-2024 Anthony Berton <anthony.berton@bb2a.fr>
11 * Copyright (C) 2018-2026 Frédéric France <frederic.france@free.fr>
12 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
13 * Copyright (C) 2024 Nick Fragoulis
14 * Copyright (C) 2024 Joachim Kueter <git-jk@bloxera.com>
15 * Copyright (C) 2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <https://www.gnu.org/licenses/>.
29 * or see https://www.gnu.org/
30 */
31
38require_once DOL_DOCUMENT_ROOT.'/core/modules/commande/modules_commande.php';
39require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
40require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
41require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
42require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
43
48{
52 public $db;
53
57 public $entity;
58
62 public $name;
63
67 public $description;
68
72 public $update_main_doc_field;
73
77 public $type;
78
83 public $version = 'dolibarr';
84
88 public $cols;
89
90
96 public function __construct(DoliDB $db)
97 {
98 global $conf, $langs, $mysoc;
99
100 // Translations
101 $langs->loadLangs(array("main", "bills", "products"));
102
103 $this->db = $db;
104 $this->name = "eratosthene";
105 $this->description = $langs->trans('PDFEratostheneDescription');
106 $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template
107
108 // Dimension page
109 $this->type = 'pdf';
110 $formatarray = pdf_getFormat();
111 $this->page_largeur = $formatarray['width'];
112 $this->page_hauteur = $formatarray['height'];
113 $this->format = array($this->page_largeur, $this->page_hauteur);
114 $this->marge_gauche = getDolGlobalInt('MAIN_PDF_MARGIN_LEFT', 10);
115 $this->marge_droite = getDolGlobalInt('MAIN_PDF_MARGIN_RIGHT', 10);
116 $this->marge_haute = getDolGlobalInt('MAIN_PDF_MARGIN_TOP', 10);
117 $this->marge_basse = getDolGlobalInt('MAIN_PDF_MARGIN_BOTTOM', 10);
118 $this->corner_radius = getDolGlobalInt('MAIN_PDF_FRAME_CORNER_RADIUS', 0);
119 $this->option_logo = 1; // Display logo
120 $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION
121 $this->option_modereg = 1; // Display payment mode
122 $this->option_condreg = 1; // Display payment terms
123 $this->option_multilang = 1; // Available in several languages
124 $this->option_escompte = 0; // Displays if there has been a discount
125 $this->option_credit_note = 0; // Support credit notes
126 $this->option_freetext = 1; // Support add of a personalised text
127 $this->option_draft_watermark = 1; // Support add of a watermark on drafts
128 $this->watermark = '';
129
130 $this->showAmountBeforeDiscount = getDolGlobalInt('MAIN_HIDE_AMOUNT_BEFORE_DISCOUNT') || getDolGlobalInt('MAIN_HIDE_AMOUNT_BEFORE_DISCOUNT_ORDER') ? 0 : 1;
131 $this->showDiscountAmount = getDolGlobalInt('MAIN_HIDE_AMOUNT_DISCOUNT') || getDolGlobalInt('MAIN_HIDE_AMOUNT_BEFORE_DISCOUNT_ORDER') ? 0 : 1;
132
133
134 if ($mysoc === null) {
135 dol_syslog(get_class($this).'::__construct() Global $mysoc should not be null.'. getCallerInfoString(), LOG_ERR);
136 return;
137 }
138
139 // Get source company
140 $this->emetteur = $mysoc;
141 if (empty($this->emetteur->country_code)) {
142 $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined
143 }
144
145 // Define position of columns
146 $this->posxdesc = $this->marge_gauche + 1; // used for notes and other stuff
147
148
149 $this->tabTitleHeight = 5; // default height
150
151 // Use new system for position of columns, view $this->defineColumnField()
152
153 $this->tva = array();
154 $this->tva_array = array();
155 $this->localtax1 = array();
156 $this->localtax2 = array();
157 $this->atleastoneratenotnull = 0;
158 $this->atleastonediscount = 0;
159 }
160
161 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
173 public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
174 {
175 // phpcs:enable
176 global $user, $langs, $conf, $mysoc, $db, $hookmanager, $nblines;
177
178 dol_syslog("write_file outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null'));
179
180 if (!is_object($outputlangs)) {
181 $outputlangs = $langs;
182 }
183 // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
184 if (getDolGlobalInt('MAIN_USE_FPDF')) {
185 $outputlangs->charset_output = 'ISO-8859-1';
186 }
187
188 // Load translation files required by the page
189 $outputlangs->loadLangs(array("main", "dict", "companies", "bills", "products", "orders", "sendginds", "compta"));
190
191 // Show Draft Watermark
192 if ($object->statut == $object::STATUS_DRAFT && getDolGlobalString('COMMANDE_DRAFT_WATERMARK')) {
193 $this->watermark = getDolGlobalString('COMMANDE_DRAFT_WATERMARK');
194 }
195
196 global $outputlangsbis;
197 $outputlangsbis = null;
198 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE') && $outputlangs->defaultlang != getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
199 $outputlangsbis = new Translate('', $conf);
200 $outputlangsbis->setDefaultLang(getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE'));
201 $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "orders", "sendginds", "compta"));
202 }
203
204 $nblines = (is_array($object->lines) ? count($object->lines) : 0);
205
206 $hidetop = getDolGlobalInt('MAIN_PDF_DISABLE_COL_HEAD_TITLE');
207
208 // Loop on each lines to detect if there is at least one image to show
209 $realpatharray = array();
210 $this->atleastonephoto = false;
211 if (getDolGlobalInt('MAIN_GENERATE_ORDERS_WITH_PICTURE')) {
212 $objphoto = new Product($this->db);
213
214 for ($i = 0; $i < $nblines; $i++) {
215 if (empty($object->lines[$i]->fk_product)) {
216 continue;
217 }
218
219 $pdir = array();
220
221 $objphoto->fetch($object->lines[$i]->fk_product);
222 //var_dump($objphoto->ref);exit;
223 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
224 $pdir[0] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/";
225 $pdir[1] = get_exdir(0, 0, 0, 0, $objphoto, 'product').dol_sanitizeFileName($objphoto->ref).'/';
226 } else {
227 $pdir[0] = get_exdir(0, 0, 0, 0, $objphoto, 'product'); // default
228 $pdir[1] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/"; // alternative
229 }
230
231 $arephoto = false;
232 $realpath = null;
233 foreach ($pdir as $midir) {
234 if (!$arephoto) {
235 $entity = $objphoto->entity;
236 if ($entity !== null && $conf->entity != $entity) {
237 $dir = $conf->product->multidir_output[$entity].'/'.$midir; //Check repertories of current entities
238 } else {
239 $dir = $conf->product->dir_output.'/'.$midir; //Check repertory of the current product
240 }
241
242 foreach ($objphoto->liste_photos($dir, 1) as $key => $obj) {
243 if (!getDolGlobalInt('CAT_HIGH_QUALITY_IMAGES')) { // If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo
244 if ($obj['photo_vignette']) {
245 $filename = $obj['photo_vignette'];
246 } else {
247 $filename = $obj['photo'];
248 }
249 } else {
250 $filename = $obj['photo'];
251 }
252
253 $realpath = $dir.$filename;
254 $arephoto = true;
255 $this->atleastonephoto = true;
256 }
257 }
258 }
259
260 if ($realpath && $arephoto) {
261 $realpatharray[$i] = $realpath;
262 }
263 }
264 }
265
266
267
269 $object->fetch_thirdparty();
270
271 $deja_regle = 0;
272
273 // Definition of $dir and $file
274 if ($object->specimen) {
276 $file = $dir."/SPECIMEN.pdf";
277 } else {
278 $objectref = dol_sanitizeFileName($object->ref);
279 $dir = getMultidirOutput($object)."/".$objectref;
280 $file = $dir."/".$objectref.".pdf";
281 }
282
283 if ($dir === null) {
284 dol_syslog(get_class($this).'::'.__METHOD__."Target directory should not be null.". getCallerInfoString(), LOG_ERR);
285 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", "Null dir");
286 return 0;
287 }
288
289 if (!file_exists($dir)) {
290 if (dol_mkdir($dir) < 0) {
291 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
292 return 0;
293 }
294 }
295
296 if (file_exists($dir)) {
297 // Add pdfgeneration hook
298 if (!is_object($hookmanager)) {
299 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
300 $hookmanager = new HookManager($this->db);
301 }
302 $hookmanager->initHooks(array('pdfgeneration'));
303 $parameters = array('file' => $file, 'object' => $object, 'outputlangs' => $outputlangs);
304 global $action;
305 $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
306
307 // Set nblines with the new lines content after hook
308 $nblines = (is_array($object->lines) ? count($object->lines) : 0);
309
310 // Create pdf instance
311 $pdf = pdf_getInstance($this->format);
312 $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
313 $pdf->setAutoPageBreak(true, 0);
314
315 $heightforinfotot = 40; // Height reserved to output the info and total part
316 $heightforfreetext = getDolGlobalInt('MAIN_PDF_FREETEXT_HEIGHT', 5); // Height reserved to output the free text on last page
317 $heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin)
318 if (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS')) {
319 $heightforfooter += 6;
320 }
321
322 if (class_exists('TCPDF')) {
323 $pdf->setPrintHeader(false);
324 $pdf->setPrintFooter(false);
325 }
326 $pdf->SetFont(pdf_getPDFFont($outputlangs));
327 // Set path to the background PDF File
328 if (getDolGlobalString('MAIN_ADD_PDF_BACKGROUND')) {
329 $logodir = $conf->mycompany->dir_output;
330 if (!empty($conf->mycompany->multidir_output[$object->entity ?? $conf->entity])) {
331 $logodir = $conf->mycompany->multidir_output[$object->entity ?? $conf->entity];
332 }
333 $pagecount = $pdf->setSourceFile($logodir.'/'.getDolGlobalString('MAIN_ADD_PDF_BACKGROUND'));
334 $tplidx = $pdf->importPage(1);
335 }
336
337 $pdf->Open();
338 $pagenb = 0;
339 $pdf->SetDrawColor(128, 128, 128);
340
341 $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
342 $pdf->SetSubject($outputlangs->transnoentities("PdfOrderTitle"));
343 $pdf->SetCreator("Dolibarr ".DOL_VERSION);
344 $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getAnonymisableFullName($outputlangs)));
345 $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfOrderTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
346 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
347 $pdf->SetCompression(false);
348 }
349
350 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
351 $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
352
353 // Set $this->atleastonediscount if you have at least one discount
354 for ($i = 0; $i < $nblines; $i++) {
355 if ($object->lines[$i]->remise_percent) {
356 $this->atleastonediscount++;
357 }
358 }
359
360
361 // New page
362 $pdf->AddPage();
363 if (!empty($tplidx)) {
364 $pdf->useTemplate($tplidx);
365 }
366 $pagenb++;
367 $pagehead = $this->_pagehead($pdf, $object, 1, $outputlangs, (is_object($outputlangsbis) ? $outputlangsbis : null));
368 $top_shift = $pagehead['top_shift'];
369 $shipp_shift = $pagehead['shipp_shift'];
370 $pdf->SetFont('', '', $default_font_size - 1);
371 $pdf->MultiCell(0, 3, ''); // Set interline to 3
372 $pdf->SetTextColor(0, 0, 0);
373
374
375 $tab_top = 80 + $this->marge_haute + $top_shift + $shipp_shift;
376 $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? $this->marge_haute + 32 + $top_shift : $this->marge_haute);
377 if (!$hidetop && getDolGlobalInt('MAIN_PDF_ENABLE_COL_HEAD_TITLE_REPEAT')) {
378 // TODO : make this hidden conf the default behavior for each PDF when each PDF managed this new Display
379 $tab_top_newpage += $this->tabTitleHeight;
380 }
381
382 $tab_height = $this->page_hauteur - $tab_top - $heightforfooter - $heightforfreetext;
383
384 $nexY = $tab_top - 1;
385
386 // Incoterm
387 $height_incoterms = 0;
388 if (isModEnabled('incoterm')) {
389 $desc_incoterms = $object->getIncotermsForPDF();
390 if ($desc_incoterms) {
391 $tab_top -= 2;
392
393 $pdf->SetFont('', '', $default_font_size - 1);
394 $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($desc_incoterms), 0, 1);
395 $nexY = max($pdf->GetY(), $nexY);
396 $height_incoterms = $nexY - $tab_top;
397
398 // Rect takes a length in 3rd parameter
399 $pdf->SetDrawColor(192, 192, 192);
400 $pdf->RoundedRect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_incoterms + 3, $this->corner_radius, '1234', 'D');
401
402 $tab_top = $nexY + 6;
403 }
404 }
405
406 // Display notes
407 $notetoshow = empty($object->note_public) ? '' : $object->note_public;
408 if (getDolGlobalString('MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE')) {
409 // Get first sale rep
410 if (is_object($object->thirdparty)) {
411 $salereparray = $object->thirdparty->getSalesRepresentatives($user);
412 $salerepobj = new User($this->db);
413 $salerepobj->fetch($salereparray[0]['id']);
414 if (!empty($salerepobj->signature)) {
415 $notetoshow = dol_concatdesc($notetoshow, $salerepobj->signature);
416 }
417 }
418 }
419 // Extrafields in note
420 $extranote = $this->getExtrafieldsInHtml($object, $outputlangs);
421 if (!empty($extranote)) {
422 $notetoshow = dol_concatdesc((string) $notetoshow, $extranote);
423 }
424
425 $pagenb = $pdf->getPage();
426 if ($notetoshow) {
427 $tab_top -= 2;
428
429 $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite;
430 $pageposbeforenote = $pagenb;
431
432 $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
433 complete_substitutions_array($substitutionarray, $outputlangs, $object);
434 $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
435 $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);
436
437 $pdf->startTransaction();
438
439 $pdf->SetFont('', '', $default_font_size - 1);
440 $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
441 // Description
442 $pageposafternote = $pdf->getPage();
443 $posyafter = $pdf->GetY();
444
445 if ($pageposafternote > $pageposbeforenote) {
446 $pdf->rollbackTransaction(true);
447
448 // prepare pages to receive notes
449 while ($pagenb < $pageposafternote) {
450 $pdf->AddPage();
451 $pagenb++;
452 if (!empty($tplidx)) {
453 $pdf->useTemplate($tplidx);
454 }
455 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
456 $this->_pagehead($pdf, $object, 0, $outputlangs);
457 }
458 // $this->_pagefoot($pdf,$object,$outputlangs,1);
459 $pdf->setTopMargin($tab_top_newpage);
460 // The only function to edit the bottom margin of current page to set it.
461 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext);
462 }
463
464 // back to start
465 $pdf->setPage($pageposbeforenote);
466 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext);
467 $pdf->SetFont('', '', $default_font_size - 1);
468 $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
469 $pageposafternote = $pdf->getPage();
470
471 $posyafter = $pdf->GetY();
472
473 if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) { // There is no space left for total+free text
474 $pdf->AddPage('', '', true);
475 $pagenb++;
476 $pageposafternote++;
477 $pdf->setPage($pageposafternote);
478 $pdf->setTopMargin($tab_top_newpage);
479 // The only function to edit the bottom margin of current page to set it.
480 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext);
481 //$posyafter = $tab_top_newpage;
482 }
483
484
485 // apply note frame to previous pages
486 $i = $pageposbeforenote;
487 while ($i < $pageposafternote) {
488 $pdf->setPage($i);
489
490
491 $pdf->SetDrawColor(128, 128, 128);
492 // Draw note frame
493 if ($i > $pageposbeforenote) {
494 $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter);
495 $pdf->RoundedRect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1, $this->corner_radius, '1234', 'D');
496 } else {
497 $height_note = $this->page_hauteur - ($tab_top + $heightforfooter);
498 $pdf->RoundedRect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1, $this->corner_radius, '1234', 'D');
499 }
500
501 // Add footer
502 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
503 $this->_pagefoot($pdf, $object, $outputlangs, 1);
504
505 $i++;
506 }
507
508 // apply note frame to last page
509 $pdf->setPage($pageposafternote);
510 if (!empty($tplidx)) {
511 $pdf->useTemplate($tplidx);
512 }
513 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
514 $this->_pagehead($pdf, $object, 0, $outputlangs);
515 }
516 $height_note = $posyafter - $tab_top_newpage;
517 $pdf->RoundedRect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1, $this->corner_radius, '1234', 'D');
518 } else {
519 // No pagebreak
520 $pdf->commitTransaction();
521 $posyafter = $pdf->GetY();
522 $height_note = $posyafter - $tab_top;
523 $pdf->RoundedRect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1, $this->corner_radius, '1234', 'D');
524
525
526 if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) {
527 // not enough space, need to add page
528 $pdf->AddPage('', '', true);
529 $pagenb++;
530 $pageposafternote++;
531 $pdf->setPage($pageposafternote);
532 if (!empty($tplidx)) {
533 $pdf->useTemplate($tplidx);
534 }
535 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
536 $this->_pagehead($pdf, $object, 0, $outputlangs);
537 }
538
539 $posyafter = $tab_top_newpage;
540 }
541 }
542
543 $tab_height -= $height_note;
544 $tab_top = $posyafter + 6;
545 } else {
546 $height_note = 0;
547 }
548
549
550 // Use new auto column system
551 $this->prepareArrayColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref);
552
553 // Table simulation to know the height of the title line
554 $pdf->startTransaction();
555 $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop);
556 $pdf->rollbackTransaction(true);
557
558 $nexY = $tab_top + $this->tabTitleHeight;
559
560 // Loop on each lines
561 $pageposbeforeprintlines = $pdf->getPage();
562 $pagenb = $pageposbeforeprintlines;
563
564 $pdf_sub_options = array();
565 $pdf_sub_options['titleshowuponpdf'] = 1;
566 $pdf_sub_options['titleshowtotalexludingvatonpdf'] = 1;
567
568 $hidenextline = 0;
569
570 for ($i = 0; $i < $nblines; $i++) {
571 $linePosition = $i + 1;
572 $curY = $nexY;
573
574 $sub_options = $object->lines[$i]->extraparams["subtotal"] ?? array();
575
576 if ($object->lines[$i]->special_code == SUBTOTALS_SPECIAL_CODE) {
577 $level = $object->lines[$i]->qty;
578 if ($sub_options) {
579 $hidenextline = 0;
580 if (isset($sub_options['titleshowuponpdf'])) {
581 $pdf_sub_options['titleshowuponpdf'] = isset($pdf_sub_options['titleshowuponpdf']) && $pdf_sub_options['titleshowuponpdf'] < $level ? $pdf_sub_options['titleshowuponpdf'] : $level;
582 } elseif (isset($pdf_sub_options['titleshowuponpdf']) && abs($level) <= $pdf_sub_options['titleshowuponpdf']) {
583 unset($pdf_sub_options['titleshowuponpdf']);
584 }
585 if (isset($sub_options['titleshowtotalexludingvatonpdf'])) {
586 $pdf_sub_options['titleshowtotalexludingvatonpdf'] = isset($pdf_sub_options['titleshowtotalexludingvatonpdf']) && $pdf_sub_options['titleshowtotalexludingvatonpdf'] < $level ? $pdf_sub_options['titleshowtotalexludingvatonpdf'] : $level;
587 } elseif (isset($pdf_sub_options['titleshowtotalexludingvatonpdf']) && abs($level) <= $pdf_sub_options['titleshowtotalexludingvatonpdf']) {
588 unset($pdf_sub_options['titleshowtotalexludingvatonpdf']);
589 }
590 } else {
591 if (isset($pdf_sub_options['titleshowuponpdf']) && abs($level) <= $pdf_sub_options['titleshowuponpdf']) {
592 unset($pdf_sub_options['titleshowuponpdf']);
593 }
594 if (isset($pdf_sub_options['titleshowtotalexludingvatonpdf']) && abs($level) <= $pdf_sub_options['titleshowtotalexludingvatonpdf']) {
595 unset($pdf_sub_options['titleshowtotalexludingvatonpdf']);
596 }
597 }
598 }
599
600 if ($object->lines[$i]->special_code == SUBTOTALS_SPECIAL_CODE && isset($sub_options['subtotalshowtotalexludingvatonpdf']) && getDolGlobalString('SUBTOTAL_HIDE_LINES_UNDER_TITLE')) { // TODO Use $sub_options['titlehidelinesundertitle'] instead of SUBTOTAL_HIDE_LINES_UNDER_TITLE
601 $hidenextline = 0;
602 $pdf_sub_options = array();
603 $pdf_sub_options['titleshowuponpdf'] = 1;
604 $pdf_sub_options['titleshowtotalexludingvatonpdf'] = 1;
605 }
606
607 //var_dump($i, $sub_options, $hidenextline);
608 if ($hidenextline) {
609 $linePosition--;
610 } else {
611 if (($curY + 6) > ($this->page_hauteur - $heightforfooter) || isset($sub_options['titleforcepagebreak']) && !($pdf->getNumPages() == 1 && $curY == $tab_top + $this->tabTitleHeight)) {
612 $object->lines[$i]->pagebreak = true;
613 }
614
615 // in First Check line page break and add page if needed
616 if (isset($object->lines[$i]->pagebreak) && $object->lines[$i]->pagebreak) {
617 // New page
618 $pdf->AddPage();
619 if (!empty($tplidx)) {
620 $pdf->useTemplate($tplidx);
621 }
622
623 $pdf->setPage($pdf->getNumPages());
624 $nexY = $curY = $tab_top_newpage;
625 }
626
627 $this->resetAfterColsLinePositionsData($nexY, $pdf->getPage());
628
629
630 $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
631 $pdf->SetTextColor(0, 0, 0);
632
633 // Define size of image if we need it
634 $imglinesize = array();
635 if (!empty($realpatharray[$i])) {
636 $imglinesize = pdf_getSizeForImage($realpatharray[$i]);
637 }
638
639 $pdf->setTopMargin($tab_top_newpage);
640 $pdf->setPageOrientation('', true, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
641 $pageposbefore = $pdf->getPage();
642 $curYBefore = $curY;
643
644 // Allows data in the first page if description is long enough to break in multiples pages
645 $showpricebeforepagebreak = getDolGlobalInt('MAIN_PDF_DATA_ON_FIRST_PAGE');
646 $posYAfterImage = 0;
647
648 if ($this->getColumnStatus('photo')) {
649 // We start with Photo of product line
650 $imageTopMargin = 1;
651 if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imageTopMargin + $imglinesize['height']) > ($this->page_hauteur - $heightforfooter)) { // If photo too high, we moved completely on new page
652 $pdf->AddPage('', '', true);
653 if (!empty($tplidx)) {
654 $pdf->useTemplate($tplidx);
655 }
656 $pdf->setPage($pageposbefore + 1);
657 $pdf->setPageOrientation('', true, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
658 $curY = $tab_top_newpage;
659 $showpricebeforepagebreak = 0;
660 }
661
662 // I remove the line commented below because it probably uselesss (or bug source) no need to change bottom margin because we have checked image fit
663 //$pdf->setPageOrientation('', 0, $heightforfooter + $heightforfreetext); // The only function to edit the bottom margin of current page to set it.
664
665 // @phan-suppress-next-line PhanTypeMismatchProperty
666 if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height'])) {
667 $pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY + $imageTopMargin, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi
668 // $pdf->Image does not increase value return by getY, so we save it manually
669 $posYAfterImage = $curY + $imglinesize['height'];
670 $this->setAfterColsLinePositionsData('photo', $posYAfterImage, $pdf->getPage());
671 }
672 }
673
674 // restore Page orientation for text
675 $pdf->setPageOrientation('', true, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
676
677 // Description of product line
678 if ($this->getColumnStatus('desc')) {
679 if ($object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
680 $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc);
681 $this->setAfterColsLinePositionsData('desc', $pdf->GetY(), $pdf->getPage());
682 } else {
683 $bg_color = colorStringToArray(getDolGlobalString("SUBTOTAL_BACK_COLOR_LEVEL_".abs($object->lines[$i]->qty), 'ffffff'));
684 pdf_render_subtotals($pdf, $this, $curY, $object, $i, $outputlangs, $hideref, $hidedesc, $bg_color, true, true);
685 }
686 }
687
688 $afterPosData = $this->getMaxAfterColsLinePositionsData();
689 $pdf->setPage($pageposbefore);
690 $pdf->setTopMargin($this->marge_haute);
691 $pdf->setPageOrientation('', false, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
692
693 // We suppose that a too long description or photo were moved completely on next page
694 if ($afterPosData['page'] > $pageposbefore && (empty($showpricebeforepagebreak) || ($curY + 4) > ($this->page_hauteur - $heightforfooter))) {
695 $pdf->setPage($afterPosData['page']);
696 $curY = $tab_top_newpage;
697 }
698
699 $pdf->SetFont('', '', $default_font_size - 1); // We reposition the default font
700
701 // Line position
702 if ($this->getColumnStatus('position')) {
703 $this->printStdColumnContent($pdf, $curY, 'position', strval($linePosition));
704 }
705
706 // VAT Rate
707 if ($this->getColumnStatus('vat') && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
708 $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
709 $this->printStdColumnContent($pdf, $curY, 'vat', $vat_rate);
710 }
711
712 // Unit price before discount
713 if ($this->getColumnStatus('subprice') && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE && isset($pdf_sub_options['titleshowuponpdf'])) {
714 $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);
715 $this->printStdColumnContent($pdf, $curY, 'subprice', $up_excl_tax);
716 }
717
718 // Quantity
719 // Enough for 6 chars
720 if ($this->getColumnStatus('qty') && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
721 $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
722 $this->printStdColumnContent($pdf, $curY, 'qty', $qty);
723 }
724
725
726 // Unit
727 if ($this->getColumnStatus('unit') && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
728 $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails);
729 $this->printStdColumnContent($pdf, $curY, 'unit', $unit);
730 }
731
732 // Discount on line
733 if ($this->getColumnStatus('discount') && $object->lines[$i]->remise_percent && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
734 $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);
735 $this->printStdColumnContent($pdf, $curY, 'discount', $remise_percent);
736 }
737
738 // Total excl tax line (HT)
739 if ($this->getColumnStatus('totalexcltax')) {
740 if ($object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE && isset($pdf_sub_options['titleshowtotalexludingvatonpdf'])) {
741 $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails);
742 $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax);
743 } elseif ($object->lines[$i]->qty < 0 && isset($sub_options['subtotalshowtotalexludingvatonpdf'])) {
744 if (isModEnabled('multicurrency') && $object->multicurrency_code != getDolCurrency()) {
745 $total_excl_tax = $object->getSubtotalLineMulticurrencyAmount($object->lines[$i]);
746 } else {
747 $total_excl_tax = $object->getSubtotalLineAmount($object->lines[$i]);
748 }
749 $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax);
750 }
751 }
752
753 // Total with tax line (TTC)
754 if ($this->getColumnStatus('totalincltax')) {
755 $total_incl_tax = pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails);
756 $this->printStdColumnContent($pdf, $curY, 'totalincltax', $total_incl_tax);
757 }
758
759 // Extrafields
760 if (!empty($object->lines[$i]->array_options)) {
761 foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) {
762 if ($this->getColumnStatus($extrafieldColKey)) {
763 $extrafieldValue = $this->getExtrafieldContent($object->lines[$i], $extrafieldColKey, $outputlangs);
764 $this->printStdColumnContent($pdf, $curY, $extrafieldColKey, $extrafieldValue);
765 $this->setAfterColsLinePositionsData('options_'.$extrafieldColKey, $pdf->GetY(), $pdf->getPage());
766 }
767 }
768 }
769
770 $afterPosData = $this->getMaxAfterColsLinePositionsData();
771 $parameters = array(
772 'object' => $object,
773 'i' => $i,
774 'pdf' => & $pdf,
775 'curY' => & $curY,
776 'nexY' => & $afterPosData['y'], // for backward module hook compatibility Y will be accessible by $object->getMaxAfterColsLinePositionsData()
777 'outputlangs' => $outputlangs,
778 'hidedetails' => $hidedetails
779 );
780 $reshook = $hookmanager->executeHooks('printPDFline', $parameters, $this); // Note that $object may have been modified by hook
781 }
782
783 // Collection of totals by value of vat in $this->tva["rate"] = total_tva
784 if (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) {
785 $tvaligne = $object->lines[$i]->multicurrency_total_tva;
786 } else {
787 $tvaligne = $object->lines[$i]->total_tva;
788 }
789
790 $localtax1ligne = $object->lines[$i]->total_localtax1;
791 $localtax2ligne = $object->lines[$i]->total_localtax2;
792 $localtax1_rate = $object->lines[$i]->localtax1_tx;
793 $localtax2_rate = $object->lines[$i]->localtax2_tx;
794 $localtax1_type = $object->lines[$i]->localtax1_type;
795 $localtax2_type = $object->lines[$i]->localtax2_type;
796
797 $vatrate = (string) $object->lines[$i]->tva_tx;
798
799 // Retrieve type from database for backward compatibility with old records
800 if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined
801 && (!empty($localtax1_rate) || !empty($localtax2_rate))) { // and there is local tax
802 $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $object->thirdparty, $mysoc);
803 $localtax1_type = isset($localtaxtmp_array[0]) ? $localtaxtmp_array[0] : '';
804 $localtax2_type = isset($localtaxtmp_array[2]) ? $localtaxtmp_array[2] : '';
805 }
806
807 // retrieve global local tax
808 if ($localtax1_type && $localtax1ligne != 0) {
809 if (empty($this->localtax1[$localtax1_type][$localtax1_rate])) {
810 $this->localtax1[$localtax1_type][$localtax1_rate] = $localtax1ligne;
811 } else {
812 $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne;
813 }
814 }
815 if ($localtax2_type && $localtax2ligne != 0) {
816 if (empty($this->localtax2[$localtax2_type][$localtax2_rate])) {
817 $this->localtax2[$localtax2_type][$localtax2_rate] = $localtax2ligne;
818 } else {
819 $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne;
820 }
821 }
822
823 if (($object->lines[$i]->info_bits & 0x01) == 0x01) {
824 $vatrate .= '*';
825 }
826
827 // Fill $this->tva and $this->tva_array
828 if (!isset($this->tva[$vatrate])) {
829 $this->tva[$vatrate] = 0;
830 }
831 $this->tva[$vatrate] += $tvaligne;
832 $vatcode = $object->lines[$i]->vat_src_code;
833 if (empty($this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'])) {
834 $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] = 0;
835 }
836 $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')] = array('vatrate' => $vatrate, 'vatcode' => $vatcode, 'amount' => $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] + $tvaligne);
837
838
839 if (!$hidenextline) {
840 $afterPosData = $this->getMaxAfterColsLinePositionsData();
841 $pdf->setPage($afterPosData['page']);
842 $nexY = $afterPosData['y'];
843
844 // Add line
845 if (getDolGlobalString('MAIN_PDF_DASH_BETWEEN_LINES') && $i < ($nblines - 1) && $afterPosData['y'] < $this->page_hauteur - $heightforfooter - 5) {
846 $pdf->SetLineStyle(array('dash' => '1,1', 'color' => array(80, 80, 80)));
847 //$pdf->SetDrawColor(190,190,200);
848 $pdf->line($this->marge_gauche, $nexY, $this->page_largeur - $this->marge_droite, $nexY);
849 $pdf->SetLineStyle(array('dash' => 0));
850 }
851 }
852 if ($object->lines[$i]->special_code == SUBTOTALS_SPECIAL_CODE && (isset($sub_options['titleshowuponpdf']) || isset($sub_options['titleshowtotalexludingvatonpdf'])) && getDolGlobalString('SUBTOTAL_HIDE_LINES_UNDER_TITLE')) { // TODO Use $sub_options['titlehidelinesundertitle'] instead of SUBTOTAL_HIDE_LINES_UNDER_TITLE
853 $hidenextline = 1;
854 }
855
856 $nexY += 0; // Add space between lines
857 }
858
859 // Add last page for document footer if there are not enough size left
860 $afterPosData = $this->getMaxAfterColsLinePositionsData();
861 if (isset($afterPosData['y']) && $afterPosData['y'] > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) {
862 $pdf->AddPage();
863 if (!empty($tplidx)) {
864 $pdf->useTemplate($tplidx);
865 }
866 $pagenb++;
867 $pdf->setPage($pagenb);
868 }
869
870 // Draw table frames and columns borders
871 $drawTabNumbPage = $pdf->getNumPages();
872 for ($i = $pageposbeforeprintlines; $i <= $drawTabNumbPage; $i++) {
873 $pdf->setPage($i);
874 // reset page orientation each loop to override it if it was changed
875 $pdf->setPageOrientation('', false, 0); // The only function to edit the bottom margin of current page to set it.
876
877 $drawTabHideTop = $hidetop;
878 $drawTabTop = $tab_top_newpage;
879 $drawTabBottom = $this->page_hauteur - $heightforfooter;
880 $hideBottom = 0; // TODO understand why it change to 1 or 0 during process
881
882 if ($i == $pageposbeforeprintlines) {
883 // first page need to start after notes
884 $drawTabTop = $tab_top;
885 } elseif (!$drawTabHideTop) {
886 if (getDolGlobalInt('MAIN_PDF_ENABLE_COL_HEAD_TITLE_REPEAT')) {
887 $drawTabTop -= $this->tabTitleHeight;
888 } else {
889 $drawTabHideTop = 1;
890 }
891 }
892
893 // last page need to include document footer
894 if ($i == $pdf->getNumPages()) {
895 // remove document footer height to tab bottom position
896 $drawTabBottom -= $heightforfreetext + $heightforinfotot;
897 }
898
899 $drawTabHeight = $drawTabBottom - $drawTabTop;
900 $this->_tableau($pdf, $drawTabTop, $drawTabHeight, 0, $outputlangs, $drawTabHideTop, $hideBottom, $object->multicurrency_code, $outputlangsbis);
901
902 $hideFreeText = $i != $pdf->getNumPages() ? 1 : 0; // Display free text only in last page
903 $this->_pagefoot($pdf, $object, $outputlangs, $hideFreeText);
904
905 $pdf->setPage($i); // in case of _pagefoot or _tableau change it
906
907 // reset page orientation each loop to override it if it was changed by _pagefoot or _tableau change it
908 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
909
910 // Don't print head on first page ($pageposbeforeprintlines) because already added previously
911 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') && $i != $pageposbeforeprintlines) {
912 $this->_pagehead($pdf, $object, 0, $outputlangs);
913 }
914 if (!empty($tplidx)) {
915 $pdf->useTemplate($tplidx);
916 }
917 }
918
919 // reset text color before print footers
920 $pdf->SetTextColor(0, 0, 0);
921
922 $pdf->setPage($pdf->getNumPages());
923
924 $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
925
926 // Display infos area
927 $posy = $this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs);
928
929 // Display total zone
930 $posy = $this->drawTotalTable($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs);
931
932
933 // Add number of pages in footer
934 if (method_exists($pdf, 'AliasNbPages')) {
935 $pdf->AliasNbPages(); // @phan-suppress-current-line PhanUndeclaredMethod
936 }
937
938 // Add terms to sale
939 $termsofsalefilename = getDolGlobalString('MAIN_INFO_ORDER_TERMSOFSALE');
940 if (getDolGlobalInt('MAIN_PDF_ADD_TERMSOFSALE_ORDER') && $termsofsalefilename) {
941 $termsofsale = $conf->order->dir_output.'/'.$termsofsalefilename;
942 if (!empty($conf->order->multidir_output[$conf->entity])) {
943 $termsofsale = $conf->order->multidir_output[$conf->entity].'/'.$termsofsalefilename;
944 }
945 if (file_exists($termsofsale) && is_readable($termsofsale)) {
946 $pagecount = $pdf->setSourceFile($termsofsale);
947 for ($i = 1; $i <= $pagecount; $i++) {
948 $tplIdx = $pdf->importPage($i);
949 if ($tplIdx !== false) {
950 $s = $pdf->getTemplatesize($tplIdx);
951 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
952 $pdf->useTemplate($tplIdx);
953 } else {
954 setEventMessages(null, array($termsofsale.' cannot be added, probably protected PDF'), 'warnings');
955 }
956 }
957 }
958 }
959
960 $pdf->Close();
961
962 $pdf->Output($file, 'F');
963
964 // Add pdfgeneration hook
965 $hookmanager->initHooks(array('pdfgeneration'));
966 $parameters = array('file' => $file, 'object' => $object, 'outputlangs' => $outputlangs);
967 global $action;
968 $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
969 $this->warnings = $hookmanager->warnings;
970 if ($reshook < 0) {
971 $this->error = $hookmanager->error;
972 $this->errors = $hookmanager->errors;
973 dolChmod($file);
974 return -1;
975 }
976
977 dolChmod($file);
978
979 $this->result = array('fullpath' => $file);
980
981 return 1; // No error
982 } else {
983 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
984 return 0;
985 }
986 } else {
987 $this->error = $langs->transnoentities("ErrorConstantNotDefined", "COMMANDE_OUTPUTDIR");
988 return 0;
989 }
990 }
991
1001 protected function drawPaymentsTable(&$pdf, $object, $posy, $outputlangs)
1002 {
1003 return 0;
1004 }
1005
1015 protected function drawInfoTable(&$pdf, $object, $posy, $outputlangs)
1016 {
1017 global $conf, $mysoc;
1018 $default_font_size = pdf_getPDFFontSize($outputlangs);
1019
1020 $pdf->SetFont('', '', $default_font_size - 1);
1021
1022 $diffsizetitle = getDolGlobalInt('PDF_DIFFSIZE_TITLE', 3);
1023
1024 // If France, show VAT mention if not applicable
1025 if ($this->emetteur->country_code == 'FR' && empty($mysoc->tva_assuj)) {
1026 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1027 $pdf->SetXY($this->marge_gauche, $posy);
1028 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', false);
1029
1030 $posy = $pdf->GetY() + 4;
1031 }
1032
1033 $posxval = 52;
1034
1035 $diffsizetitle = getDolGlobalInt('PDF_DIFFSIZE_TITLE', 3);
1036
1037 // Show payments conditions
1038 if ($object->cond_reglement_code || $object->cond_reglement) {
1039 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1040 $pdf->SetXY($this->marge_gauche, $posy);
1041 $titre = $outputlangs->transnoentities("PaymentConditions").':';
1042 $pdf->MultiCell(43, 4, $titre, 0, 'L');
1043
1044 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1045 $pdf->SetXY($posxval, $posy);
1046 $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);
1047 $lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
1048 if ($object->deposit_percent > 0) {
1049 $lib_condition_paiement = str_replace('__DEPOSIT_PERCENT__', (string) $object->deposit_percent, $lib_condition_paiement);
1050 }
1051 $pdf->MultiCell(67, 4, $lib_condition_paiement, 0, 'L');
1052
1053 $posy = $pdf->GetY() + 3;
1054 }
1055
1056 // Check a payment mode is defined
1057 /* Not used with orders
1058 if (empty($object->mode_reglement_code)
1059 && ! $conf->global->FACTURE_CHQ_NUMBER
1060 && ! $conf->global->FACTURE_RIB_NUMBER)
1061 {
1062 $pdf->SetXY($this->marge_gauche, $posy);
1063 $pdf->SetTextColor(200,0,0);
1064 $pdf->SetFont('','B', $default_font_size - 2);
1065 $pdf->MultiCell(80, 3, $outputlangs->transnoentities("ErrorNoPaiementModeConfigured"),0,'L',0);
1066 $pdf->SetTextColor(0,0,0);
1067
1068 $posy=$pdf->GetY()+1;
1069 }
1070 */
1071 /* TODO
1072 else if (!empty($object->availability_code))
1073 {
1074 $pdf->SetXY($this->marge_gauche, $posy);
1075 $pdf->SetTextColor(200,0,0);
1076 $pdf->SetFont('','B', $default_font_size - 2);
1077 $pdf->MultiCell(80, 3, $outputlangs->transnoentities("AvailabilityPeriod").': '.,0,'L',0);
1078 $pdf->SetTextColor(0,0,0);
1079
1080 $posy=$pdf->GetY()+1;
1081 }*/
1082
1083 // Show planned date of delivery
1084 if (!empty($object->delivery_date)) {
1085 $outputlangs->load("sendings");
1086 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1087 $pdf->SetXY($this->marge_gauche, $posy);
1088 $titre = $outputlangs->transnoentities("DateDeliveryPlanned").':';
1089 $pdf->MultiCell(80, 4, $titre, 0, 'L');
1090 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1091 $pdf->SetXY($posxval, $posy);
1092 $dlp = dol_print_date($object->delivery_date, "daytext", false, $outputlangs, true);
1093 $pdf->MultiCell(80, 4, $dlp, 0, 'L');
1094
1095 $posy = $pdf->GetY() + 1;
1096 } elseif ($object->availability_code || $object->availability) { // Show availability conditions
1097 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1098 $pdf->SetXY($this->marge_gauche, $posy);
1099 $titre = $outputlangs->transnoentities("AvailabilityPeriod").':';
1100 $pdf->MultiCell(80, 4, $titre, 0, 'L');
1101 $pdf->SetTextColor(0, 0, 0);
1102 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1103 $pdf->SetXY($posxval, $posy);
1104 $lib_availability = $outputlangs->transnoentities("AvailabilityType".$object->availability_code) != 'AvailabilityType'.$object->availability_code ? $outputlangs->transnoentities("AvailabilityType".$object->availability_code) : $outputlangs->convToOutputCharset(isset($object->availability) ? $object->availability : '');
1105 $lib_availability = str_replace('\n', "\n", $lib_availability);
1106 $pdf->MultiCell(80, 4, $lib_availability, 0, 'L');
1107
1108 $posy = $pdf->GetY() + 1;
1109 }
1110
1111 // Show payment mode
1112 if ($object->mode_reglement_code
1113 && $object->mode_reglement_code != 'CHQ'
1114 && $object->mode_reglement_code != 'VIR') {
1115 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1116 $pdf->SetXY($this->marge_gauche, $posy);
1117 $titre = $outputlangs->transnoentities("PaymentMode").':';
1118 $pdf->MultiCell(80, 5, $titre, 0, 'L');
1119
1120 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1121 $pdf->SetXY($posxval, $posy);
1122 $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);
1123 $pdf->MultiCell(80, 5, $lib_mode_reg, 0, 'L');
1124
1125 $posy = $pdf->GetY() + 2;
1126 }
1127
1128 // Show payment mode CHQ
1129 if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ') {
1130 // Si mode reglement non force ou si force a CHQ
1131 if (getDolGlobalString('FACTURE_CHQ_NUMBER')) {
1132 if (getDolGlobalInt('FACTURE_CHQ_NUMBER') > 0) {
1133 $account = new Account($this->db);
1134 $account->fetch(getDolGlobalString('FACTURE_CHQ_NUMBER'));
1135
1136 $pdf->SetXY($this->marge_gauche, $posy);
1137 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1138 $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $account->owner_name), 0, 'L', false);
1139 $posy = $pdf->GetY() + 1;
1140
1141 if (!getDolGlobalString('MAIN_PDF_HIDE_CHQ_ADDRESS')) {
1142 $pdf->SetXY($this->marge_gauche, $posy);
1143 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1144 $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', false);
1145 $posy = $pdf->GetY() + 2;
1146 }
1147 }
1148 if (getDolGlobalString('FACTURE_CHQ_NUMBER') == -1) {
1149 $pdf->SetXY($this->marge_gauche, $posy);
1150 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1151 $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $this->emetteur->name), 0, 'L', false);
1152 $posy = $pdf->GetY() + 1;
1153
1154 if (!getDolGlobalString('MAIN_PDF_HIDE_CHQ_ADDRESS')) {
1155 $pdf->SetXY($this->marge_gauche, $posy);
1156 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1157 $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', false);
1158 $posy = $pdf->GetY() + 2;
1159 }
1160 }
1161 }
1162 }
1163
1164 // If payment mode not forced or forced to VIR, show payment with BAN
1165 if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') {
1166 if ($object->fk_account > 0 || $object->fk_bank > 0 || getDolGlobalInt('FACTURE_RIB_NUMBER')) {
1167 $bankid = ($object->fk_account <= 0 ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account);
1168 if ($object->fk_bank > 0) {
1169 $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank
1170 }
1171 $account = new Account($this->db);
1172 $account->fetch($bankid);
1173
1174 $curx = $this->marge_gauche;
1175 $cury = $posy;
1176
1177 $posy = pdf_bank($pdf, $outputlangs, $curx, $cury, $account, 0, $default_font_size);
1178
1179 $posy += 2;
1180 }
1181 }
1182
1183 return $posy;
1184 }
1185
1186
1198 protected function drawTotalTable(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis = null)
1199 {
1200 global $conf, $mysoc, $hookmanager;
1201
1202 $default_font_size = pdf_getPDFFontSize($outputlangs);
1203
1204 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE') && $outputlangs->defaultlang != getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
1205 $outputlangsbis = new Translate('', $conf);
1206 $outputlangsbis->setDefaultLang(getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE'));
1207 $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal"));
1208 $default_font_size--;
1209 }
1210
1211 $tab2_top = $posy;
1212 $tab2_hl = 4;
1213 $pdf->SetFont('', '', $default_font_size - 1);
1214
1215 // Total table
1216 $col1x = 120;
1217 $col2x = 170;
1218 if ($this->page_largeur < 210) { // To work with US executive format
1219 $col2x -= 20;
1220 }
1221 $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
1222
1223 $useborder = 0;
1224 $index = 0;
1225
1226 // Get Total HT
1227 $total_ht = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1 ? $object->multicurrency_total_ht : $object->total_ht);
1228
1229 // Total discount
1230 $total_discount_on_lines = 0;
1231 $multicurrency_total_discount_on_lines = 0;
1232 foreach ($object->lines as $i => $line) {
1233 $resdiscount = pdfGetLineTotalDiscountAmount($object, $i, $outputlangs, 2);
1234 $multicurrency_resdiscount = pdfGetLineTotalDiscountAmount($object, $i, $outputlangs, 2, 1);
1235
1236 $total_discount_on_lines += (is_numeric($resdiscount) ? $resdiscount : 0);
1237 $multicurrency_total_discount_on_lines += (is_numeric($multicurrency_resdiscount) ? $multicurrency_resdiscount : 0);
1238 // If line was a negative line, we do not count the discount as a discount
1239 if ($line->total_ht < 0) {
1240 $total_discount_on_lines += -$line->total_ht;
1241 $multicurrency_total_discount_on_lines += -$line->multicurrency_total_ht;
1242 }
1243 }
1244
1245 if ($total_discount_on_lines > 0) {
1246 if ($this->showAmountBeforeDiscount) {
1247 // Show total NET before discount
1248 $pdf->SetFillColor(255, 255, 255);
1249 $pdf->SetXY($col1x, $tab2_top);
1250 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHTBeforeDiscount") . (is_object($outputlangsbis) ? ' / ' . $outputlangsbis->transnoentities("TotalHTBeforeDiscount") : ''), 0, 'L', true);
1251 $pdf->SetXY($col2x, $tab2_top);
1252
1253 $total_before_discount_to_show = ((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? ($object->multicurrency_total_ht + $multicurrency_total_discount_on_lines) : ($object->total_ht + $total_discount_on_lines));
1254 $pdf->MultiCell($largcol2, $tab2_hl, price($total_before_discount_to_show, 0, $outputlangs), 0, 'R', true);
1255
1256 $index++;
1257 }
1258
1259 if ($this->showDiscountAmount) {
1260 $pdf->SetFillColor(255, 255, 255);
1261 $pdf->SetXY($col1x, $tab2_top + $tab2_hl);
1262 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalDiscount") . (is_object($outputlangsbis) ? ' / ' . $outputlangsbis->transnoentities("TotalDiscount") : ''), 0, 'L', true);
1263 $pdf->SetXY($col2x, $tab2_top + $tab2_hl);
1264
1265 $total_discount_to_show = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $multicurrency_total_discount_on_lines : $total_discount_on_lines);
1266 $pdf->MultiCell($largcol2, $tab2_hl, price($total_discount_to_show, 0, $outputlangs), 0, 'R', true);
1267
1268 $index++;
1269 }
1270 }
1271
1272 // Total HT
1273 $pdf->SetFillColor(255, 255, 255);
1274 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1275 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("TotalHT") : ''), 0, 'L', true);
1276 $total_ht = ((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht);
1277 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1278 $pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + (!empty($object->remise) ? $object->remise : 0), 0, $outputlangs), 0, 'R', true);
1279
1280 // Show VAT by rates and total
1281 $pdf->SetFillColor(248, 248, 248);
1282
1283 $total_ttc = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
1284 $total_ttc_origin = $object->total_ttc;
1285
1286 $this->atleastoneratenotnull = 0;
1287 if (!getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT')) {
1288 $tvaisnull = (!empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000']));
1289 if (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL') && $tvaisnull) {
1290 // Nothing to do
1291 } else {
1292 //Local tax 1 before VAT
1293 foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1294 if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1295 continue;
1296 }
1297 foreach ($localtax_rate as $tvakey => $tvaval) {
1298 if ($tvakey != 0) { // On affiche pas taux 0
1299 //$this->atleastoneratenotnull++;
1300 $index++;
1301 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1302
1303 $tvacompl = '';
1304 if (preg_match('/\*/', (string) $tvakey)) {
1305 $tvakey = str_replace('*', '', (string) $tvakey);
1306 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1307 }
1308 $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : '');
1309 $totalvat .= ' ';
1310
1311 if (getDolGlobalString('PDF_LOCALTAX1_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') {
1312 $totalvat .= $tvacompl;
1313 } else {
1314 $totalvat .= vatrate((string) abs((float) $tvakey), true).$tvacompl;
1315 }
1316
1317 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1318
1319 $total_localtax = ((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1320
1321 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1322 $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', true);
1323 }
1324 }
1325 }
1326
1327 //Local tax 2 before VAT
1328 foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1329 if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1330 continue;
1331 }
1332 foreach ($localtax_rate as $tvakey => $tvaval) {
1333 if ($tvakey != 0) { // On affiche pas taux 0
1334 //$this->atleastoneratenotnull++;
1335
1336 $index++;
1337 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1338
1339 $tvacompl = '';
1340 if (preg_match('/\*/', (string) $tvakey)) {
1341 $tvakey = str_replace('*', '', (string) $tvakey);
1342 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1343 }
1344 $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : '');
1345 $totalvat .= ' ';
1346
1347 if (getDolGlobalString('PDF_LOCALTAX2_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') {
1348 $totalvat .= $tvacompl;
1349 } else {
1350 $totalvat .= vatrate((string) abs((float) $tvakey), true).$tvacompl;
1351 }
1352
1353 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1354
1355 $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1356
1357 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1358 $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', true);
1359 }
1360 }
1361 }
1362
1363 // VAT
1364 foreach ($this->tva_array as $tvakey => $tvaval) {
1365 if ($tvakey != 0) { // On affiche pas taux 0
1366 $this->atleastoneratenotnull++;
1367
1368 $index++;
1369 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1370
1371 $tvacompl = '';
1372 if (preg_match('/\*/', $tvakey)) {
1373 $tvakey = str_replace('*', '', $tvakey);
1374 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1375 }
1376 $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalVAT", $mysoc->country_code) : '');
1377 $totalvat .= ' ';
1378 if (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'rateonly') {
1379 $totalvat .= vatrate((string) $tvaval['vatrate'], true).$tvacompl;
1380 } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'codeonly') {
1381 $totalvat .= $tvaval['vatcode'].$tvacompl;
1382 } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') {
1383 $totalvat .= $tvacompl;
1384 } else {
1385 $totalvat .= vatrate((string) $tvaval['vatrate'], true).($tvaval['vatcode'] ? ' ('.$tvaval['vatcode'].')' : '').$tvacompl;
1386 }
1387 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1388
1389 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1390 $pdf->MultiCell($largcol2, $tab2_hl, price(price2num($tvaval['amount'], 'MT'), 0, $outputlangs), 0, 'R', true);
1391 }
1392 }
1393
1394 //Local tax 1 after VAT
1395 foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1396 if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1397 continue;
1398 }
1399
1400 foreach ($localtax_rate as $tvakey => $tvaval) {
1401 if ($tvakey != 0) { // On affiche pas taux 0
1402 //$this->atleastoneratenotnull++;
1403
1404 $index++;
1405 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1406
1407 $tvacompl = '';
1408 if (preg_match('/\*/', (string) $tvakey)) {
1409 $tvakey = str_replace('*', '', (string) $tvakey);
1410 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1411 }
1412 $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : '');
1413 $totalvat .= ' ';
1414
1415 if (getDolGlobalString('PDF_LOCALTAX1_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') {
1416 $totalvat .= $tvacompl;
1417 } else {
1418 $totalvat .= vatrate((string) abs((float) $tvakey), true).$tvacompl;
1419 }
1420
1421 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1422
1423 $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1424
1425 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1426 $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', true);
1427 }
1428 }
1429 }
1430
1431 //Local tax 2 after VAT
1432 foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1433 if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1434 continue;
1435 }
1436
1437 foreach ($localtax_rate as $tvakey => $tvaval) {
1438 // retrieve global local tax
1439 if ($tvakey != 0) { // On affiche pas taux 0
1440 //$this->atleastoneratenotnull++;
1441
1442 $index++;
1443 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1444
1445 $tvacompl = '';
1446 if (preg_match('/\*/', (string) $tvakey)) {
1447 $tvakey = str_replace('*', '', (string) $tvakey);
1448 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1449 }
1450 $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : '');
1451 $totalvat .= ' ';
1452
1453 if (getDolGlobalString('PDF_LOCALTAX2_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') {
1454 $totalvat .= $tvacompl;
1455 } else {
1456 $totalvat .= vatrate((string) abs((float) $tvakey), true).$tvacompl;
1457 }
1458
1459 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1460
1461 $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1462
1463 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1464 $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', true);
1465 }
1466 }
1467 }
1468 //}
1469
1470 // Total TTC
1471 $index++;
1472 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1473 $pdf->SetTextColor(0, 0, 60);
1474 $pdf->SetFillColor(224, 224, 224);
1475 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalTTC", $mysoc->country_code) : ''), $useborder, 'L', true);
1476
1477 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1478 if (!isModEnabled("multicurrency") || $object->multicurrency_tx == 1 || getDolGlobalInt('MULTICURRENCY_SHOW_ALSO_MAIN_CURRENCY_ON_PDF') == 0) {
1479 $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', true);
1480 } else {
1481 $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', true);
1482
1483 //$pdf->writeHTMLCell($largcol2, $tab2_hl, null, null, '<font size="-2">('.price($sign * $object->total_ttc, 0, $outputlangs, 1, -1, 'MT', $mysoc->currency_code).')</font> &nbsp; '.price($sign * $total_ttc, 0, $outputlangs), $useborder, 1, true, true, 'R');
1484 $index++;
1485 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1486 $pdf->SetTextColor(0, 0, 60);
1487 $pdf->SetFillColor(224, 224, 224);
1488 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("TotalTTC") : '').' ('.$outputlangs->getCurrencySymbol($mysoc->currency_code).')', $useborder, 'L', true);
1489
1490 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1491 $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc_origin, 0, $outputlangs, 1, -1, -1, $mysoc->currency_code), $useborder, 'L', true);
1492 }
1493 }
1494 }
1495
1496 $pdf->SetTextColor(0, 0, 0);
1497
1498 $creditnoteamount = 0;
1499 $depositsamount = 0;
1500 //$creditnoteamount=$object->getSumCreditNotesUsed();
1501 //$depositsamount=$object->getSumDepositsUsed();
1502 //print "x".$creditnoteamount."-".$depositsamount;exit;
1503 $resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT');
1504 if (!empty($object->paye)) {
1505 $resteapayer = 0;
1506 }
1507
1508 if ($deja_regle > 0) {
1509 // Already paid + Deposits
1510 $index++;
1511
1512 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1513 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("AlreadyPaid") : ''), 0, 'L', false);
1514 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1515 $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', false);
1516
1517 $index++;
1518 $pdf->SetTextColor(0, 0, 60);
1519 $pdf->SetFillColor(224, 224, 224);
1520 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1521 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("RemainderToPay") : ''), $useborder, 'L', true);
1522
1523 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1524 $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', true);
1525
1526 $pdf->SetFont('', '', $default_font_size - 1);
1527 $pdf->SetTextColor(0, 0, 0);
1528 }
1529
1530 $parameters = array('pdf' => &$pdf, 'object' => &$object, 'outputlangs' => $outputlangs, 'index' => &$index, 'posy' => $posy);
1531
1532 $reshook = $hookmanager->executeHooks('afterPDFTotalTable', $parameters, $this); // Note that $action and $object may have been modified by some hooks
1533 if ($reshook < 0) {
1534 $this->error = $hookmanager->error;
1535 $this->errors = $hookmanager->errors;
1536 }
1537
1538 $index++;
1539 return ($tab2_top + ($tab2_hl * $index));
1540 }
1541
1542 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1557 protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '', $outputlangsbis = null)
1558 {
1559 global $conf;
1560
1561 // Force to disable hidetop and hidebottom
1562 $hidebottom = 0;
1563 if ($hidetop) {
1564 $hidetop = -1;
1565 }
1566
1567 $currency = !empty($currency) ? $currency : getDolCurrency();
1568 $default_font_size = pdf_getPDFFontSize($outputlangs);
1569
1570 // Amount in (at tab_top - 1)
1571 $pdf->SetTextColor(0, 0, 0);
1572 $pdf->SetFont('', '', $default_font_size - 2);
1573
1574 if (empty($hidetop)) {
1575 $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
1576 if (getDolGlobalInt('PDF_USE_ALSO_LANGUAGE_CODE') && is_object($outputlangsbis)) {
1577 $titre .= ' - '.$outputlangsbis->transnoentities("AmountInCurrency", $outputlangsbis->transnoentitiesnoconv("Currency".$currency));
1578 }
1579
1580 $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
1581 $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
1582
1583 //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
1584 if (getDolGlobalString('MAIN_PDF_TITLE_BACKGROUND_COLOR')) {
1585 $pdf->RoundedRect($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite - $this->marge_gauche, $this->tabTitleHeight, $this->corner_radius, '1001', 'F', array(), explode(',', getDolGlobalString('MAIN_PDF_TITLE_BACKGROUND_COLOR')));
1586 }
1587 }
1588
1589 $pdf->SetDrawColor(128, 128, 128);
1590 $pdf->SetFont('', '', $default_font_size - 1);
1591
1592 // Output Rect
1593 $this->printRoundedRect($pdf, $this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $tab_height, $this->corner_radius, $hidetop, $hidebottom, 'D'); // Rect takes a length in 3rd parameter and 4th parameter
1594
1595
1596 $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop);
1597
1598 if (empty($hidetop)) {
1599 $pdf->line($this->marge_gauche, $tab_top + $this->tabTitleHeight, $this->page_largeur - $this->marge_droite, $tab_top + $this->tabTitleHeight); // line takes a position y in 2nd parameter and 4th parameter
1600 }
1601 }
1602
1603 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1604 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1616 protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null, $titlekey = "PdfOrderTitle")
1617 {
1618 // phpcs:enable
1619 global $conf, $langs, $hookmanager, $mysoc;
1620
1621 $ltrdirection = 'L';
1622 if ($outputlangs->trans("DIRECTION") == 'rtl') {
1623 $ltrdirection = 'R';
1624 }
1625
1626 // Load traductions files required by page
1627 $outputlangs->loadLangs(array("main", "bills", "propal", "orders", "companies"));
1628
1629 $default_font_size = pdf_getPDFFontSize($outputlangs);
1630
1631 pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
1632
1633 $pdf->SetTextColor(0, 0, 60);
1634 $pdf->SetFont('', 'B', $default_font_size + 3);
1635
1636 $w = 100;
1637
1638 $posy = $this->marge_haute;
1639 $posx = $this->page_largeur - $this->marge_droite - $w;
1640
1641 $pdf->SetXY($this->marge_gauche, $posy);
1642
1643 // Logo
1644 $logodir = $conf->mycompany->dir_output;
1645 $multidiroutput = getMultidirOutput($mysoc, 'mycompany');
1646 if (!empty($multidiroutput)) {
1647 $logodir = $multidiroutput;
1648 }
1649 pdf_writeLogoOrCompanyName($pdf, $outputlangs, $this->emetteur, $logodir, $this->marge_gauche, $posy, $w, $default_font_size, 'L');
1650
1651 $pdf->SetFont('', 'B', $default_font_size + 3);
1652 $pdf->SetXY($posx, $posy);
1653 $pdf->SetTextColor(0, 0, 60);
1654 $title = $outputlangs->transnoentities($titlekey);
1655 if (getDolGlobalInt('PDF_USE_ALSO_LANGUAGE_CODE') && is_object($outputlangsbis)) {
1656 $title .= ' - ';
1657 $title .= $outputlangsbis->transnoentities($titlekey);
1658 }
1659 $title .= ' '.$outputlangs->convToOutputCharset($object->ref);
1660 if ($object->status == $object::STATUS_DRAFT) {
1661 $pdf->SetTextColor(128, 0, 0);
1662 $title .= ' - '.$outputlangs->transnoentities("NotValidated");
1663 }
1664
1665 $pdf->MultiCell($w, 3, $title, '', 'R');
1666
1667 $pdf->SetFont('', 'B', $default_font_size);
1668
1669 /*
1670 $posy += 5;
1671 $pdf->SetXY($posx, $posy);
1672 $pdf->SetTextColor(0, 0, 60);
1673 $textref = $outputlangs->transnoentities("Ref")." : ".$outputlangs->convToOutputCharset($object->ref);
1674 if ($object->statut == $object::STATUS_DRAFT) {
1675 $pdf->SetTextColor(128, 0, 0);
1676 $textref .= ' - '.$outputlangs->transnoentities("NotValidated");
1677 }
1678 $pdf->MultiCell($w, 4, $textref, '', 'R');
1679 */
1680
1681 $posy += 3;
1682 $pdf->SetFont('', '', $default_font_size - 2);
1683
1684 if ($object->ref_client) {
1685 $posy += 4;
1686 $pdf->SetXY($posx, $posy);
1687 $pdf->SetTextColor(0, 0, 60);
1688 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".dol_trunc($outputlangs->convToOutputCharset((string) $object->ref_client), 65), '', 'R');
1689 }
1690
1691 if (getDolGlobalInt('PDF_SHOW_PROJECT_TITLE')) {
1692 $object->fetchProject();
1693 if (!empty($object->project->ref)) {
1694 $posy += 3;
1695 $pdf->SetXY($posx, $posy);
1696 $pdf->SetTextColor(0, 0, 60);
1697 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->project->title), '', 'R');
1698 }
1699 }
1700
1701 if (getDolGlobalInt('PDF_SHOW_PROJECT')) {
1702 $object->fetchProject();
1703 if (!empty($object->project->ref)) {
1704 $outputlangs->load("projects");
1705 $posy += 3;
1706 $pdf->SetXY($posx, $posy);
1707 $pdf->SetTextColor(0, 0, 60);
1708 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefProject")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R');
1709 }
1710 }
1711
1712 $posy += 4;
1713
1714 $pdf->SetXY($posx, $posy);
1715 $pdf->SetTextColor(0, 0, 60);
1716 $title = $outputlangs->transnoentities("OrderDate");
1717 if (getDolGlobalInt('PDF_USE_ALSO_LANGUAGE_CODE') && is_object($outputlangsbis)) {
1718 $title .= ' - '.$outputlangsbis->transnoentities("DateInvoice");
1719 }
1720 $pdf->MultiCell($w, 3, $title." : ".dol_print_date($object->date, "day", false, $outputlangs, true), '', 'R');
1721
1722 if (!getDolGlobalString('MAIN_PDF_HIDE_CUSTOMER_CODE') && !empty($object->thirdparty->code_client)) {
1723 $posy += 4;
1724 $pdf->SetXY($posx, $posy);
1725 $pdf->SetTextColor(0, 0, 60);
1726 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities((string) $object->thirdparty->code_client), '', 'R');
1727 }
1728
1729 if (!getDolGlobalString('MAIN_PDF_HIDE_CUSTOMER_ACCOUNTING_CODE') && !empty($object->thirdparty->code_compta_client)) {
1730 $posy += 4;
1731 $pdf->SetXY($posx, $posy);
1732 $pdf->SetTextColor(0, 0, 60);
1733 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerAccountancyCode")." : ".$outputlangs->transnoentities((string) $object->thirdparty->code_compta_client), '', 'R');
1734 }
1735
1736 // Get contact
1737 if (getDolGlobalInt('DOC_SHOW_FIRST_SALES_REP')) {
1738 $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1739 if (count($arrayidcontact) > 0) {
1740 $usertmp = new User($this->db);
1741 $usertmp->fetch($arrayidcontact[0]);
1742 $posy += 4;
1743 $pdf->SetXY($posx, $posy);
1744 $pdf->SetTextColor(0, 0, 60);
1745 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
1746 }
1747 }
1748
1749 $posy += 2;
1750
1751 $top_shift = 0;
1752 $shipp_shift = 0;
1753 // Show list of linked objects
1754 $current_y = $pdf->getY();
1755 $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size);
1756 if ($current_y < $pdf->getY()) {
1757 $top_shift = $pdf->getY() - $current_y;
1758 }
1759
1760 if ($showaddress) {
1761 // Sender properties
1762 $carac_emetteur = '';
1763 // Add internal contact of object if defined
1764 $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1765 if (count($arrayidcontact) > 0) {
1766 $object->fetch_user($arrayidcontact[0]);
1767 $labelbeforecontactname = ($outputlangs->transnoentities("FromContactName") != 'FromContactName' ? $outputlangs->transnoentities("FromContactName") : $outputlangs->transnoentities("Name"));
1768 $carac_emetteur .= ($carac_emetteur ? "\n" : '').$labelbeforecontactname." ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs));
1769 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ' (' : '';
1770 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && !empty($object->user->office_phone)) ? $object->user->office_phone : '';
1771 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ', ' : '';
1772 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT') && !empty($object->user->email)) ? $object->user->email : '';
1773 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ')' : '';
1774 $carac_emetteur .= "\n";
1775 }
1776
1777 $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
1778
1779 // Show sender
1780 $posy = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? $this->marge_haute : $this->marge_haute + 32;
1781 $posy += $top_shift;
1782 $posx = $this->marge_gauche;
1783 if (getDolGlobalInt('MAIN_INVERT_SENDER_RECIPIENT')) {
1784 $posx = $this->page_largeur - $this->marge_droite - 80;
1785 }
1786
1787 $hautcadre = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 38 : 40;
1788 $widthrecbox = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 92 : 82;
1789
1790
1791 // Show sender frame
1792 if (!getDolGlobalString('MAIN_PDF_NO_SENDER_FRAME')) {
1793 $pdf->SetTextColor(0, 0, 0);
1794 $pdf->SetFont('', '', $default_font_size - 2);
1795 $pdf->SetXY($posx, $posy - 5);
1796 $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillFrom"), 0, $ltrdirection);
1797 $pdf->SetXY($posx, $posy);
1798 $pdf->SetFillColor(230, 230, 230);
1799 $pdf->RoundedRect($posx, $posy, $widthrecbox, $hautcadre, $this->corner_radius, '1234', 'F');
1800 $pdf->SetTextColor(0, 0, 60);
1801 }
1802
1803 // Show sender name
1804 if (!getDolGlobalString('MAIN_PDF_HIDE_SENDER_NAME')) {
1805 $pdf->SetXY($posx + 2, $posy + 3);
1806 $pdf->SetFont('', 'B', $default_font_size);
1807 $pdf->MultiCell($widthrecbox - 2, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, $ltrdirection);
1808 $posy = $pdf->getY();
1809 }
1810
1811 // Show sender information
1812 $pdf->SetXY($posx + 2, $posy);
1813 $pdf->SetFont('', '', $default_font_size - 1);
1814 $pdf->MultiCell($widthrecbox - 2, 4, $carac_emetteur, 0, $ltrdirection);
1815
1816 // If CUSTOMER contact defined, we use it
1817 $usecontact = false;
1818 $arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
1819 if (count($arrayidcontact) > 0) {
1820 $usecontact = true;
1821 $result = $object->fetch_contact($arrayidcontact[0]);
1822 }
1823
1824 //Recipient name
1825 if ($usecontact && $object->contact->socid != $object->thirdparty->id && getDolGlobalInt('MAIN_USE_COMPANY_NAME_OF_CONTACT')) {
1826 $thirdparty = $object->contact;
1827 } else {
1828 $thirdparty = $object->thirdparty;
1829 }
1830
1831 if (is_object($thirdparty)) {
1832 $carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);
1833 } else {
1834 $carac_client_name = '';
1835 }
1836
1837 $mode = 'target';
1838 $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), ($usecontact ? 1 : 0), $mode, $object);
1839
1840 // Show recipient
1841 $widthrecbox = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 92 : 100;
1842 if ($this->page_largeur < 210) {
1843 $widthrecbox = 84; // To work with US executive format
1844 }
1845 $posy = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? $this->marge_haute + 30 : 32 + $this->marge_haute;
1846 $posy += $top_shift;
1847 $posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
1848 if (getDolGlobalInt('MAIN_INVERT_SENDER_RECIPIENT')) {
1849 $posx = $this->marge_gauche;
1850 }
1851
1852 // Show recipient frame
1853 if (!getDolGlobalString('MAIN_PDF_NO_RECIPENT_FRAME')) {
1854 $pdf->SetTextColor(0, 0, 0);
1855 $pdf->SetFont('', '', $default_font_size - 2);
1856 $pdf->SetXY($posx + 2, $posy - 5);
1857 $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo"), 0, $ltrdirection);
1858 $pdf->RoundedRect($posx, $posy, $widthrecbox, $hautcadre, $this->corner_radius, '1234', 'D');
1859 }
1860
1861 // Show recipient name
1862 $pdf->SetXY($posx + 2, $posy + 3);
1863 $pdf->SetFont('', 'B', $default_font_size);
1864 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
1865 $pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, $ltrdirection);
1866
1867 $posy = $pdf->getY();
1868
1869 // Show recipient information
1870 $pdf->SetFont('', '', $default_font_size - 1);
1871 $pdf->SetXY($posx + 2, $posy);
1872 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
1873 $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, $ltrdirection);
1874
1875 // Show shipping address
1876 if (getDolGlobalInt('SALES_ORDER_SHOW_SHIPPING_ADDRESS')) {
1877 $idaddressshipping = $object->getIdContact('external', 'SHIPPING');
1878
1879 if (!empty($idaddressshipping)) {
1880 $contactshipping = $object->fetch_contact($idaddressshipping[0]);
1881 $companystatic = new Societe($this->db);
1882 $companystatic->fetch($object->contact->fk_soc);
1883 $carac_client_name_shipping = (($object->contact instanceof Contact) ? pdfBuildThirdpartyName($object->contact, $outputlangs) : '');
1884 $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $companystatic, $object->contact, 1, 'target', $object);
1885 } else {
1886 $carac_client_name_shipping = ($object->thirdparty instanceof Societe ? pdfBuildThirdpartyName($object->thirdparty, $outputlangs) : '');
1887 $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'target', $object);
1888 }
1889 if (!empty($carac_client_shipping)) {
1890 $posy += $hautcadre;
1891
1892 $hautcadre -= 10; // Height for the shipping address does not need to be as high as main box
1893
1894 // Show shipping frame
1895 $pdf->SetXY($posx + 2, $posy - 5);
1896 $pdf->SetFont('', '', $default_font_size - 2);
1897 $pdf->MultiCell($widthrecbox, 0, $outputlangs->transnoentities('ShippingTo'), 0, 'L', false);
1898 $pdf->RoundedRect($posx, $posy, $widthrecbox, $hautcadre, $this->corner_radius, '1234', 'D');
1899
1900 // Show shipping name
1901 $pdf->SetXY($posx + 2, $posy + 1);
1902 $pdf->SetFont('', 'B', $default_font_size);
1903 $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_name_shipping, '', 'L');
1904
1905 $posy = $pdf->getY();
1906
1907 // Show shipping information
1908 $pdf->SetXY($posx + 2, $posy);
1909 $pdf->SetFont('', '', $default_font_size - 1);
1910 $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_shipping, '', 'L');
1911
1912 $shipp_shift += $hautcadre + 10;
1913 }
1914 }
1915 }
1916
1917 $pdf->SetTextColor(0, 0, 0);
1918
1919 $pagehead = array('top_shift' => $top_shift, 'shipp_shift' => $shipp_shift);
1920
1921 return $pagehead;
1922 }
1923
1924 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1925 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1935 protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
1936 {
1937 // phpcs:enable
1938 $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0);
1939 return pdf_pagefoot($pdf, $outputlangs, 'ORDER_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext, $this->page_largeur, $this->watermark);
1940 }
1941
1942
1943
1954 public function defineColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1955 {
1956 global $hookmanager;
1957
1958 // Default field style for content
1959 $this->defaultContentsFieldsStyle = array(
1960 'align' => 'R', // R,C,L
1961 'padding' => array(1, 0.5, 1, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1962 );
1963
1964 // Default field style for content
1965 $this->defaultTitlesFieldsStyle = array(
1966 'align' => 'C', // R,C,L
1967 'padding' => array(0.5, 0, 0.5, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1968 );
1969
1970 /*
1971 * For example
1972 $this->cols['theColKey'] = array(
1973 'rank' => $rank, // int : use for ordering columns
1974 'width' => 20, // the column width in mm
1975 'title' => array(
1976 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
1977 'label' => ' ', // the final label : used fore final generated text
1978 'align' => 'L', // text alignment : R,C,L
1979 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1980 ),
1981 'content' => array(
1982 'align' => 'L', // text alignment : R,C,L
1983 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1984 ),
1985 );
1986 */
1987
1988 $rank = 0; // do not use negative rank
1989 $this->cols['position'] = array(
1990 'rank' => $rank,
1991 'width' => 10,
1992 'status' => (getDolGlobalInt('PDF_ERATOSTHENE_ADD_POSITION') || getDolGlobalInt('PDF_ERATOSHTENE_ADD_POSITION')) ? true : (getDolGlobalInt('PDF_ADD_POSITION') ? true : false),
1993 'title' => array(
1994 'textkey' => '#', // use lang key is useful in some case with module
1995 'align' => 'C',
1996 // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
1997 // 'label' => ' ', // the final label
1998 'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1999 ),
2000 'content' => array(
2001 'align' => 'C',
2002 'padding' => array(1, 0.5, 1, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2003 ),
2004 );
2005
2006 $rank = 5; // do not use negative rank
2007 $this->cols['desc'] = array(
2008 'rank' => $rank,
2009 'width' => false, // only for desc
2010 'status' => true,
2011 'title' => array(
2012 'textkey' => 'Designation', // use lang key is useful in some case with module
2013 'align' => 'L',
2014 // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
2015 // 'label' => ' ', // the final label
2016 'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2017 ),
2018 'content' => array(
2019 'align' => 'L',
2020 'padding' => array(1, 0.5, 1, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2021 ),
2022 );
2023
2024 // Image of product
2025 $rank += 10;
2026 $this->cols['photo'] = array(
2027 'rank' => $rank,
2028 'width' => (!getDolGlobalInt('MAIN_DOCUMENTS_WITH_PICTURE_WIDTH') ? 20 : getDolGlobalInt('MAIN_DOCUMENTS_WITH_PICTURE_WIDTH')), // in mm
2029 'status' => false,
2030 'title' => array(
2031 'textkey' => 'Photo',
2032 'label' => ' '
2033 ),
2034 'content' => array(
2035 'padding' => array(0, 0, 0, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2036 ),
2037 'border-left' => false, // remove left line separator
2038 );
2039
2040 if (getDolGlobalInt('MAIN_GENERATE_ORDERS_WITH_PICTURE') && !empty($this->atleastonephoto)) {
2041 $this->cols['photo']['status'] = true;
2042 }
2043
2044 $rank += 10;
2045 $this->cols['vat'] = array(
2046 'rank' => $rank,
2047 'status' => false,
2048 'width' => 16, // in mm
2049 'title' => array(
2050 'textkey' => 'VAT'
2051 ),
2052 'border-left' => true, // add left line separator
2053 );
2054
2055 if (!getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT') && !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN')) {
2056 $this->cols['vat']['status'] = true;
2057 }
2058
2059 $rank += 10;
2060 $this->cols['subprice'] = array(
2061 'rank' => $rank,
2062 'width' => 19, // in mm
2063 'status' => true,
2064 'title' => array(
2065 'textkey' => 'PriceUHT'
2066 ),
2067 'border-left' => true, // add left line separator
2068 );
2069
2070 // Adapt dynamically the width of subprice, if text is too long.
2071 $tmpwidth = 0;
2072 $nblines = count($object->lines);
2073 for ($i = 0; $i < $nblines; $i++) {
2074 $tmpwidth2 = dol_strlen(dol_string_nohtmltag(pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails)));
2075 $tmpwidth = max($tmpwidth, $tmpwidth2);
2076 }
2077 if ($tmpwidth > 10) {
2078 $this->cols['subprice']['width'] += (2 * ($tmpwidth - 10));
2079 }
2080
2081 $rank += 10;
2082 $this->cols['qty'] = array(
2083 'rank' => $rank,
2084 'width' => 16, // in mm
2085 'status' => true,
2086 'title' => array(
2087 'textkey' => 'Qty'
2088 ),
2089 'border-left' => true, // add left line separator
2090 );
2091
2092 $rank += 10;
2093 $this->cols['unit'] = array(
2094 'rank' => $rank,
2095 'width' => 11, // in mm
2096 'status' => false,
2097 'title' => array(
2098 'textkey' => 'Unit'
2099 ),
2100 'border-left' => true, // add left line separator
2101 );
2102 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2103 $this->cols['unit']['status'] = true;
2104 }
2105
2106 $rank += 10;
2107 $this->cols['discount'] = array(
2108 'rank' => $rank,
2109 'width' => 13, // in mm
2110 'status' => false,
2111 'title' => array(
2112 'textkey' => 'ReductionShort'
2113 ),
2114 'border-left' => true, // add left line separator
2115 );
2116 if ($this->atleastonediscount) {
2117 $this->cols['discount']['status'] = true;
2118 }
2119
2120 $rank += 1000; // add a big offset to be sure is the last col because default extrafield rank is 100
2121 $this->cols['totalexcltax'] = array(
2122 'rank' => $rank,
2123 'width' => 26, // in mm
2124 'status' => !getDolGlobalString('PDF_ORDER_HIDE_PRICE_EXCL_TAX'),
2125 'title' => array(
2126 'textkey' => 'TotalHTShort'
2127 ),
2128 'border-left' => true, // add left line separator
2129 );
2130
2131 $rank += 1010; // add a big offset to be sure is the last col because default extrafield rank is 100
2132 $this->cols['totalincltax'] = array(
2133 'rank' => $rank,
2134 'width' => 26, // in mm
2135 'status' => getDolGlobalBool('PDF_ORDER_SHOW_PRICE_INCL_TAX'),
2136 'title' => array(
2137 'textkey' => 'TotalTTCShort'
2138 ),
2139 'border-left' => true, // add left line separator
2140 );
2141
2142 // Add extrafields cols
2143 if (!empty($object->lines)) {
2144 $line = reset($object->lines);
2145 $this->defineColumnExtrafield($line, $outputlangs, $hidedetails);
2146 }
2147
2148 $parameters = array(
2149 'object' => $object,
2150 'outputlangs' => $outputlangs,
2151 'hidedetails' => $hidedetails,
2152 'hidedesc' => $hidedesc,
2153 'hideref' => $hideref
2154 );
2155
2156 $reshook = $hookmanager->executeHooks('defineColumnField', $parameters, $this); // Note that $object may have been modified by hook
2157 if ($reshook < 0) {
2158 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2159 } elseif (empty($reshook)) {
2160 // @phan-suppress-next-line PhanPluginSuspiciousParamOrderInternal
2161 $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys
2162 } else {
2163 $this->cols = $hookmanager->resArray;
2164 }
2165 }
2166}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
Class to manage bank accounts.
prepareArrayColumnField($object, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Prepare Array Column Field.
getColumnStatus($colKey)
get column status from column key
printStdColumnContent($pdf, &$curY, $colKey, $columnText='')
print standard column content
pdfTabTitles(&$pdf, $tab_top, $tab_height, $outputlangs, $hidetop=0)
Print standard column content.
printColDescContent($pdf, &$curY, $colKey, $object, $i, $outputlangs, $hideref=0, $hidedesc=0, $issupplierline=0)
print description column content
getMaxAfterColsLinePositionsData()
Get position in PDF after col display.
getColumnContentXStart($colKey)
get column content X (abscissa) left position from column key
setAfterColsLinePositionsData(string $colId, float $y, int $pageNumb)
Used for to set afterColsLinePositions var in a pdf draw line loop.
getExtrafieldContent($object, $extrafieldKey, $outputlangs=null)
get extrafield content for pdf writeHtmlCell compatibility usage for PDF line columns and object note...
printRoundedRect($pdf, $x, $y, $w, $h, $r, $hidetop=0, $hidebottom=0, $style='D')
Print a rounded rectangle on the PDF.
resetAfterColsLinePositionsData(float $y, int $pageNumb)
Used for reset afterColsLinePositions var in start of a new pdf draw line loop.
defineColumnExtrafield($object, $outputlangs, $hidedetails=0)
Define Array Column Field for extrafields.
Class to manage contact/addresses.
Class to manage Dolibarr database access.
Class to manage hooks.
Parent class for orders models.
Class to manage products or services.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
Class to manage Dolibarr users.
Class to generate PDF orders with template Eratosthene.
drawInfoTable(&$pdf, $object, $posy, $outputlangs)
Show miscellaneous information (payment mode, payment term, ...)
write_file($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0)
Function to build pdf onto disk.
_tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='', $outputlangsbis=null)
Show table for lines.
drawPaymentsTable(&$pdf, $object, $posy, $outputlangs)
Show payments table.
_pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis=null, $titlekey="PdfOrderTitle")
Show top header of page.
__construct(DoliDB $db)
Constructor.
_pagefoot(&$pdf, $object, $outputlangs, $hidefreetext=0)
Show footer of page.
drawTotalTable(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis=null)
Show total to pay.
defineColumnField($object, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Define Array Column Field.
global $mysoc
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
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...
colorStringToArray($stringcolor, $colorifnotfound=array(88, 88, 88))
Convert a string RGB value ('FFFFFF', '255,255,255') into an array RGB array(255,255,...
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
getCallerInfoString()
Get caller info as a string that can be appended to a log message.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return a 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.
getMultidirOutput($object, $module='', $forobject=0, $mode='output')
Return the full path of the directory where a module (or an object of a module) stores its files.
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...
getDolCurrency()
Return the main currency ('EUR', 'USD', ...)
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...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalBool($key, $default=false)
Return a Dolibarr global constant boolean value.
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...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
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:3217
pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line total excluding tax.
Definition pdf.lib.php:2918
pdf_getFormat($outputlangs=null, $mode='setup')
Return array with format properties of default PDF format.
Definition pdf.lib.php:87
pdfGetLineTotalDiscountAmount($object, $i, $outputlangs, $hidedetails=0, $multicurrency=0)
Return line total amount discount.
Definition pdf.lib.php:3249
pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, $h, $align, $default_font_size)
Show linked objects for PDF generation.
Definition pdf.lib.php:1851
pdf_getPDFFontSize($outputlangs)
Return font size to use for PDF generation.
Definition pdf.lib.php:294
pdf_bank($pdf, $outputlangs, $curx, $cury, $account, $onlynumber=0, $default_font_size=10)
Show bank information for PDF generation.
Definition pdf.lib.php:1282
pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails=0)
Return line total including tax.
Definition pdf.lib.php:2968
pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line unit price excluding tax.
Definition pdf.lib.php:2507
pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails=0)
Return line vat rate.
Definition pdf.lib.php:2445
pdf_pagehead($pdf, $outputlangs, $page_height)
Show header of page for PDF generation.
Definition pdf.lib.php:790
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:1464
pdf_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition pdf.lib.php:273
pdf_render_subtotals(TCPDF $pdf, CommonDocGenerator $generator, float $curY, CommonObject $object, int $i, Translate $outputlangs, int $hideref, int $hidedesc, array $bgColor, bool $isSubtotal=false, bool $applySubtotalLogic=true)
Render subtotals line with a colored background and adapted text color .
Definition pdf.lib.php:3347
pdf_build_address($outputlangs, $sourcecompany, $targetcompany='', $targetcontact='', $usecontact=0, $mode='source', $object=null)
Return a string with full address formatted for output on PDF documents.
Definition pdf.lib.php:479
pdf_writeLogoOrCompanyName($pdf, $outputlangs, $emetteur, $logodir, $posx, $posy, $w, $default_font_size, $align)
Output company logo on top-left of a PDF page header, or the company name as fallback text if no logo...
Definition pdf.lib.php:349
pdf_getlineunit($object, $i, $outputlangs, $hidedetails=0)
Return line unit.
Definition pdf.lib.php:2752
pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails=0)
Return line remise percent.
Definition pdf.lib.php:2795
pdf_getlineqty($object, $i, $outputlangs, $hidedetails=0)
Return line quantity.
Definition pdf.lib.php:2592
pdf_getSubstitutionArray($outputlangs, $exclude=null, $object=null, $onlykey=0, $include=null)
Return array of possible substitutions for PDF content (without external module substitutions).
Definition pdf.lib.php:1178
pdf_getInstance($format='', $metric='mm', $pagetype='P')
Return a PDF instance object.
Definition pdf.lib.php:129
pdfBuildThirdpartyName($thirdparty, Translate $outputlangs, $includealias=0)
Returns the name of the thirdparty.
Definition pdf.lib.php:434
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:130
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:133