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