dolibarr 24.0.0-beta
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 = 90 + $top_shift + $shipp_shift;
376 $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
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 for ($i = 0; $i < $nblines; $i++) {
569 $linePosition = $i + 1;
570 $curY = $nexY;
571
572 $sub_options = $object->lines[$i]->extraparams["subtotal"] ?? array();
573
574 if ($object->lines[$i]->special_code == SUBTOTALS_SPECIAL_CODE) {
575 $level = $object->lines[$i]->qty;
576 if ($sub_options) {
577 if (isset($sub_options['titleshowuponpdf'])) {
578 $pdf_sub_options['titleshowuponpdf'] = isset($pdf_sub_options['titleshowuponpdf']) && $pdf_sub_options['titleshowuponpdf'] < $level ? $pdf_sub_options['titleshowuponpdf'] : $level;
579 } elseif (isset($pdf_sub_options['titleshowuponpdf']) && abs($level) <= $pdf_sub_options['titleshowuponpdf']) {
580 unset($pdf_sub_options['titleshowuponpdf']);
581 }
582 if (isset($sub_options['titleshowtotalexludingvatonpdf'])) {
583 $pdf_sub_options['titleshowtotalexludingvatonpdf'] = isset($pdf_sub_options['titleshowtotalexludingvatonpdf']) && $pdf_sub_options['titleshowtotalexludingvatonpdf'] < $level ? $pdf_sub_options['titleshowtotalexludingvatonpdf'] : $level;
584 } elseif (isset($pdf_sub_options['titleshowtotalexludingvatonpdf']) && abs($level) <= $pdf_sub_options['titleshowtotalexludingvatonpdf']) {
585 unset($pdf_sub_options['titleshowtotalexludingvatonpdf']);
586 }
587 } else {
588 if (isset($pdf_sub_options['titleshowuponpdf']) && abs($level) <= $pdf_sub_options['titleshowuponpdf']) {
589 unset($pdf_sub_options['titleshowuponpdf']);
590 }
591 if (isset($pdf_sub_options['titleshowtotalexludingvatonpdf']) && abs($level) <= $pdf_sub_options['titleshowtotalexludingvatonpdf']) {
592 unset($pdf_sub_options['titleshowtotalexludingvatonpdf']);
593 }
594 }
595 }
596
597 if (($curY + 6) > ($this->page_hauteur - $heightforfooter) || isset($sub_options['titleforcepagebreak']) && !($pdf->getNumPages() == 1 && $curY == $tab_top + $this->tabTitleHeight)) {
598 $object->lines[$i]->pagebreak = true;
599 }
600
601 // in First Check line page break and add page if needed
602 if (isset($object->lines[$i]->pagebreak) && $object->lines[$i]->pagebreak) {
603 // New page
604 $pdf->AddPage();
605 if (!empty($tplidx)) {
606 $pdf->useTemplate($tplidx);
607 }
608
609 $pdf->setPage($pdf->getNumPages());
610 $nexY = $curY = $tab_top_newpage;
611 }
612
613 $this->resetAfterColsLinePositionsData($nexY, $pdf->getPage());
614
615
616 $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
617 $pdf->SetTextColor(0, 0, 0);
618
619 // Define size of image if we need it
620 $imglinesize = array();
621 if (!empty($realpatharray[$i])) {
622 $imglinesize = pdf_getSizeForImage($realpatharray[$i]);
623 }
624
625 $pdf->setTopMargin($tab_top_newpage);
626 $pdf->setPageOrientation('', true, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
627 $pageposbefore = $pdf->getPage();
628 $curYBefore = $curY;
629
630 // Allows data in the first page if description is long enough to break in multiples pages
631 $showpricebeforepagebreak = getDolGlobalInt('MAIN_PDF_DATA_ON_FIRST_PAGE');
632 $posYAfterImage = 0;
633
634 if ($this->getColumnStatus('photo')) {
635 // We start with Photo of product line
636 $imageTopMargin = 1;
637 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
638 $pdf->AddPage('', '', true);
639 if (!empty($tplidx)) {
640 $pdf->useTemplate($tplidx);
641 }
642 $pdf->setPage($pageposbefore + 1);
643 $pdf->setPageOrientation('', true, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
644 $curY = $tab_top_newpage;
645 $showpricebeforepagebreak = 0;
646 }
647
648 // 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
649 //$pdf->setPageOrientation('', 0, $heightforfooter + $heightforfreetext); // The only function to edit the bottom margin of current page to set it.
650
651 // @phan-suppress-next-line PhanTypeMismatchProperty
652 if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height'])) {
653 $pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY + $imageTopMargin, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi
654 // $pdf->Image does not increase value return by getY, so we save it manually
655 $posYAfterImage = $curY + $imglinesize['height'];
656 $this->setAfterColsLinePositionsData('photo', $posYAfterImage, $pdf->getPage());
657 }
658 }
659
660 // restore Page orientation for text
661 $pdf->setPageOrientation('', true, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
662
663 // Description of product line
664 if ($this->getColumnStatus('desc')) {
665 if ($object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
666 $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc);
667 $this->setAfterColsLinePositionsData('desc', $pdf->GetY(), $pdf->getPage());
668 } else {
669 $bg_color = colorStringToArray(getDolGlobalString("SUBTOTAL_BACK_COLOR_LEVEL_".abs($object->lines[$i]->qty)));
670 pdf_render_subtotals($pdf, $this, $curY, $object, $i, $outputlangs, $hideref, $hidedesc, $bg_color, true, true);
671 }
672 }
673
674 $afterPosData = $this->getMaxAfterColsLinePositionsData();
675 $pdf->setPage($pageposbefore);
676 $pdf->setTopMargin($this->marge_haute);
677 $pdf->setPageOrientation('', false, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
678
679 // We suppose that a too long description or photo were moved completely on next page
680 if ($afterPosData['page'] > $pageposbefore && (empty($showpricebeforepagebreak) || ($curY + 4) > ($this->page_hauteur - $heightforfooter))) {
681 $pdf->setPage($afterPosData['page']);
682 $curY = $tab_top_newpage;
683 }
684
685 $pdf->SetFont('', '', $default_font_size - 1); // We reposition the default font
686
687 // Line position
688 if ($this->getColumnStatus('position')) {
689 $this->printStdColumnContent($pdf, $curY, 'position', strval($linePosition));
690 }
691
692 // VAT Rate
693 if ($this->getColumnStatus('vat') && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
694 $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
695 $this->printStdColumnContent($pdf, $curY, 'vat', $vat_rate);
696 }
697
698 // Unit price before discount
699 if ($this->getColumnStatus('subprice') && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE && isset($pdf_sub_options['titleshowuponpdf'])) {
700 $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);
701 $this->printStdColumnContent($pdf, $curY, 'subprice', $up_excl_tax);
702 }
703
704 // Quantity
705 // Enough for 6 chars
706 if ($this->getColumnStatus('qty') && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
707 $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
708 $this->printStdColumnContent($pdf, $curY, 'qty', $qty);
709 }
710
711
712 // Unit
713 if ($this->getColumnStatus('unit') && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
714 $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails);
715 $this->printStdColumnContent($pdf, $curY, 'unit', $unit);
716 }
717
718 // Discount on line
719 if ($this->getColumnStatus('discount') && $object->lines[$i]->remise_percent && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
720 $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);
721 $this->printStdColumnContent($pdf, $curY, 'discount', $remise_percent);
722 }
723
724 // Total excl tax line (HT)
725 if ($this->getColumnStatus('totalexcltax')) {
726 if ($object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE && isset($pdf_sub_options['titleshowtotalexludingvatonpdf'])) {
727 $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails);
728 $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax);
729 } elseif ($object->lines[$i]->qty < 0 && isset($sub_options['subtotalshowtotalexludingvatonpdf'])) {
730 if (isModEnabled('multicurrency') && $object->multicurrency_code != getDolCurrency()) {
731 $total_excl_tax = $object->getSubtotalLineMulticurrencyAmount($object->lines[$i]);
732 } else {
733 $total_excl_tax = $object->getSubtotalLineAmount($object->lines[$i]);
734 }
735 $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax);
736 }
737 }
738
739 // Total with tax line (TTC)
740 if ($this->getColumnStatus('totalincltax')) {
741 $total_incl_tax = pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails);
742 $this->printStdColumnContent($pdf, $curY, 'totalincltax', $total_incl_tax);
743 }
744
745 // Extrafields
746 if (!empty($object->lines[$i]->array_options)) {
747 foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) {
748 if ($this->getColumnStatus($extrafieldColKey)) {
749 $extrafieldValue = $this->getExtrafieldContent($object->lines[$i], $extrafieldColKey, $outputlangs);
750 $this->printStdColumnContent($pdf, $curY, $extrafieldColKey, $extrafieldValue);
751 $this->setAfterColsLinePositionsData('options_'.$extrafieldColKey, $pdf->GetY(), $pdf->getPage());
752 }
753 }
754 }
755
756 $afterPosData = $this->getMaxAfterColsLinePositionsData();
757 $parameters = array(
758 'object' => $object,
759 'i' => $i,
760 'pdf' => & $pdf,
761 'curY' => & $curY,
762 'nexY' => & $afterPosData['y'], // for backward module hook compatibility Y will be accessible by $object->getMaxAfterColsLinePositionsData()
763 'outputlangs' => $outputlangs,
764 'hidedetails' => $hidedetails
765 );
766 $reshook = $hookmanager->executeHooks('printPDFline', $parameters, $this); // Note that $object may have been modified by hook
767
768
769 // Collection of totals by value of vat in $this->tva["rate"] = total_tva
770 if (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) {
771 $tvaligne = $object->lines[$i]->multicurrency_total_tva;
772 } else {
773 $tvaligne = $object->lines[$i]->total_tva;
774 }
775
776 $localtax1ligne = $object->lines[$i]->total_localtax1;
777 $localtax2ligne = $object->lines[$i]->total_localtax2;
778 $localtax1_rate = $object->lines[$i]->localtax1_tx;
779 $localtax2_rate = $object->lines[$i]->localtax2_tx;
780 $localtax1_type = $object->lines[$i]->localtax1_type;
781 $localtax2_type = $object->lines[$i]->localtax2_type;
782
783 $vatrate = (string) $object->lines[$i]->tva_tx;
784
785 // Retrieve type from database for backward compatibility with old records
786 if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined
787 && (!empty($localtax1_rate) || !empty($localtax2_rate))) { // and there is local tax
788 $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $object->thirdparty, $mysoc);
789 $localtax1_type = isset($localtaxtmp_array[0]) ? $localtaxtmp_array[0] : '';
790 $localtax2_type = isset($localtaxtmp_array[2]) ? $localtaxtmp_array[2] : '';
791 }
792
793 // retrieve global local tax
794 if ($localtax1_type && $localtax1ligne != 0) {
795 if (empty($this->localtax1[$localtax1_type][$localtax1_rate])) {
796 $this->localtax1[$localtax1_type][$localtax1_rate] = $localtax1ligne;
797 } else {
798 $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne;
799 }
800 }
801 if ($localtax2_type && $localtax2ligne != 0) {
802 if (empty($this->localtax2[$localtax2_type][$localtax2_rate])) {
803 $this->localtax2[$localtax2_type][$localtax2_rate] = $localtax2ligne;
804 } else {
805 $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne;
806 }
807 }
808
809 if (($object->lines[$i]->info_bits & 0x01) == 0x01) {
810 $vatrate .= '*';
811 }
812
813 // Fill $this->tva and $this->tva_array
814 if (!isset($this->tva[$vatrate])) {
815 $this->tva[$vatrate] = 0;
816 }
817 $this->tva[$vatrate] += $tvaligne;
818 $vatcode = $object->lines[$i]->vat_src_code;
819 if (empty($this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'])) {
820 $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] = 0;
821 }
822 $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')] = array('vatrate' => $vatrate, 'vatcode' => $vatcode, 'amount' => $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] + $tvaligne);
823
824 $afterPosData = $this->getMaxAfterColsLinePositionsData();
825 $pdf->setPage($afterPosData['page']);
826 $nexY = $afterPosData['y'];
827
828 // Add line
829 if (getDolGlobalString('MAIN_PDF_DASH_BETWEEN_LINES') && $i < ($nblines - 1) && $afterPosData['y'] < $this->page_hauteur - $heightforfooter - 5) {
830 $pdf->SetLineStyle(array('dash' => '1,1', 'color' => array(80, 80, 80)));
831 //$pdf->SetDrawColor(190,190,200);
832 $pdf->line($this->marge_gauche, $nexY, $this->page_largeur - $this->marge_droite, $nexY);
833 $pdf->SetLineStyle(array('dash' => 0));
834 }
835
836 $nexY += 0; // Add space between lines
837 }
838
839 // Add last page for document footer if there are not enough size left
840 $afterPosData = $this->getMaxAfterColsLinePositionsData();
841 if (isset($afterPosData['y']) && $afterPosData['y'] > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) {
842 $pdf->AddPage();
843 if (!empty($tplidx)) {
844 $pdf->useTemplate($tplidx);
845 }
846 $pagenb++;
847 $pdf->setPage($pagenb);
848 }
849
850 // Draw table frames and columns borders
851 $drawTabNumbPage = $pdf->getNumPages();
852 for ($i = $pageposbeforeprintlines; $i <= $drawTabNumbPage; $i++) {
853 $pdf->setPage($i);
854 // reset page orientation each loop to override it if it was changed
855 $pdf->setPageOrientation('', false, 0); // The only function to edit the bottom margin of current page to set it.
856
857 $drawTabHideTop = $hidetop;
858 $drawTabTop = $tab_top_newpage;
859 $drawTabBottom = $this->page_hauteur - $heightforfooter;
860 $hideBottom = 0; // TODO understand why it change to 1 or 0 during process
861
862 if ($i == $pageposbeforeprintlines) {
863 // first page need to start after notes
864 $drawTabTop = $tab_top;
865 } elseif (!$drawTabHideTop) {
866 if (getDolGlobalInt('MAIN_PDF_ENABLE_COL_HEAD_TITLE_REPEAT')) {
867 $drawTabTop -= $this->tabTitleHeight;
868 } else {
869 $drawTabHideTop = 1;
870 }
871 }
872
873 // last page need to include document footer
874 if ($i == $pdf->getNumPages()) {
875 // remove document footer height to tab bottom position
876 $drawTabBottom -= $heightforfreetext + $heightforinfotot;
877 }
878
879 $drawTabHeight = $drawTabBottom - $drawTabTop;
880 $this->_tableau($pdf, $drawTabTop, $drawTabHeight, 0, $outputlangs, $drawTabHideTop, $hideBottom, $object->multicurrency_code, $outputlangsbis);
881
882 $hideFreeText = $i != $pdf->getNumPages() ? 1 : 0; // Display free text only in last page
883 $this->_pagefoot($pdf, $object, $outputlangs, $hideFreeText);
884
885 $pdf->setPage($i); // in case of _pagefoot or _tableau change it
886
887 // reset page orientation each loop to override it if it was changed by _pagefoot or _tableau change it
888 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
889
890 // Don't print head on first page ($pageposbeforeprintlines) because already added previously
891 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') && $i != $pageposbeforeprintlines) {
892 $this->_pagehead($pdf, $object, 0, $outputlangs);
893 }
894 if (!empty($tplidx)) {
895 $pdf->useTemplate($tplidx);
896 }
897 }
898
899 // reset text color before print footers
900 $pdf->SetTextColor(0, 0, 0);
901
902 $pdf->setPage($pdf->getNumPages());
903
904 $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
905
906 // Display infos area
907 $posy = $this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs);
908
909 // Display total zone
910 $posy = $this->drawTotalTable($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs);
911
912
913 // Add number of pages in footer
914 if (method_exists($pdf, 'AliasNbPages')) {
915 $pdf->AliasNbPages(); // @phan-suppress-current-line PhanUndeclaredMethod
916 }
917
918 // Add terms to sale
919 $termsofsalefilename = getDolGlobalString('MAIN_INFO_ORDER_TERMSOFSALE');
920 if (getDolGlobalInt('MAIN_PDF_ADD_TERMSOFSALE_ORDER') && $termsofsalefilename) {
921 $termsofsale = $conf->order->dir_output.'/'.$termsofsalefilename;
922 if (!empty($conf->order->multidir_output[$conf->entity])) {
923 $termsofsale = $conf->order->multidir_output[$conf->entity].'/'.$termsofsalefilename;
924 }
925 if (file_exists($termsofsale) && is_readable($termsofsale)) {
926 $pagecount = $pdf->setSourceFile($termsofsale);
927 for ($i = 1; $i <= $pagecount; $i++) {
928 $tplIdx = $pdf->importPage($i);
929 if ($tplIdx !== false) {
930 $s = $pdf->getTemplatesize($tplIdx);
931 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
932 $pdf->useTemplate($tplIdx);
933 } else {
934 setEventMessages(null, array($termsofsale.' cannot be added, probably protected PDF'), 'warnings');
935 }
936 }
937 }
938 }
939
940 $pdf->Close();
941
942 $pdf->Output($file, 'F');
943
944 // Add pdfgeneration hook
945 $hookmanager->initHooks(array('pdfgeneration'));
946 $parameters = array('file' => $file, 'object' => $object, 'outputlangs' => $outputlangs);
947 global $action;
948 $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
949 $this->warnings = $hookmanager->warnings;
950 if ($reshook < 0) {
951 $this->error = $hookmanager->error;
952 $this->errors = $hookmanager->errors;
953 dolChmod($file);
954 return -1;
955 }
956
957 dolChmod($file);
958
959 $this->result = array('fullpath' => $file);
960
961 return 1; // No error
962 } else {
963 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
964 return 0;
965 }
966 } else {
967 $this->error = $langs->transnoentities("ErrorConstantNotDefined", "COMMANDE_OUTPUTDIR");
968 return 0;
969 }
970 }
971
981 protected function drawPaymentsTable(&$pdf, $object, $posy, $outputlangs)
982 {
983 return 0;
984 }
985
995 protected function drawInfoTable(&$pdf, $object, $posy, $outputlangs)
996 {
997 global $conf, $mysoc;
998 $default_font_size = pdf_getPDFFontSize($outputlangs);
999
1000 $pdf->SetFont('', '', $default_font_size - 1);
1001
1002 $diffsizetitle = getDolGlobalInt('PDF_DIFFSIZE_TITLE', 3);
1003
1004 // If France, show VAT mention if not applicable
1005 if ($this->emetteur->country_code == 'FR' && empty($mysoc->tva_assuj)) {
1006 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1007 $pdf->SetXY($this->marge_gauche, $posy);
1008 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', false);
1009
1010 $posy = $pdf->GetY() + 4;
1011 }
1012
1013 $posxval = 52;
1014
1015 $diffsizetitle = getDolGlobalInt('PDF_DIFFSIZE_TITLE', 3);
1016
1017 // Show payments conditions
1018 if ($object->cond_reglement_code || $object->cond_reglement) {
1019 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1020 $pdf->SetXY($this->marge_gauche, $posy);
1021 $titre = $outputlangs->transnoentities("PaymentConditions").':';
1022 $pdf->MultiCell(43, 4, $titre, 0, 'L');
1023
1024 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1025 $pdf->SetXY($posxval, $posy);
1026 $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);
1027 $lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
1028 if ($object->deposit_percent > 0) {
1029 $lib_condition_paiement = str_replace('__DEPOSIT_PERCENT__', (string) $object->deposit_percent, $lib_condition_paiement);
1030 }
1031 $pdf->MultiCell(67, 4, $lib_condition_paiement, 0, 'L');
1032
1033 $posy = $pdf->GetY() + 3;
1034 }
1035
1036 // Check a payment mode is defined
1037 /* Not used with orders
1038 if (empty($object->mode_reglement_code)
1039 && ! $conf->global->FACTURE_CHQ_NUMBER
1040 && ! $conf->global->FACTURE_RIB_NUMBER)
1041 {
1042 $pdf->SetXY($this->marge_gauche, $posy);
1043 $pdf->SetTextColor(200,0,0);
1044 $pdf->SetFont('','B', $default_font_size - 2);
1045 $pdf->MultiCell(80, 3, $outputlangs->transnoentities("ErrorNoPaiementModeConfigured"),0,'L',0);
1046 $pdf->SetTextColor(0,0,0);
1047
1048 $posy=$pdf->GetY()+1;
1049 }
1050 */
1051 /* TODO
1052 else if (!empty($object->availability_code))
1053 {
1054 $pdf->SetXY($this->marge_gauche, $posy);
1055 $pdf->SetTextColor(200,0,0);
1056 $pdf->SetFont('','B', $default_font_size - 2);
1057 $pdf->MultiCell(80, 3, $outputlangs->transnoentities("AvailabilityPeriod").': '.,0,'L',0);
1058 $pdf->SetTextColor(0,0,0);
1059
1060 $posy=$pdf->GetY()+1;
1061 }*/
1062
1063 // Show planned date of delivery
1064 if (!empty($object->delivery_date)) {
1065 $outputlangs->load("sendings");
1066 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1067 $pdf->SetXY($this->marge_gauche, $posy);
1068 $titre = $outputlangs->transnoentities("DateDeliveryPlanned").':';
1069 $pdf->MultiCell(80, 4, $titre, 0, 'L');
1070 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1071 $pdf->SetXY($posxval, $posy);
1072 $dlp = dol_print_date($object->delivery_date, "daytext", false, $outputlangs, true);
1073 $pdf->MultiCell(80, 4, $dlp, 0, 'L');
1074
1075 $posy = $pdf->GetY() + 1;
1076 } elseif ($object->availability_code || $object->availability) { // Show availability conditions
1077 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1078 $pdf->SetXY($this->marge_gauche, $posy);
1079 $titre = $outputlangs->transnoentities("AvailabilityPeriod").':';
1080 $pdf->MultiCell(80, 4, $titre, 0, 'L');
1081 $pdf->SetTextColor(0, 0, 0);
1082 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1083 $pdf->SetXY($posxval, $posy);
1084 $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 : '');
1085 $lib_availability = str_replace('\n', "\n", $lib_availability);
1086 $pdf->MultiCell(80, 4, $lib_availability, 0, 'L');
1087
1088 $posy = $pdf->GetY() + 1;
1089 }
1090
1091 // Show payment mode
1092 if ($object->mode_reglement_code
1093 && $object->mode_reglement_code != 'CHQ'
1094 && $object->mode_reglement_code != 'VIR') {
1095 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1096 $pdf->SetXY($this->marge_gauche, $posy);
1097 $titre = $outputlangs->transnoentities("PaymentMode").':';
1098 $pdf->MultiCell(80, 5, $titre, 0, 'L');
1099
1100 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1101 $pdf->SetXY($posxval, $posy);
1102 $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);
1103 $pdf->MultiCell(80, 5, $lib_mode_reg, 0, 'L');
1104
1105 $posy = $pdf->GetY() + 2;
1106 }
1107
1108 // Show payment mode CHQ
1109 if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ') {
1110 // Si mode reglement non force ou si force a CHQ
1111 if (getDolGlobalString('FACTURE_CHQ_NUMBER')) {
1112 if (getDolGlobalInt('FACTURE_CHQ_NUMBER') > 0) {
1113 $account = new Account($this->db);
1114 $account->fetch(getDolGlobalString('FACTURE_CHQ_NUMBER'));
1115
1116 $pdf->SetXY($this->marge_gauche, $posy);
1117 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1118 $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $account->owner_name), 0, 'L', false);
1119 $posy = $pdf->GetY() + 1;
1120
1121 if (!getDolGlobalString('MAIN_PDF_HIDE_CHQ_ADDRESS')) {
1122 $pdf->SetXY($this->marge_gauche, $posy);
1123 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1124 $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', false);
1125 $posy = $pdf->GetY() + 2;
1126 }
1127 }
1128 if (getDolGlobalString('FACTURE_CHQ_NUMBER') == -1) {
1129 $pdf->SetXY($this->marge_gauche, $posy);
1130 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1131 $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $this->emetteur->name), 0, 'L', false);
1132 $posy = $pdf->GetY() + 1;
1133
1134 if (!getDolGlobalString('MAIN_PDF_HIDE_CHQ_ADDRESS')) {
1135 $pdf->SetXY($this->marge_gauche, $posy);
1136 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1137 $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', false);
1138 $posy = $pdf->GetY() + 2;
1139 }
1140 }
1141 }
1142 }
1143
1144 // If payment mode not forced or forced to VIR, show payment with BAN
1145 if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') {
1146 if ($object->fk_account > 0 || $object->fk_bank > 0 || getDolGlobalInt('FACTURE_RIB_NUMBER')) {
1147 $bankid = ($object->fk_account <= 0 ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account);
1148 if ($object->fk_bank > 0) {
1149 $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank
1150 }
1151 $account = new Account($this->db);
1152 $account->fetch($bankid);
1153
1154 $curx = $this->marge_gauche;
1155 $cury = $posy;
1156
1157 $posy = pdf_bank($pdf, $outputlangs, $curx, $cury, $account, 0, $default_font_size);
1158
1159 $posy += 2;
1160 }
1161 }
1162
1163 return $posy;
1164 }
1165
1166
1178 protected function drawTotalTable(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis = null)
1179 {
1180 global $conf, $mysoc, $hookmanager;
1181
1182 $default_font_size = pdf_getPDFFontSize($outputlangs);
1183
1184 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE') && $outputlangs->defaultlang != getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
1185 $outputlangsbis = new Translate('', $conf);
1186 $outputlangsbis->setDefaultLang(getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE'));
1187 $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal"));
1188 $default_font_size--;
1189 }
1190
1191 $tab2_top = $posy;
1192 $tab2_hl = 4;
1193 $pdf->SetFont('', '', $default_font_size - 1);
1194
1195 // Total table
1196 $col1x = 120;
1197 $col2x = 170;
1198 if ($this->page_largeur < 210) { // To work with US executive format
1199 $col2x -= 20;
1200 }
1201 $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
1202
1203 $useborder = 0;
1204 $index = 0;
1205
1206 // Get Total HT
1207 $total_ht = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1 ? $object->multicurrency_total_ht : $object->total_ht);
1208
1209 // Total discount
1210 $total_discount_on_lines = 0;
1211 $multicurrency_total_discount_on_lines = 0;
1212 foreach ($object->lines as $i => $line) {
1213 $resdiscount = pdfGetLineTotalDiscountAmount($object, $i, $outputlangs, 2);
1214 $multicurrency_resdiscount = pdfGetLineTotalDiscountAmount($object, $i, $outputlangs, 2, 1);
1215
1216 $total_discount_on_lines += (is_numeric($resdiscount) ? $resdiscount : 0);
1217 $multicurrency_total_discount_on_lines += (is_numeric($multicurrency_resdiscount) ? $multicurrency_resdiscount : 0);
1218 // If line was a negative line, we do not count the discount as a discount
1219 if ($line->total_ht < 0) {
1220 $total_discount_on_lines += -$line->total_ht;
1221 $multicurrency_total_discount_on_lines += -$line->multicurrency_total_ht;
1222 }
1223 }
1224
1225 if ($total_discount_on_lines > 0) {
1226 if ($this->showAmountBeforeDiscount) {
1227 // Show total NET before discount
1228 $pdf->SetFillColor(255, 255, 255);
1229 $pdf->SetXY($col1x, $tab2_top);
1230 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHTBeforeDiscount") . (is_object($outputlangsbis) ? ' / ' . $outputlangsbis->transnoentities("TotalHTBeforeDiscount") : ''), 0, 'L', true);
1231 $pdf->SetXY($col2x, $tab2_top);
1232
1233 $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));
1234 $pdf->MultiCell($largcol2, $tab2_hl, price($total_before_discount_to_show, 0, $outputlangs), 0, 'R', true);
1235
1236 $index++;
1237 }
1238
1239 if ($this->showDiscountAmount) {
1240 $pdf->SetFillColor(255, 255, 255);
1241 $pdf->SetXY($col1x, $tab2_top + $tab2_hl);
1242 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalDiscount") . (is_object($outputlangsbis) ? ' / ' . $outputlangsbis->transnoentities("TotalDiscount") : ''), 0, 'L', true);
1243 $pdf->SetXY($col2x, $tab2_top + $tab2_hl);
1244
1245 $total_discount_to_show = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $multicurrency_total_discount_on_lines : $total_discount_on_lines);
1246 $pdf->MultiCell($largcol2, $tab2_hl, price($total_discount_to_show, 0, $outputlangs), 0, 'R', true);
1247
1248 $index++;
1249 }
1250 }
1251
1252 // Total HT
1253 $pdf->SetFillColor(255, 255, 255);
1254 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1255 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("TotalHT") : ''), 0, 'L', true);
1256 $total_ht = ((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht);
1257 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1258 $pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + (!empty($object->remise) ? $object->remise : 0), 0, $outputlangs), 0, 'R', true);
1259
1260 // Show VAT by rates and total
1261 $pdf->SetFillColor(248, 248, 248);
1262
1263 $total_ttc = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
1264 $total_ttc_origin = $object->total_ttc;
1265
1266 $this->atleastoneratenotnull = 0;
1267 if (!getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT')) {
1268 $tvaisnull = (!empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000']));
1269 if (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL') && $tvaisnull) {
1270 // Nothing to do
1271 } else {
1272 //Local tax 1 before VAT
1273 foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1274 if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1275 continue;
1276 }
1277 foreach ($localtax_rate as $tvakey => $tvaval) {
1278 if ($tvakey != 0) { // On affiche pas taux 0
1279 //$this->atleastoneratenotnull++;
1280 $index++;
1281 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1282
1283 $tvacompl = '';
1284 if (preg_match('/\*/', (string) $tvakey)) {
1285 $tvakey = str_replace('*', '', (string) $tvakey);
1286 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1287 }
1288 $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : '');
1289 $totalvat .= ' ';
1290
1291 if (getDolGlobalString('PDF_LOCALTAX1_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') {
1292 $totalvat .= $tvacompl;
1293 } else {
1294 $totalvat .= vatrate((string) abs((float) $tvakey), true).$tvacompl;
1295 }
1296
1297 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1298
1299 $total_localtax = ((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1300
1301 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1302 $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', true);
1303 }
1304 }
1305 }
1306
1307 //Local tax 2 before VAT
1308 foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1309 if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1310 continue;
1311 }
1312 foreach ($localtax_rate as $tvakey => $tvaval) {
1313 if ($tvakey != 0) { // On affiche pas taux 0
1314 //$this->atleastoneratenotnull++;
1315
1316 $index++;
1317 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1318
1319 $tvacompl = '';
1320 if (preg_match('/\*/', (string) $tvakey)) {
1321 $tvakey = str_replace('*', '', (string) $tvakey);
1322 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1323 }
1324 $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : '');
1325 $totalvat .= ' ';
1326
1327 if (getDolGlobalString('PDF_LOCALTAX2_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') {
1328 $totalvat .= $tvacompl;
1329 } else {
1330 $totalvat .= vatrate((string) abs((float) $tvakey), true).$tvacompl;
1331 }
1332
1333 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1334
1335 $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1336
1337 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1338 $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', true);
1339 }
1340 }
1341 }
1342
1343 // VAT
1344 foreach ($this->tva_array as $tvakey => $tvaval) {
1345 if ($tvakey != 0) { // On affiche pas taux 0
1346 $this->atleastoneratenotnull++;
1347
1348 $index++;
1349 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1350
1351 $tvacompl = '';
1352 if (preg_match('/\*/', $tvakey)) {
1353 $tvakey = str_replace('*', '', $tvakey);
1354 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1355 }
1356 $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalVAT", $mysoc->country_code) : '');
1357 $totalvat .= ' ';
1358 if (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'rateonly') {
1359 $totalvat .= vatrate((string) $tvaval['vatrate'], true).$tvacompl;
1360 } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'codeonly') {
1361 $totalvat .= $tvaval['vatcode'].$tvacompl;
1362 } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') {
1363 $totalvat .= $tvacompl;
1364 } else {
1365 $totalvat .= vatrate((string) $tvaval['vatrate'], true).($tvaval['vatcode'] ? ' ('.$tvaval['vatcode'].')' : '').$tvacompl;
1366 }
1367 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1368
1369 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1370 $pdf->MultiCell($largcol2, $tab2_hl, price(price2num($tvaval['amount'], 'MT'), 0, $outputlangs), 0, 'R', true);
1371 }
1372 }
1373
1374 //Local tax 1 after VAT
1375 foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1376 if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1377 continue;
1378 }
1379
1380 foreach ($localtax_rate as $tvakey => $tvaval) {
1381 if ($tvakey != 0) { // On affiche pas taux 0
1382 //$this->atleastoneratenotnull++;
1383
1384 $index++;
1385 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1386
1387 $tvacompl = '';
1388 if (preg_match('/\*/', (string) $tvakey)) {
1389 $tvakey = str_replace('*', '', (string) $tvakey);
1390 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1391 }
1392 $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : '');
1393 $totalvat .= ' ';
1394
1395 if (getDolGlobalString('PDF_LOCALTAX1_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') {
1396 $totalvat .= $tvacompl;
1397 } else {
1398 $totalvat .= vatrate((string) abs((float) $tvakey), true).$tvacompl;
1399 }
1400
1401 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1402
1403 $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1404
1405 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1406 $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', true);
1407 }
1408 }
1409 }
1410
1411 //Local tax 2 after VAT
1412 foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1413 if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1414 continue;
1415 }
1416
1417 foreach ($localtax_rate as $tvakey => $tvaval) {
1418 // retrieve global local tax
1419 if ($tvakey != 0) { // On affiche pas taux 0
1420 //$this->atleastoneratenotnull++;
1421
1422 $index++;
1423 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1424
1425 $tvacompl = '';
1426 if (preg_match('/\*/', (string) $tvakey)) {
1427 $tvakey = str_replace('*', '', (string) $tvakey);
1428 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1429 }
1430 $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : '');
1431 $totalvat .= ' ';
1432
1433 if (getDolGlobalString('PDF_LOCALTAX2_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') {
1434 $totalvat .= $tvacompl;
1435 } else {
1436 $totalvat .= vatrate((string) abs((float) $tvakey), true).$tvacompl;
1437 }
1438
1439 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1440
1441 $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1442
1443 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1444 $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', true);
1445 }
1446 }
1447 }
1448 //}
1449
1450 // Total TTC
1451 $index++;
1452 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1453 $pdf->SetTextColor(0, 0, 60);
1454 $pdf->SetFillColor(224, 224, 224);
1455 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalTTC", $mysoc->country_code) : ''), $useborder, 'L', true);
1456
1457 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1458 if (!isModEnabled("multicurrency") || $object->multicurrency_tx == 1 || getDolGlobalInt('MULTICURRENCY_SHOW_ALSO_MAIN_CURRENCY_ON_PDF') == 0) {
1459 $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', true);
1460 } else {
1461 $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', true);
1462
1463 //$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');
1464 $index++;
1465 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1466 $pdf->SetTextColor(0, 0, 60);
1467 $pdf->SetFillColor(224, 224, 224);
1468 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("TotalTTC") : '').' ('.$outputlangs->getCurrencySymbol($mysoc->currency_code).')', $useborder, 'L', true);
1469
1470 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1471 $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc_origin, 0, $outputlangs, 1, -1, -1, $mysoc->currency_code), $useborder, 'L', true);
1472 }
1473 }
1474 }
1475
1476 $pdf->SetTextColor(0, 0, 0);
1477
1478 $creditnoteamount = 0;
1479 $depositsamount = 0;
1480 //$creditnoteamount=$object->getSumCreditNotesUsed();
1481 //$depositsamount=$object->getSumDepositsUsed();
1482 //print "x".$creditnoteamount."-".$depositsamount;exit;
1483 $resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT');
1484 if (!empty($object->paye)) {
1485 $resteapayer = 0;
1486 }
1487
1488 if ($deja_regle > 0) {
1489 // Already paid + Deposits
1490 $index++;
1491
1492 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1493 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("AlreadyPaid") : ''), 0, 'L', false);
1494 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1495 $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', false);
1496
1497 $index++;
1498 $pdf->SetTextColor(0, 0, 60);
1499 $pdf->SetFillColor(224, 224, 224);
1500 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1501 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("RemainderToPay") : ''), $useborder, 'L', true);
1502
1503 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1504 $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', true);
1505
1506 $pdf->SetFont('', '', $default_font_size - 1);
1507 $pdf->SetTextColor(0, 0, 0);
1508 }
1509
1510 $parameters = array('pdf' => &$pdf, 'object' => &$object, 'outputlangs' => $outputlangs, 'index' => &$index, 'posy' => $posy);
1511
1512 $reshook = $hookmanager->executeHooks('afterPDFTotalTable', $parameters, $this); // Note that $action and $object may have been modified by some hooks
1513 if ($reshook < 0) {
1514 $this->error = $hookmanager->error;
1515 $this->errors = $hookmanager->errors;
1516 }
1517
1518 $index++;
1519 return ($tab2_top + ($tab2_hl * $index));
1520 }
1521
1522 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1537 protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '', $outputlangsbis = null)
1538 {
1539 global $conf;
1540
1541 // Force to disable hidetop and hidebottom
1542 $hidebottom = 0;
1543 if ($hidetop) {
1544 $hidetop = -1;
1545 }
1546
1547 $currency = !empty($currency) ? $currency : getDolCurrency();
1548 $default_font_size = pdf_getPDFFontSize($outputlangs);
1549
1550 // Amount in (at tab_top - 1)
1551 $pdf->SetTextColor(0, 0, 0);
1552 $pdf->SetFont('', '', $default_font_size - 2);
1553
1554 if (empty($hidetop)) {
1555 $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
1556 if (getDolGlobalInt('PDF_USE_ALSO_LANGUAGE_CODE') && is_object($outputlangsbis)) {
1557 $titre .= ' - '.$outputlangsbis->transnoentities("AmountInCurrency", $outputlangsbis->transnoentitiesnoconv("Currency".$currency));
1558 }
1559
1560 $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
1561 $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
1562
1563 //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
1564 if (getDolGlobalString('MAIN_PDF_TITLE_BACKGROUND_COLOR')) {
1565 $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')));
1566 }
1567 }
1568
1569 $pdf->SetDrawColor(128, 128, 128);
1570 $pdf->SetFont('', '', $default_font_size - 1);
1571
1572 // Output Rect
1573 $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
1574
1575
1576 $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop);
1577
1578 if (empty($hidetop)) {
1579 $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
1580 }
1581 }
1582
1583 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1584 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1596 protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null, $titlekey = "PdfOrderTitle")
1597 {
1598 // phpcs:enable
1599 global $conf, $langs, $hookmanager, $mysoc;
1600
1601 $ltrdirection = 'L';
1602 if ($outputlangs->trans("DIRECTION") == 'rtl') {
1603 $ltrdirection = 'R';
1604 }
1605
1606 // Load traductions files required by page
1607 $outputlangs->loadLangs(array("main", "bills", "propal", "orders", "companies"));
1608
1609 $default_font_size = pdf_getPDFFontSize($outputlangs);
1610
1611 pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
1612
1613 $pdf->SetTextColor(0, 0, 60);
1614 $pdf->SetFont('', 'B', $default_font_size + 3);
1615
1616 $w = 100;
1617
1618 $posy = $this->marge_haute;
1619 $posx = $this->page_largeur - $this->marge_droite - $w;
1620
1621 $pdf->SetXY($this->marge_gauche, $posy);
1622
1623 // Logo
1624 if (!getDolGlobalInt('PDF_DISABLE_MYCOMPANY_LOGO')) {
1625 if ($this->emetteur->logo) {
1626 $logodir = $conf->mycompany->dir_output;
1627 if (!empty(getMultidirOutput($mysoc, 'mycompany'))) {
1628 $logodir = getMultidirOutput($mysoc, 'mycompany');
1629 }
1630 if (!getDolGlobalInt('MAIN_PDF_USE_LARGE_LOGO')) {
1631 $logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
1632 } else {
1633 $logo = $logodir.'/logos/'.$this->emetteur->logo;
1634 }
1635 if (is_readable($logo)) {
1636 $height = pdf_getHeightForLogo($logo);
1637 $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
1638 } else {
1639 $pdf->SetTextColor(200, 0, 0);
1640 $pdf->SetFont('', 'B', $default_font_size - 2);
1641 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
1642 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
1643 }
1644 } else {
1645 $text = $this->emetteur->name;
1646 $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
1647 }
1648 }
1649
1650 $pdf->SetFont('', 'B', $default_font_size + 3);
1651 $pdf->SetXY($posx, $posy);
1652 $pdf->SetTextColor(0, 0, 60);
1653 $title = $outputlangs->transnoentities($titlekey);
1654 if (getDolGlobalInt('PDF_USE_ALSO_LANGUAGE_CODE') && is_object($outputlangsbis)) {
1655 $title .= ' - ';
1656 $title .= $outputlangsbis->transnoentities($titlekey);
1657 }
1658 $title .= ' '.$outputlangs->convToOutputCharset($object->ref);
1659 if ($object->status == $object::STATUS_DRAFT) {
1660 $pdf->SetTextColor(128, 0, 0);
1661 $title .= ' - '.$outputlangs->transnoentities("NotValidated");
1662 }
1663
1664 $pdf->MultiCell($w, 3, $title, '', 'R');
1665
1666 $pdf->SetFont('', 'B', $default_font_size);
1667
1668 /*
1669 $posy += 5;
1670 $pdf->SetXY($posx, $posy);
1671 $pdf->SetTextColor(0, 0, 60);
1672 $textref = $outputlangs->transnoentities("Ref")." : ".$outputlangs->convToOutputCharset($object->ref);
1673 if ($object->statut == $object::STATUS_DRAFT) {
1674 $pdf->SetTextColor(128, 0, 0);
1675 $textref .= ' - '.$outputlangs->transnoentities("NotValidated");
1676 }
1677 $pdf->MultiCell($w, 4, $textref, '', 'R');
1678 */
1679
1680 $posy += 3;
1681 $pdf->SetFont('', '', $default_font_size - 2);
1682
1683 if ($object->ref_client) {
1684 $posy += 4;
1685 $pdf->SetXY($posx, $posy);
1686 $pdf->SetTextColor(0, 0, 60);
1687 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".dol_trunc($outputlangs->convToOutputCharset((string) $object->ref_client), 65), '', 'R');
1688 }
1689
1690 if (getDolGlobalInt('PDF_SHOW_PROJECT_TITLE')) {
1691 $object->fetchProject();
1692 if (!empty($object->project->ref)) {
1693 $posy += 3;
1694 $pdf->SetXY($posx, $posy);
1695 $pdf->SetTextColor(0, 0, 60);
1696 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->project->title), '', 'R');
1697 }
1698 }
1699
1700 if (getDolGlobalInt('PDF_SHOW_PROJECT')) {
1701 $object->fetchProject();
1702 if (!empty($object->project->ref)) {
1703 $outputlangs->load("projects");
1704 $posy += 3;
1705 $pdf->SetXY($posx, $posy);
1706 $pdf->SetTextColor(0, 0, 60);
1707 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefProject")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R');
1708 }
1709 }
1710
1711 $posy += 4;
1712
1713 $pdf->SetXY($posx, $posy);
1714 $pdf->SetTextColor(0, 0, 60);
1715 $title = $outputlangs->transnoentities("OrderDate");
1716 if (getDolGlobalInt('PDF_USE_ALSO_LANGUAGE_CODE') && is_object($outputlangsbis)) {
1717 $title .= ' - '.$outputlangsbis->transnoentities("DateInvoice");
1718 }
1719 $pdf->MultiCell($w, 3, $title." : ".dol_print_date($object->date, "day", false, $outputlangs, true), '', 'R');
1720
1721 if (!getDolGlobalString('MAIN_PDF_HIDE_CUSTOMER_CODE') && !empty($object->thirdparty->code_client)) {
1722 $posy += 4;
1723 $pdf->SetXY($posx, $posy);
1724 $pdf->SetTextColor(0, 0, 60);
1725 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities((string) $object->thirdparty->code_client), '', 'R');
1726 }
1727
1728 if (!getDolGlobalString('MAIN_PDF_HIDE_CUSTOMER_ACCOUNTING_CODE') && !empty($object->thirdparty->code_compta_client)) {
1729 $posy += 4;
1730 $pdf->SetXY($posx, $posy);
1731 $pdf->SetTextColor(0, 0, 60);
1732 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerAccountancyCode")." : ".$outputlangs->transnoentities((string) $object->thirdparty->code_compta_client), '', 'R');
1733 }
1734
1735 // Get contact
1736 if (getDolGlobalInt('DOC_SHOW_FIRST_SALES_REP')) {
1737 $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1738 if (count($arrayidcontact) > 0) {
1739 $usertmp = new User($this->db);
1740 $usertmp->fetch($arrayidcontact[0]);
1741 $posy += 4;
1742 $pdf->SetXY($posx, $posy);
1743 $pdf->SetTextColor(0, 0, 60);
1744 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
1745 }
1746 }
1747
1748 $posy += 2;
1749
1750 $top_shift = 0;
1751 $shipp_shift = 0;
1752 // Show list of linked objects
1753 $current_y = $pdf->getY();
1754 $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size);
1755 if ($current_y < $pdf->getY()) {
1756 $top_shift = $pdf->getY() - $current_y;
1757 }
1758
1759 if ($showaddress) {
1760 // Sender properties
1761 $carac_emetteur = '';
1762 // Add internal contact of object if defined
1763 $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1764 if (count($arrayidcontact) > 0) {
1765 $object->fetch_user($arrayidcontact[0]);
1766 $labelbeforecontactname = ($outputlangs->transnoentities("FromContactName") != 'FromContactName' ? $outputlangs->transnoentities("FromContactName") : $outputlangs->transnoentities("Name"));
1767 $carac_emetteur .= ($carac_emetteur ? "\n" : '').$labelbeforecontactname." ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs));
1768 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ' (' : '';
1769 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && !empty($object->user->office_phone)) ? $object->user->office_phone : '';
1770 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ', ' : '';
1771 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT') && !empty($object->user->email)) ? $object->user->email : '';
1772 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ')' : '';
1773 $carac_emetteur .= "\n";
1774 }
1775
1776 $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
1777
1778 // Show sender
1779 $posy = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 40 : 42;
1780 $posy += $top_shift;
1781 $posx = $this->marge_gauche;
1782 if (getDolGlobalInt('MAIN_INVERT_SENDER_RECIPIENT')) {
1783 $posx = $this->page_largeur - $this->marge_droite - 80;
1784 }
1785
1786 $hautcadre = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 38 : 40;
1787 $widthrecbox = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 92 : 82;
1788
1789
1790 // Show sender frame
1791 if (!getDolGlobalString('MAIN_PDF_NO_SENDER_FRAME')) {
1792 $pdf->SetTextColor(0, 0, 0);
1793 $pdf->SetFont('', '', $default_font_size - 2);
1794 $pdf->SetXY($posx, $posy - 5);
1795 $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillFrom"), 0, $ltrdirection);
1796 $pdf->SetXY($posx, $posy);
1797 $pdf->SetFillColor(230, 230, 230);
1798 $pdf->RoundedRect($posx, $posy, $widthrecbox, $hautcadre, $this->corner_radius, '1234', 'F');
1799 $pdf->SetTextColor(0, 0, 60);
1800 }
1801
1802 // Show sender name
1803 if (!getDolGlobalString('MAIN_PDF_HIDE_SENDER_NAME')) {
1804 $pdf->SetXY($posx + 2, $posy + 3);
1805 $pdf->SetFont('', 'B', $default_font_size);
1806 $pdf->MultiCell($widthrecbox - 2, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, $ltrdirection);
1807 $posy = $pdf->getY();
1808 }
1809
1810 // Show sender information
1811 $pdf->SetXY($posx + 2, $posy);
1812 $pdf->SetFont('', '', $default_font_size - 1);
1813 $pdf->MultiCell($widthrecbox - 2, 4, $carac_emetteur, 0, $ltrdirection);
1814
1815 // If CUSTOMER contact defined, we use it
1816 $usecontact = false;
1817 $arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
1818 if (count($arrayidcontact) > 0) {
1819 $usecontact = true;
1820 $result = $object->fetch_contact($arrayidcontact[0]);
1821 }
1822
1823 //Recipient name
1824 if ($usecontact && $object->contact->socid != $object->thirdparty->id && getDolGlobalInt('MAIN_USE_COMPANY_NAME_OF_CONTACT')) {
1825 $thirdparty = $object->contact;
1826 } else {
1827 $thirdparty = $object->thirdparty;
1828 }
1829
1830 if (is_object($thirdparty)) {
1831 $carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);
1832 } else {
1833 $carac_client_name = '';
1834 }
1835
1836 $mode = 'target';
1837 $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), ($usecontact ? 1 : 0), $mode, $object);
1838
1839 // Show recipient
1840 $widthrecbox = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 92 : 100;
1841 if ($this->page_largeur < 210) {
1842 $widthrecbox = 84; // To work with US executive format
1843 }
1844 $posy = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 40 : 42;
1845 $posy += $top_shift;
1846 $posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
1847 if (getDolGlobalInt('MAIN_INVERT_SENDER_RECIPIENT')) {
1848 $posx = $this->marge_gauche;
1849 }
1850
1851 // Show recipient frame
1852 if (!getDolGlobalString('MAIN_PDF_NO_RECIPENT_FRAME')) {
1853 $pdf->SetTextColor(0, 0, 0);
1854 $pdf->SetFont('', '', $default_font_size - 2);
1855 $pdf->SetXY($posx + 2, $posy - 5);
1856 $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo"), 0, $ltrdirection);
1857 $pdf->RoundedRect($posx, $posy, $widthrecbox, $hautcadre, $this->corner_radius, '1234', 'D');
1858 }
1859
1860 // Show recipient name
1861 $pdf->SetXY($posx + 2, $posy + 3);
1862 $pdf->SetFont('', 'B', $default_font_size);
1863 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
1864 $pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, $ltrdirection);
1865
1866 $posy = $pdf->getY();
1867
1868 // Show recipient information
1869 $pdf->SetFont('', '', $default_font_size - 1);
1870 $pdf->SetXY($posx + 2, $posy);
1871 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
1872 $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, $ltrdirection);
1873
1874 // Show shipping address
1875 if (getDolGlobalInt('SALES_ORDER_SHOW_SHIPPING_ADDRESS')) {
1876 $idaddressshipping = $object->getIdContact('external', 'SHIPPING');
1877
1878 if (!empty($idaddressshipping)) {
1879 $contactshipping = $object->fetch_contact($idaddressshipping[0]);
1880 $companystatic = new Societe($this->db);
1881 $companystatic->fetch($object->contact->fk_soc);
1882 $carac_client_name_shipping = (($object->contact instanceof Contact) ? pdfBuildThirdpartyName($object->contact, $outputlangs) : '');
1883 $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $companystatic, $object->contact, 1, 'target', $object);
1884 } else {
1885 $carac_client_name_shipping = ($object->thirdparty instanceof Societe ? pdfBuildThirdpartyName($object->thirdparty, $outputlangs) : '');
1886 $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'target', $object);
1887 }
1888 if (!empty($carac_client_shipping)) {
1889 $posy += $hautcadre;
1890
1891 $hautcadre -= 10; // Height for the shipping address does not need to be as high as main box
1892
1893 // Show shipping frame
1894 $pdf->SetXY($posx + 2, $posy - 5);
1895 $pdf->SetFont('', '', $default_font_size - 2);
1896 $pdf->MultiCell($widthrecbox, 0, $outputlangs->transnoentities('ShippingTo'), 0, 'L', false);
1897 $pdf->RoundedRect($posx, $posy, $widthrecbox, $hautcadre, $this->corner_radius, '1234', 'D');
1898
1899 // Show shipping name
1900 $pdf->SetXY($posx + 2, $posy + 1);
1901 $pdf->SetFont('', 'B', $default_font_size);
1902 $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_name_shipping, '', 'L');
1903
1904 $posy = $pdf->getY();
1905
1906 // Show shipping information
1907 $pdf->SetXY($posx + 2, $posy);
1908 $pdf->SetFont('', '', $default_font_size - 1);
1909 $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_shipping, '', 'L');
1910
1911 $shipp_shift += $hautcadre + 10;
1912 }
1913 }
1914 }
1915
1916 $pdf->SetTextColor(0, 0, 0);
1917
1918 $pagehead = array('top_shift' => $top_shift, 'shipp_shift' => $shipp_shift);
1919
1920 return $pagehead;
1921 }
1922
1923 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1924 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1934 protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
1935 {
1936 // phpcs:enable
1937 $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0);
1938 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);
1939 }
1940
1941
1942
1953 public function defineColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1954 {
1955 global $hookmanager;
1956
1957 // Default field style for content
1958 $this->defaultContentsFieldsStyle = array(
1959 'align' => 'R', // R,C,L
1960 'padding' => array(1, 0.5, 1, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1961 );
1962
1963 // Default field style for content
1964 $this->defaultTitlesFieldsStyle = array(
1965 'align' => 'C', // R,C,L
1966 'padding' => array(0.5, 0, 0.5, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1967 );
1968
1969 /*
1970 * For example
1971 $this->cols['theColKey'] = array(
1972 'rank' => $rank, // int : use for ordering columns
1973 'width' => 20, // the column width in mm
1974 'title' => array(
1975 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
1976 'label' => ' ', // the final label : used fore final generated text
1977 'align' => 'L', // text alignment : R,C,L
1978 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1979 ),
1980 'content' => array(
1981 'align' => 'L', // text alignment : R,C,L
1982 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1983 ),
1984 );
1985 */
1986
1987 $rank = 0; // do not use negative rank
1988 $this->cols['position'] = array(
1989 'rank' => $rank,
1990 'width' => 10,
1991 'status' => (getDolGlobalInt('PDF_ERATOSTHENE_ADD_POSITION') || getDolGlobalInt('PDF_ERATOSHTENE_ADD_POSITION')) ? true : (getDolGlobalInt('PDF_ADD_POSITION') ? true : false),
1992 'title' => array(
1993 'textkey' => '#', // use lang key is useful in some case with module
1994 'align' => 'C',
1995 // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
1996 // 'label' => ' ', // the final label
1997 'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1998 ),
1999 'content' => array(
2000 'align' => 'C',
2001 'padding' => array(1, 0.5, 1, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2002 ),
2003 );
2004
2005 $rank = 5; // do not use negative rank
2006 $this->cols['desc'] = array(
2007 'rank' => $rank,
2008 'width' => false, // only for desc
2009 'status' => true,
2010 'title' => array(
2011 'textkey' => 'Designation', // use lang key is useful in some case with module
2012 'align' => 'L',
2013 // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
2014 // 'label' => ' ', // the final label
2015 'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2016 ),
2017 'content' => array(
2018 'align' => 'L',
2019 'padding' => array(1, 0.5, 1, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2020 ),
2021 );
2022
2023 // Image of product
2024 $rank += 10;
2025 $this->cols['photo'] = array(
2026 'rank' => $rank,
2027 'width' => (!getDolGlobalInt('MAIN_DOCUMENTS_WITH_PICTURE_WIDTH') ? 20 : getDolGlobalInt('MAIN_DOCUMENTS_WITH_PICTURE_WIDTH')), // in mm
2028 'status' => false,
2029 'title' => array(
2030 'textkey' => 'Photo',
2031 'label' => ' '
2032 ),
2033 'content' => array(
2034 'padding' => array(0, 0, 0, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2035 ),
2036 'border-left' => false, // remove left line separator
2037 );
2038
2039 if (getDolGlobalInt('MAIN_GENERATE_ORDERS_WITH_PICTURE') && !empty($this->atleastonephoto)) {
2040 $this->cols['photo']['status'] = true;
2041 }
2042
2043 $rank += 10;
2044 $this->cols['vat'] = array(
2045 'rank' => $rank,
2046 'status' => false,
2047 'width' => 16, // in mm
2048 'title' => array(
2049 'textkey' => 'VAT'
2050 ),
2051 'border-left' => true, // add left line separator
2052 );
2053
2054 if (!getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT') && !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN')) {
2055 $this->cols['vat']['status'] = true;
2056 }
2057
2058 $rank += 10;
2059 $this->cols['subprice'] = array(
2060 'rank' => $rank,
2061 'width' => 19, // in mm
2062 'status' => true,
2063 'title' => array(
2064 'textkey' => 'PriceUHT'
2065 ),
2066 'border-left' => true, // add left line separator
2067 );
2068
2069 // Adapt dynamically the width of subprice, if text is too long.
2070 $tmpwidth = 0;
2071 $nblines = count($object->lines);
2072 for ($i = 0; $i < $nblines; $i++) {
2073 $tmpwidth2 = dol_strlen(dol_string_nohtmltag(pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails)));
2074 $tmpwidth = max($tmpwidth, $tmpwidth2);
2075 }
2076 if ($tmpwidth > 10) {
2077 $this->cols['subprice']['width'] += (2 * ($tmpwidth - 10));
2078 }
2079
2080 $rank += 10;
2081 $this->cols['qty'] = array(
2082 'rank' => $rank,
2083 'width' => 16, // in mm
2084 'status' => true,
2085 'title' => array(
2086 'textkey' => 'Qty'
2087 ),
2088 'border-left' => true, // add left line separator
2089 );
2090
2091 $rank += 10;
2092 $this->cols['unit'] = array(
2093 'rank' => $rank,
2094 'width' => 11, // in mm
2095 'status' => false,
2096 'title' => array(
2097 'textkey' => 'Unit'
2098 ),
2099 'border-left' => true, // add left line separator
2100 );
2101 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2102 $this->cols['unit']['status'] = true;
2103 }
2104
2105 $rank += 10;
2106 $this->cols['discount'] = array(
2107 'rank' => $rank,
2108 'width' => 13, // in mm
2109 'status' => false,
2110 'title' => array(
2111 'textkey' => 'ReductionShort'
2112 ),
2113 'border-left' => true, // add left line separator
2114 );
2115 if ($this->atleastonediscount) {
2116 $this->cols['discount']['status'] = true;
2117 }
2118
2119 $rank += 1000; // add a big offset to be sure is the last col because default extrafield rank is 100
2120 $this->cols['totalexcltax'] = array(
2121 'rank' => $rank,
2122 'width' => 26, // in mm
2123 'status' => !getDolGlobalString('PDF_ORDER_HIDE_PRICE_EXCL_TAX'),
2124 'title' => array(
2125 'textkey' => 'TotalHTShort'
2126 ),
2127 'border-left' => true, // add left line separator
2128 );
2129
2130 $rank += 1010; // add a big offset to be sure is the last col because default extrafield rank is 100
2131 $this->cols['totalincltax'] = array(
2132 'rank' => $rank,
2133 'width' => 26, // in mm
2134 'status' => getDolGlobalBool('PDF_ORDER_SHOW_PRICE_INCL_TAX'),
2135 'title' => array(
2136 'textkey' => 'TotalTTCShort'
2137 ),
2138 'border-left' => true, // add left line separator
2139 );
2140
2141 // Add extrafields cols
2142 if (!empty($object->lines)) {
2143 $line = reset($object->lines);
2144 $this->defineColumnExtrafield($line, $outputlangs, $hidedetails);
2145 }
2146
2147 $parameters = array(
2148 'object' => $object,
2149 'outputlangs' => $outputlangs,
2150 'hidedetails' => $hidedetails,
2151 'hidedesc' => $hidedesc,
2152 'hideref' => $hideref
2153 );
2154
2155 $reshook = $hookmanager->executeHooks('defineColumnField', $parameters, $this); // Note that $object may have been modified by hook
2156 if ($reshook < 0) {
2157 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2158 } elseif (empty($reshook)) {
2159 // @phan-suppress-next-line PhanPluginSuspiciousParamOrderInternal
2160 $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys
2161 } else {
2162 $this->cols = $hookmanager->resArray;
2163 }
2164 }
2165}
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,...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
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)
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
buildzip.php
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:3160
pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line total excluding tax.
Definition pdf.lib.php:2861
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:3192
pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, $h, $align, $default_font_size)
Show linked objects for PDF generation.
Definition pdf.lib.php:1808
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:1239
pdf_getHeightForLogo($logo, $url=false)
Return height to use for Logo onto PDF.
Definition pdf.lib.php:317
pdf_getlinetotalwithtax($object, $i, $outputlangs, $hidedetails=0)
Return line total including tax.
Definition pdf.lib.php:2911
pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line unit price excluding tax.
Definition pdf.lib.php:2464
pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails=0)
Return line vat rate.
Definition pdf.lib.php:2402
pdf_pagehead($pdf, $outputlangs, $page_height)
Show header of page for PDF generation.
Definition pdf.lib.php:747
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:1421
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:3288
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:438
pdf_getlineunit($object, $i, $outputlangs, $hidedetails=0)
Return line unit.
Definition pdf.lib.php:2709
pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails=0)
Return line remise percent.
Definition pdf.lib.php:2752
pdf_getlineqty($object, $i, $outputlangs, $hidedetails=0)
Return line quantity.
Definition pdf.lib.php:2549
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:1135
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:393
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