dolibarr 23.0.3
pdf_standard_myobject.modules.php
1<?php
2/* Copyright (C) 2004-2014 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2008 Raphael Bertrand <raphael.bertrand@resultic.fr>
5 * Copyright (C) 2010-2014 Juanjo Menent <jmenent@2byte.es>
6 * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
7 * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr>
8 * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
9 * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
10 * Copyright (C) 2017 Ferran Marcet <fmarcet@2byte.es>
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 Alexandre Spangaro <alexandre@inovea-conseil.com>
14 * Copyright (C) ---Replace with your own copyright and developer email---
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program. If not, see <https://www.gnu.org/licenses/>.
28 * or see https://www.gnu.org/
29 */
30
37dol_include_once('/mymodule/core/modules/mymodule/modules_myobject.php');
38require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
39require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
40require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
41require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
42
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 $phpmin = array(7, 0);
84
89 public $version = 'dolibarr';
90
95 public $emetteur;
96
100 public $cols;
101
102
108 public function __construct($db)
109 {
110 global $langs, $mysoc;
111
112 // Translations
113 $langs->loadLangs(array("main", "bills"));
114
115 $this->db = $db;
116 $this->name = "standard";
117 $this->description = $langs->trans('DocumentModelStandardPDF');
118 $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template
119
120 // Dimension page
121 $this->type = 'pdf';
122 $formatarray = pdf_getFormat();
123 $this->page_largeur = $formatarray['width'];
124 $this->page_hauteur = $formatarray['height'];
125 $this->format = array($this->page_largeur, $this->page_hauteur);
126 $this->marge_gauche = getDolGlobalInt('MAIN_PDF_MARGIN_LEFT', 10);
127 $this->marge_droite = getDolGlobalInt('MAIN_PDF_MARGIN_RIGHT', 10);
128 $this->marge_haute = getDolGlobalInt('MAIN_PDF_MARGIN_TOP', 10);
129 $this->marge_basse = getDolGlobalInt('MAIN_PDF_MARGIN_BOTTOM', 10);
130
131 // Define position of columns
132 $this->posxdesc = $this->marge_gauche + 1; // used for notes and other stuff
133
134 $this->tabTitleHeight = 5; // default height
135
136 // Use new system for position of columns, view $this->defineColumnField()
137
138 $this->tva = array();
139 $this->tva_array = array();
140 $this->localtax1 = array();
141 $this->localtax2 = array();
142 $this->atleastoneratenotnull = 0;
143 $this->atleastonediscount = 0;
144
145 if ($mysoc === null) {
146 dol_syslog(get_class($this).'::__construct() Global $mysoc should not be null.'. getCallerInfoString(), LOG_ERR);
147 return;
148 }
149
150 // Get source company
151 $this->emetteur = $mysoc;
152 if (empty($this->emetteur->country_code)) {
153 $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined
154 }
155 }
156
157
158 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
170 public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
171 {
172 // phpcs:enable
173 global $user, $langs, $conf, $mysoc, $hookmanager, $nblines;
174
175 dol_syslog("write_file outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null'));
176
177 if (!is_object($outputlangs)) {
178 $outputlangs = $langs;
179 }
180 // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
181 if (getDolGlobalInt('MAIN_USE_FPDF')) {
182 $outputlangs->charset_output = 'ISO-8859-1';
183 }
184
185 // Load translation files required by the page
186 $langfiles = array("main", "bills", "products", "dict", "companies", "compta");
187 $outputlangs->loadLangs($langfiles);
188
189 // Show Draft Watermark
190 if (getDolGlobalString('MYOBJECT_DRAFT_WATERMARK') && $object->status == $object::STATUS_DRAFT) {
191 $this->watermark = getDolGlobalString('MYOBJECT_DRAFT_WATERMARK');
192 }
193
194 global $outputlangsbis;
195 $outputlangsbis = null;
196 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE') && $outputlangs->defaultlang != getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
197 $outputlangsbis = new Translate('', $conf);
198 $outputlangsbis->setDefaultLang(getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE'));
199 $outputlangsbis->loadLangs($langfiles);
200 }
201
202 $nblines = (is_array($object->lines) ? count($object->lines) : 0);
203
204 $hidetop = 0;
205 if (getDolGlobalString('MAIN_PDF_DISABLE_COL_HEAD_TITLE')) {
206 $hidetop = getDolGlobalString('MAIN_PDF_DISABLE_COL_HEAD_TITLE');
207 }
208
209 // Loop on each lines to detect if there is at least one image to show
210 $realpatharray = array();
211 $this->atleastonephoto = false;
212 /*
213 if (getDolGlobalInt('MAIN_GENERATE_MYOBJECT_WITH_PICTURE'))) {
214 $objphoto = new Product($this->db);
215
216 for ($i = 0; $i < $nblines; $i++) {
217 if (empty($object->lines[$i]->fk_product)) {
218 continue;
219 }
220
221 $objphoto->fetch($object->lines[$i]->fk_product);
222 //var_dump($objphoto->ref);exit;
223 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
224 $pdir[0] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/";
225 $pdir[1] = get_exdir(0, 0, 0, 0, $objphoto, 'product').dol_sanitizeFileName($objphoto->ref).'/';
226 } else {
227 $pdir[0] = get_exdir(0, 0, 0, 0, $objphoto, 'product'); // default
228 $pdir[1] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/"; // alternative
229 }
230
231 $arephoto = false;
232 foreach ($pdir as $midir) {
233 if (!$arephoto) {
234 if ($conf->entity != $objphoto->entity) {
235 $dir = $conf->product->multidir_output[$objphoto->entity].'/'.$midir; //Check repertories of current entities
236 } else {
237 $dir = $conf->product->dir_output.'/'.$midir; //Check repertory of the current product
238 }
239
240 foreach ($objphoto->liste_photos($dir, 1) as $key => $obj) {
241 if (!getDolGlobalInt('CAT_HIGH_QUALITY_IMAGES')) { // If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo
242 if ($obj['photo_vignette']) {
243 $filename = $obj['photo_vignette'];
244 } else {
245 $filename = $obj['photo'];
246 }
247 } else {
248 $filename = $obj['photo'];
249 }
250
251 $realpath = $dir.$filename;
252 $arephoto = true;
253 $this->atleastonephoto = true;
254 }
255 }
256 }
257
258 if ($realpath && $arephoto) {
259 $realpatharray[$i] = $realpath;
260 }
261 }
262 }
263 */
264
265 //if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva;
266 $dir_output = getMultidirOutput($object, $object->module);
267 if (!empty($dir_output)) {
268 $dir_output .= '/' . $object->element;
269
270 $object->fetch_thirdparty();
271
272 $dir = null;
273 // Definition of $dir and $file
274 if ($object->specimen) {
275 $dir = $dir_output;
276 $file = $dir."/SPECIMEN.pdf";
277 } else {
278 $objectref = dol_sanitizeFileName($object->ref);
279 $dir = $dir_output."/".$objectref;
280 $file = $dir."/".$objectref.".pdf";
281 }
282 // if ($dir === null) {
283 // return 0;
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 '@phan-var-force TCPDI|TCPDF $pdf';
309 $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
310 $pdf->setAutoPageBreak(true, 0);
311
312 $heightforinfotot = 50; // Height reserved to output the info and total part and payment part
313 $heightforfreetext = getDolGlobalInt('MAIN_PDF_FREETEXT_HEIGHT', 5); // Height reserved to output the free text on last page
314 $heightforfooter = $this->marge_basse + (getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS') ? 12 : 22); // Height reserved to output the footer (value include bottom margin)
315
316 if (class_exists('TCPDF')) {
317 $pdf->setPrintHeader(false);
318 $pdf->setPrintFooter(false);
319 }
320 $pdf->SetFont(pdf_getPDFFont($outputlangs));
321
322 // Set path to the background PDF File
323 if (getDolGlobalString('MAIN_ADD_PDF_BACKGROUND')) {
324 $logodir = $conf->mycompany->dir_output;
325 if (!empty($conf->mycompany->multidir_output[$object->entity ?? $conf->entity])) {
326 $logodir = $conf->mycompany->multidir_output[$object->entity ?? $conf->entity];
327 }
328 $pagecount = $pdf->setSourceFile($logodir.'/'.getDolGlobalString('MAIN_ADD_PDF_BACKGROUND'));
329 $tplidx = $pdf->importPage(1);
330 }
331
332 $pdf->Open();
333 $pagenb = 0;
334 $pdf->SetDrawColor(128, 128, 128);
335
336 $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
337 $pdf->SetSubject($outputlangs->transnoentities("PdfTitle"));
338 $pdf->SetCreator("Dolibarr ".DOL_VERSION);
339 $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
340 $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
341 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
342 $pdf->SetCompression(false);
343 }
344
345 // Set certificate
346 $cert = empty($user->conf->CERTIFICATE_CRT) ? '' : $user->conf->CERTIFICATE_CRT;
347 // If user has no certificate, we try to take the company one
348 if (!$cert) {
349 $cert = getDolGlobalString('CERTIFICATE_CRT');
350 }
351 // If a certificate is found
352 if ($cert) {
353 $info = array(
354 'Name' => $this->emetteur->name,
355 'Location' => getCountry($this->emetteur->country_code, ''),
356 'Reason' => 'MYOBJECT',
357 'ContactInfo' => $this->emetteur->email
358 );
359 $pdf->setSignature($cert, $cert, $this->emetteur->name, '', 2, $info);
360 }
361
362 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
363 $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
364
365
366 // New page
367 $pdf->AddPage();
368 if (!empty($tplidx)) {
369 $pdf->useTemplate($tplidx);
370 }
371 $pagenb++;
372
373 $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis);
374 $pdf->SetFont('', '', $default_font_size - 1);
375 $pdf->MultiCell(0, 3, ''); // Set interline to 3
376 $pdf->SetTextColor(0, 0, 0);
377
378 $tab_top = 90 + $top_shift;
379 $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
380
381 $tab_height = $this->page_hauteur - $tab_top - $heightforfooter - $heightforfreetext;
382
383 $tab_height_newpage = 150;
384 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
385 $tab_height_newpage -= $top_shift;
386 }
387
388 $nexY = $tab_top - 1;
389
390 // Display notes
391 $notetoshow = empty($object->note_public) ? '' : $object->note_public;
392 // Extrafields in note
393 $extranote = $this->getExtrafieldsInHtml($object, $outputlangs);
394 if (!empty($extranote)) {
395 $notetoshow = dol_concatdesc($notetoshow, $extranote);
396 }
397
398 $pagenb = $pdf->getPage();
399 if ($notetoshow) {
400 $tab_top -= 2;
401
402 $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite;
403 $pageposbeforenote = $pagenb;
404
405 $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
406 complete_substitutions_array($substitutionarray, $outputlangs, $object);
407 $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
408 $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);
409
410 $pdf->startTransaction();
411
412 $pdf->SetFont('', '', $default_font_size - 1);
413 $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
414 // Description
415 $pageposafternote = $pdf->getPage();
416 $posyafter = $pdf->GetY();
417
418 if ($pageposafternote > $pageposbeforenote) {
419 $pdf->rollbackTransaction(true);
420
421 // prepare pages to receive notes
422 while ($pagenb < $pageposafternote) {
423 $pdf->AddPage();
424 $pagenb++;
425 if (!empty($tplidx)) {
426 $pdf->useTemplate($tplidx);
427 }
428 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
429 $this->_pagehead($pdf, $object, 0, $outputlangs);
430 }
431 // $this->_pagefoot($pdf,$object,$outputlangs,1);
432 $pdf->setTopMargin($tab_top_newpage);
433 // The only function to edit the bottom margin of current page to set it.
434 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext);
435 }
436
437 // back to start
438 $pdf->setPage($pageposbeforenote);
439 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext);
440 $pdf->SetFont('', '', $default_font_size - 1);
441 $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
442 $pageposafternote = $pdf->getPage();
443
444 $posyafter = $pdf->GetY();
445
446 if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) { // There is no space left for total+free text
447 $pdf->AddPage('', '', true);
448 $pagenb++;
449 $pageposafternote++;
450 $pdf->setPage($pageposafternote);
451 $pdf->setTopMargin($tab_top_newpage);
452 // The only function to edit the bottom margin of current page to set it.
453 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext);
454 //$posyafter = $tab_top_newpage;
455 }
456
457
458 // apply note frame to previous pages
459 $i = $pageposbeforenote;
460 while ($i < $pageposafternote) {
461 $pdf->setPage($i);
462
463
464 $pdf->SetDrawColor(128, 128, 128);
465 // Draw note frame
466 if ($i > $pageposbeforenote) {
467 $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter);
468 $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1);
469 } else {
470 $height_note = $this->page_hauteur - ($tab_top + $heightforfooter);
471 $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1);
472 }
473
474 // Add footer
475 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
476 $this->_pagefoot($pdf, $object, $outputlangs, 1);
477
478 $i++;
479 }
480
481 // apply note frame to last page
482 $pdf->setPage($pageposafternote);
483 if (!empty($tplidx)) {
484 $pdf->useTemplate($tplidx);
485 }
486 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
487 $this->_pagehead($pdf, $object, 0, $outputlangs);
488 }
489 $height_note = $posyafter - $tab_top_newpage;
490 $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1);
491 } else {
492 // No pagebreak
493 $pdf->commitTransaction();
494 $posyafter = $pdf->GetY();
495 $height_note = $posyafter - $tab_top;
496 $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1);
497
498
499 if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) {
500 // not enough space, need to add page
501 $pdf->AddPage('', '', true);
502 $pagenb++;
503 $pageposafternote++;
504 $pdf->setPage($pageposafternote);
505 if (!empty($tplidx)) {
506 $pdf->useTemplate($tplidx);
507 }
508 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
509 $this->_pagehead($pdf, $object, 0, $outputlangs);
510 }
511
512 $posyafter = $tab_top_newpage;
513 }
514 }
515
516 $tab_height -= $height_note;
517 $tab_top = $posyafter + 6;
518 } else {
519 $height_note = 0;
520 }
521
522 // Use new auto column system
523 $this->prepareArrayColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref);
524
525 // Table simulation to know the height of the title line
526 $pdf->startTransaction();
527 $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop);
528 $pdf->rollbackTransaction(true);
529
530 $nexY = $tab_top + $this->tabTitleHeight;
531
532 // Loop on each lines
533 $pageposbeforeprintlines = $pdf->getPage();
534 $pagenb = $pageposbeforeprintlines;
535 for ($i = 0; $i < $nblines; $i++) {
536 $curY = $nexY;
537 $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
538 $pdf->SetTextColor(0, 0, 0);
539
540 // Define size of image if we need it
541 // $imglinesize = array();
542 // if (!empty($realpatharray[$i])) {
543 // $imglinesize = pdf_getSizeForImage($realpatharray[$i]);
544 // }
545
546 $pdf->setTopMargin($tab_top_newpage);
547 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext + $heightforinfotot); // The only function to edit the bottom margin of current page to set it.
548 $pageposbefore = $pdf->getPage();
549
550 $showpricebeforepagebreak = 1;
551 $posYAfterImage = 0;
552 $posYAfterDescription = 0;
553
554 // if ($this->getColumnStatus('photo')) {
555 // // We start with Photo of product line
556 // if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) { // If photo too high, we moved completely on new page
557 // $pdf->AddPage('', '', true);
558 // if (!empty($tplidx)) {
559 // $pdf->useTemplate($tplidx);
560 // }
561 // $pdf->setPage($pageposbefore + 1);
562
563 // $curY = $tab_top_newpage;
564
565 // // Allows data in the first page if description is long enough to break in multiples pages
566 // if (getDolGlobalInt('MAIN_PDF_DATA_ON_FIRST_PAGE')) {
567 // $showpricebeforepagebreak = 1;
568 // } else {
569 // $showpricebeforepagebreak = 0;
570 // }
571 // }
572
573 // if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height'])) {
574 // $pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY + 1, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi
575 // // $pdf->Image does not increase value return by getY, so we save it manually
576 // $posYAfterImage = $curY + $imglinesize['height'];
577 // }
578 // }
579
580 // Description of product line
581 if ($this->getColumnStatus('desc')) {
582 $pdf->startTransaction();
583
584 $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc);
585 $pageposafter = $pdf->getPage();
586
587 if ($pageposafter > $pageposbefore) { // There is a pagebreak
588 $pdf->rollbackTransaction(true);
589 $pageposafter = $pageposbefore;
590 $pdf->setPageOrientation('', true, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
591
592 $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc);
593
594 $pageposafter = $pdf->getPage();
595 $posyafter = $pdf->GetY();
596
597 if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) { // There is no space left for total+free text
598 if ($i == ($nblines - 1)) { // No more lines, and no space left to show total, so we create a new page
599 $pdf->AddPage('', '', true);
600 if (!empty($tplidx)) {
601 $pdf->useTemplate($tplidx);
602 }
603 $pdf->setPage($pageposafter + 1);
604 }
605 } else {
606 // We found a page break
607 // Allows data in the first page if description is long enough to break in multiples pages
608 if (getDolGlobalInt('MAIN_PDF_DATA_ON_FIRST_PAGE')) {
609 $showpricebeforepagebreak = 1;
610 } else {
611 $showpricebeforepagebreak = 0;
612 }
613 }
614 } else { // No pagebreak
615 $pdf->commitTransaction();
616 }
617 $posYAfterDescription = $pdf->GetY();
618 }
619
620 $nexY = max($pdf->GetY(), $posYAfterImage);
621
622
623 $pageposafter = $pdf->getPage();
624 $pdf->setPage($pageposbefore);
625 $pdf->setTopMargin($this->marge_haute);
626 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
627
628 // We suppose that a too long description or photo were moved completely on next page
629 if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
630 $pdf->setPage($pageposafter);
631 $curY = $tab_top_newpage;
632 }
633
634 $pdf->SetFont('', '', $default_font_size - 1); // We reposition the default font
635
636 // Quantity
637 // Enough for 6 chars
638 if ($this->getColumnStatus('qty')) {
639 $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
640 $this->printStdColumnContent($pdf, $curY, 'qty', $qty);
641 $nexY = max($pdf->GetY(), $nexY);
642 }
643
644 // Extrafields
645 if (!empty($object->lines[$i]->array_options)) {
646 foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) {
647 if ($this->getColumnStatus($extrafieldColKey)) {
648 $extrafieldValue = $this->getExtrafieldContent($object->lines[$i], $extrafieldColKey, $outputlangs);
649 $this->printStdColumnContent($pdf, $curY, $extrafieldColKey, $extrafieldValue);
650 $nexY = max($pdf->GetY(), $nexY);
651 }
652 }
653 }
654
655
656 $parameters = array(
657 'object' => $object,
658 'i' => $i,
659 'pdf' => & $pdf,
660 'curY' => & $curY,
661 'nexY' => & $nexY,
662 'outputlangs' => $outputlangs,
663 'hidedetails' => $hidedetails
664 );
665 $reshook = $hookmanager->executeHooks('printPDFline', $parameters, $this); // Note that $object may have been modified by hook
666
667
668 $sign = 1;
669 // Collection of totals by value of VAT in $this->tva["taux"]=total_tva
670 $prev_progress = $object->lines[$i]->get_prev_progress($object->id);
671 if ($prev_progress > 0 && $object->lines instanceof CommonInvoiceLine && !empty($object->lines[$i]->situation_percent)) { // Compute progress from previous situation
672 if (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) {
673 $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent;
674 } else {
675 $tvaligne = $sign * $object->lines[$i]->total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent;
676 }
677 } else {
678 if (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) {
679 $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva;
680 } else {
681 $tvaligne = $sign * $object->lines[$i]->total_tva;
682 }
683 }
684
685 $localtax1ligne = $object->lines[$i]->total_localtax1;
686 $localtax2ligne = $object->lines[$i]->total_localtax2;
687 $localtax1_rate = $object->lines[$i]->localtax1_tx;
688 $localtax2_rate = $object->lines[$i]->localtax2_tx;
689 $localtax1_type = $object->lines[$i]->localtax1_type;
690 $localtax2_type = $object->lines[$i]->localtax2_type;
691
692 $vatrate = (string) $object->lines[$i]->tva_tx;
693
694 // Retrieve type from database for backward compatibility with old records
695 if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined
696 && (!empty($localtax1_rate) || !empty($localtax2_rate))) { // and there is local tax
697 $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $object->thirdparty, $mysoc);
698 $localtax1_type = isset($localtaxtmp_array[0]) ? $localtaxtmp_array[0] : '';
699 $localtax2_type = isset($localtaxtmp_array[2]) ? $localtaxtmp_array[2] : '';
700 }
701
702 // retrieve global local tax
703 if ($localtax1_type && $localtax1ligne != 0) {
704 if (empty($this->localtax1[$localtax1_type][$localtax1_rate])) {
705 $this->localtax1[$localtax1_type][$localtax1_rate] = $localtax1ligne;
706 } else {
707 $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne;
708 }
709 }
710 if ($localtax2_type && $localtax2ligne != 0) {
711 if (empty($this->localtax2[$localtax2_type][$localtax2_rate])) {
712 $this->localtax2[$localtax2_type][$localtax2_rate] = $localtax2ligne;
713 } else {
714 $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne;
715 }
716 }
717
718 if (((int) $object->lines[$i]->info_bits & 0x01) == 0x01) {
719 $vatrate .= '*';
720 }
721
722 // Fill $this->tva and $this->tva_array
723 if (!isset($this->tva[$vatrate])) {
724 $this->tva[$vatrate] = 0;
725 }
726 $this->tva[$vatrate] += $tvaligne;
727 $vatcode = $object->lines[$i]->vat_src_code;
728 if (empty($this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'])) {
729 $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] = 0;
730 }
731 $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')] = array('vatrate' => $vatrate, 'vatcode' => $vatcode, 'amount' => $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] + $tvaligne);
732
733 $nexY = max($nexY, $posYAfterImage);
734
735 // Add line
736 if (getDolGlobalInt('MAIN_PDF_DASH_BETWEEN_LINES') && $i < ($nblines - 1)) {
737 $pdf->setPage($pageposafter);
738 $pdf->SetLineStyle(array('dash' => '1,1', 'color' => array(80, 80, 80)));
739 //$pdf->SetDrawColor(190,190,200);
740 $pdf->line($this->marge_gauche, $nexY, $this->page_largeur - $this->marge_droite, $nexY);
741 $pdf->SetLineStyle(array('dash' => 0));
742 }
743
744 // Detect if some page were added automatically and output _tableau for past pages
745 while ($pagenb < $pageposafter) {
746 $pdf->setPage($pagenb);
747 if ($pagenb == $pageposbeforeprintlines) {
748 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code, $outputlangsbis);
749 } else {
750 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code, $outputlangsbis);
751 }
752 $this->_pagefoot($pdf, $object, $outputlangs, 1);
753 $pagenb++;
754 $pdf->setPage($pagenb);
755 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
756 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
757 $this->_pagehead($pdf, $object, 0, $outputlangs);
758 }
759 if (!empty($tplidx)) {
760 $pdf->useTemplate($tplidx);
761 }
762 }
763
764 if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) {
765 if ($pagenb == $pageposafter) {
766 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code, $outputlangsbis);
767 } else {
768 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code, $outputlangsbis);
769 }
770 $this->_pagefoot($pdf, $object, $outputlangs, 1);
771 // New page
772 $pdf->AddPage();
773 if (!empty($tplidx)) {
774 $pdf->useTemplate($tplidx);
775 }
776 $pagenb++;
777 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
778 $this->_pagehead($pdf, $object, 0, $outputlangs);
779 }
780 }
781 }
782
783 // Show square
784 if ($pagenb == $pageposbeforeprintlines) {
785 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, $hidetop, 0, $object->multicurrency_code, $outputlangsbis);
786 } else {
787 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code, $outputlangsbis);
788 }
789 $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
790
791 // Display infos area
792 //$posy = $this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs);
793
794 // Display total zone
795 //$posy = $this->drawTotalTable($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs);
796
797 // Display payment area
798 /*
799 if ($deja_regle)
800 {
801 $posy = $this->drawPaymentsTable($pdf, $object, $posy, $outputlangs);
802 }
803 */
804
805 // Pagefoot
806 $this->_pagefoot($pdf, $object, $outputlangs);
807 if (method_exists($pdf, 'AliasNbPages')) {
808 $pdf->AliasNbPages(); // @phan-suppress-current-line PhanUndeclaredMethod
809 }
810
811 $pdf->Close();
812
813 $pdf->Output($file, 'F');
814
815 // Add pdfgeneration hook
816 $hookmanager->initHooks(array('pdfgeneration'));
817 $parameters = array('file' => $file, 'object' => $object, 'outputlangs' => $outputlangs);
818 global $action;
819 $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
820 $this->warnings = $hookmanager->warnings;
821 if ($reshook < 0) {
822 $this->error = $hookmanager->error;
823 $this->errors = $hookmanager->errors;
824 dolChmod($file);
825 return -1;
826 }
827
828 dolChmod($file);
829
830 $this->result = array('fullpath' => $file);
831
832 return 1; // No error
833 } else {
834 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
835 return 0;
836 }
837 } else {
838 $this->error = $langs->transnoentities("ErrorConstantNotDefined", "FAC_OUTPUTDIR");
839 return 0;
840 }
841 }
842
843 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
851 public static function liste_modeles($db, $maxfilenamelength = 0)
852 {
853 // phpcs:enable
854 return parent::liste_modeles($db, $maxfilenamelength); // TODO: Change the autogenerated stub
855 }
856
857 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
872 protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '', $outputlangsbis = null)
873 {
874 global $conf;
875
876 // Force to disable hidetop and hidebottom
877 $hidebottom = 0;
878 if ($hidetop) {
879 $hidetop = -1;
880 }
881
882 $currency = !empty($currency) ? $currency : $conf->currency;
883 $default_font_size = pdf_getPDFFontSize($outputlangs);
884
885 // Amount in (at tab_top - 1)
886 $pdf->SetTextColor(0, 0, 0);
887 $pdf->SetFont('', '', $default_font_size - 2);
888
889 if (empty($hidetop)) {
890 $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
891 if (getDolGlobalInt('PDF_USE_ALSO_LANGUAGE_CODE') && is_object($outputlangsbis)) {
892 $titre .= ' - '.$outputlangsbis->transnoentities("AmountInCurrency", $outputlangsbis->transnoentitiesnoconv("Currency".$currency));
893 }
894
895 $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
896 $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
897
898 //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
899 if (getDolGlobalString('MAIN_PDF_TITLE_BACKGROUND_COLOR')) {
900 $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite - $this->marge_gauche, $this->tabTitleHeight, 'F', array(), explode(',', getDolGlobalString('MAIN_PDF_TITLE_BACKGROUND_COLOR')));
901 }
902 }
903
904 $pdf->SetDrawColor(128, 128, 128);
905 $pdf->SetFont('', '', $default_font_size - 1);
906
907 // Output Rect
908 $this->printRect($pdf, $this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $tab_height, $hidetop, $hidebottom); // Rect takes a length in 3rd parameter and 4th parameter
909
910
911 $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop);
912
913 if (empty($hidetop)) {
914 $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
915 }
916 }
917
918 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
929 protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null)
930 {
931 // phpcs:enable
932 global $conf, $langs;
933
934 $ltrdirection = 'L';
935 if ($outputlangs->trans("DIRECTION") == 'rtl') {
936 $ltrdirection = 'R';
937 }
938
939 // Load traductions files required by page
940 $outputlangs->loadLangs(array("main", "bills", "propal", "companies"));
941
942 $default_font_size = pdf_getPDFFontSize($outputlangs);
943
944 pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
945
946 // Show Draft Watermark
947 if (getDolGlobalString('MYMODULE_DRAFT_WATERMARK') && $object->status == $object::STATUS_DRAFT) {
948 pdf_watermark($pdf, $outputlangs, $this->page_hauteur, $this->page_largeur, 'mm', dol_escape_htmltag(getDolGlobalString('MYMODULE_DRAFT_WATERMARK')));
949 }
950
951 $pdf->SetTextColor(0, 0, 60);
952 $pdf->SetFont('', 'B', $default_font_size + 3);
953
954 $w = 110;
955
956 $posy = $this->marge_haute;
957 $posx = $this->page_largeur - $this->marge_droite - $w;
958
959 $pdf->SetXY($this->marge_gauche, $posy);
960
961 // Logo
962 if (!getDolGlobalInt('PDF_DISABLE_MYCOMPANY_LOGO')) {
963 if ($this->emetteur->logo) {
964 $logodir = $conf->mycompany->dir_output;
965 if (!empty(getMultidirOutput($object, 'mycompany'))) {
966 $logodir = getMultidirOutput($object, 'mycompany');
967 }
968 if (!getDolGlobalInt('MAIN_PDF_USE_LARGE_LOGO')) {
969 $logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
970 } else {
971 $logo = $logodir.'/logos/'.$this->emetteur->logo;
972 }
973 if (is_readable($logo)) {
974 $height = pdf_getHeightForLogo($logo);
975 $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
976 } else {
977 $pdf->SetTextColor(200, 0, 0);
978 $pdf->SetFont('', 'B', $default_font_size - 2);
979 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
980 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
981 }
982 } else {
983 $text = $this->emetteur->name;
984 $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
985 }
986 }
987
988 $pdf->SetFont('', 'B', $default_font_size + 3);
989 $pdf->SetXY($posx, $posy);
990 $pdf->SetTextColor(0, 0, 60);
991 $title = $outputlangs->transnoentities("PdfTitle");
992 if (getDolGlobalInt('PDF_USE_ALSO_LANGUAGE_CODE') && is_object($outputlangsbis)) {
993 $title .= ' - ';
994 $title .= $outputlangsbis->transnoentities("PdfTitle");
995 }
996 $pdf->MultiCell($w, 3, $title, '', 'R');
997
998 $pdf->SetFont('', 'B', $default_font_size);
999
1000 $posy += 5;
1001 $pdf->SetXY($posx, $posy);
1002 $pdf->SetTextColor(0, 0, 60);
1003 $textref = $outputlangs->transnoentities("Ref")." : ".$outputlangs->convToOutputCharset($object->ref);
1004 if ($object->status == $object::STATUS_DRAFT) {
1005 $pdf->SetTextColor(128, 0, 0);
1006 $textref .= ' - '.$outputlangs->transnoentities("NotValidated");
1007 }
1008 $pdf->MultiCell($w, 4, $textref, '', 'R');
1009
1010 $posy += 1;
1011 $pdf->SetFont('', '', $default_font_size - 2);
1012
1013 // @phan-suppress-next-line PhanUndeclaredProperty
1014 if (property_exists($object, 'ref_client') && $object->ref_client) {
1015 $posy += 4;
1016 $pdf->SetXY($posx, $posy);
1017 $pdf->SetTextColor(0, 0, 60);
1018 // @phan-suppress-next-line PhanUndeclaredProperty
1019 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".dol_trunc($outputlangs->convToOutputCharset($object->ref_client), 65), '', 'R');
1020 }
1021
1022 if (getDolGlobalInt('PDF_SHOW_PROJECT_TITLE')) {
1023 $object->fetchProject();
1024 if (!empty($object->project->ref)) {
1025 $posy += 3;
1026 $pdf->SetXY($posx, $posy);
1027 $pdf->SetTextColor(0, 0, 60);
1028 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->project->title), '', 'R');
1029 }
1030 }
1031
1032 if (getDolGlobalInt('PDF_SHOW_PROJECT')) {
1033 $object->fetchProject();
1034 if (!empty($object->project->ref)) {
1035 $outputlangs->load("projects");
1036 $posy += 3;
1037 $pdf->SetXY($posx, $posy);
1038 $pdf->SetTextColor(0, 0, 60);
1039 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefProject")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R');
1040 }
1041 }
1042
1043 $posy += 4;
1044 $pdf->SetXY($posx, $posy);
1045 $pdf->SetTextColor(0, 0, 60);
1046
1047 $title = $outputlangs->transnoentities("Date");
1048 if (getDolGlobalInt('PDF_USE_ALSO_LANGUAGE_CODE') && is_object($outputlangsbis)) {
1049 $title .= ' - '.$outputlangsbis->transnoentities("Date");
1050 }
1051 $pdf->MultiCell($w, 3, $title." : ".dol_print_date($object->date_creation, "day", false, $outputlangs, true), '', 'R');
1052
1053 if (!getDolGlobalString('MAIN_PDF_HIDE_CUSTOMER_CODE') && !empty($object->thirdparty->code_client)) {
1054 $posy += 3;
1055 $pdf->SetXY($posx, $posy);
1056 $pdf->SetTextColor(0, 0, 60);
1057 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R');
1058 }
1059
1060 if (!getDolGlobalString('MAIN_PDF_HIDE_CUSTOMER_ACCOUNTING_CODE') && !empty($object->thirdparty->code_compta_client)) {
1061 $posy += 3;
1062 $pdf->SetXY($posx, $posy);
1063 $pdf->SetTextColor(0, 0, 60);
1064 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerAccountancyCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_compta_client), '', 'R');
1065 }
1066
1067 // Get contact
1068 if (getDolGlobalInt('DOC_SHOW_FIRST_SALES_REP')) {
1069 $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1070 if (count($arrayidcontact) > 0) {
1071 $usertmp = new User($this->db);
1072 $usertmp->fetch($arrayidcontact[0]);
1073 $posy += 4;
1074 $pdf->SetXY($posx, $posy);
1075 $pdf->SetTextColor(0, 0, 60);
1076 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
1077 }
1078 }
1079
1080 $posy += 1;
1081
1082 $top_shift = 0;
1083 // Show list of linked objects
1084 $current_y = $pdf->getY();
1085 $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size);
1086 if ($current_y < $pdf->getY()) {
1087 $top_shift = $pdf->getY() - $current_y;
1088 }
1089
1090 if ($showaddress) {
1091 // Sender properties
1092 $carac_emetteur = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
1093
1094 // Show sender
1095 $posy = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 40 : 42;
1096 $posy += $top_shift;
1097 $posx = $this->marge_gauche;
1098 if (getDolGlobalInt('MAIN_INVERT_SENDER_RECIPIENT')) {
1099 $posx = $this->page_largeur - $this->marge_droite - 80;
1100 }
1101
1102 $hautcadre = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 38 : 40;
1103 $widthrecbox = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 92 : 82;
1104
1105
1106 // Show sender frame
1107 if (!getDolGlobalString('MAIN_PDF_NO_SENDER_FRAME')) {
1108 $pdf->SetTextColor(0, 0, 0);
1109 $pdf->SetFont('', '', $default_font_size - 2);
1110 $pdf->SetXY($posx, $posy - 5);
1111 $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillFrom").":", 0, $ltrdirection);
1112 $pdf->SetXY($posx, $posy);
1113 $pdf->SetFillColor(230, 230, 230);
1114 $pdf->MultiCell($widthrecbox, $hautcadre, "", 0, 'R', true);
1115 $pdf->SetTextColor(0, 0, 60);
1116 }
1117
1118 // Show sender name
1119 if (!getDolGlobalString('MAIN_PDF_HIDE_SENDER_NAME')) {
1120 $pdf->SetXY($posx + 2, $posy + 3);
1121 $pdf->SetFont('', 'B', $default_font_size);
1122 $pdf->MultiCell($widthrecbox - 2, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, $ltrdirection);
1123 $posy = $pdf->getY();
1124 }
1125
1126 // Show sender information
1127 $pdf->SetXY($posx + 2, $posy);
1128 $pdf->SetFont('', '', $default_font_size - 1);
1129 $pdf->MultiCell($widthrecbox - 2, 4, $carac_emetteur, 0, $ltrdirection);
1130
1131 // If BILLING contact defined, we use it
1132 $usecontact = false;
1133 $arrayidcontact = $object->getIdContact('external', 'BILLING');
1134 if (count($arrayidcontact) > 0) {
1135 $usecontact = true;
1136 $result = $object->fetch_contact($arrayidcontact[0]);
1137 }
1138
1139 // Recipient name
1140 if ($usecontact && $object->contact->socid != $object->thirdparty->id && getDolGlobalInt('MAIN_USE_COMPANY_NAME_OF_CONTACT')) {
1141 $thirdparty = $object->contact;
1142 } else {
1143 $thirdparty = $object->thirdparty;
1144 }
1145
1146 if (is_object($thirdparty)) {
1147 $carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);
1148 } else {
1149 $carac_client_name = null;
1150 }
1151
1152 $mode = 'target';
1153 $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), ($usecontact ? 1 : 0), $mode, $object);
1154
1155 // Show recipient
1156 $widthrecbox = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 92 : 100;
1157 if ($this->page_largeur < 210) {
1158 $widthrecbox = 84; // To work with US executive format
1159 }
1160 $posy = getDolGlobalInt('MAIN_PDF_USE_ISO_LOCATION') ? 40 : 42;
1161 $posy += $top_shift;
1162 $posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
1163 if (getDolGlobalInt('MAIN_INVERT_SENDER_RECIPIENT')) {
1164 $posx = $this->marge_gauche;
1165 }
1166
1167 // Show recipient frame
1168 if (!getDolGlobalString('MAIN_PDF_NO_RECIPENT_FRAME')) {
1169 $pdf->SetTextColor(0, 0, 0);
1170 $pdf->SetFont('', '', $default_font_size - 2);
1171 $pdf->SetXY($posx + 2, $posy - 5);
1172 $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("To").":", 0, $ltrdirection);
1173 $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
1174 }
1175
1176 // Show recipient name
1177 $pdf->SetXY($posx + 2, $posy + 3);
1178 $pdf->SetFont('', 'B', $default_font_size);
1179 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
1180 $pdf->MultiCell($widthrecbox, 2, (string) $carac_client_name, 0, $ltrdirection);
1181
1182 $posy = $pdf->getY();
1183
1184 // Show recipient information
1185 $pdf->SetFont('', '', $default_font_size - 1);
1186 $pdf->SetXY($posx + 2, $posy);
1187 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
1188 $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, $ltrdirection);
1189 }
1190
1191 $pdf->SetTextColor(0, 0, 0);
1192 return $top_shift;
1193 }
1194
1195 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1205 protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
1206 {
1207 global $conf;
1208 $showdetails = !getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS') ? 0 : getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS');
1209 return pdf_pagefoot($pdf, $outputlangs, 'INVOICE_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext);
1210 }
1211
1222 public function defineColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1223 {
1224 global $hookmanager;
1225
1226 // Default field style for content
1227 $this->defaultContentsFieldsStyle = array(
1228 'align' => 'R', // R,C,L
1229 'padding' => array(1, 0.5, 1, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1230 );
1231
1232 // Default field style for content
1233 $this->defaultTitlesFieldsStyle = array(
1234 'align' => 'C', // R,C,L
1235 'padding' => array(0.5, 0, 0.5, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1236 );
1237
1238 /*
1239 * For example
1240 $this->cols['theColKey'] = array(
1241 'rank' => $rank, // int : use for ordering columns
1242 'width' => 20, // the column width in mm
1243 'title' => array(
1244 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
1245 'label' => ' ', // the final label : used fore final generated text
1246 'align' => 'L', // text alignment : R,C,L
1247 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1248 ),
1249 'content' => array(
1250 'align' => 'L', // text alignment : R,C,L
1251 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1252 ),
1253 );
1254 */
1255
1256 $rank = 0; // do not use negative rank
1257 $this->cols['desc'] = array(
1258 'rank' => $rank,
1259 'width' => false, // only for desc
1260 'status' => true,
1261 'title' => array(
1262 'textkey' => 'Designation', // use lang key is useful in some case with module
1263 'align' => 'L',
1264 // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
1265 // 'label' => ' ', // the final label
1266 'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1267 ),
1268 'content' => array(
1269 'align' => 'L',
1270 'padding' => array(1, 0.5, 1, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1271 ),
1272 );
1273
1274 // PHOTO
1275 // $rank += 10;
1276 // $this->cols['photo'] = array(
1277 // 'rank' => $rank,
1278 // 'width' => (!getDolGlobalInt('MAIN_DOCUMENTS_WITH_PICTURE_WIDTH') ? 20 : getDolGlobalInt('MAIN_DOCUMENTS_WITH_PICTURE_WIDTH')), // in mm
1279 // 'status' => false,
1280 // 'title' => array(
1281 // 'textkey' => 'Photo',
1282 // 'label' => ' '
1283 // ),
1284 // 'content' => array(
1285 // 'padding' => array(0, 0, 0, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1286 // ),
1287 // 'border-left' => false, // remove left line separator
1288 // );
1289
1290 // if (getDolGlobalInt('MAIN_GENERATE_INVOICES_WITH_PICTURE') && !empty($this->atleastonephoto)) {
1291 // $this->cols['photo']['status'] = true;
1292 // }
1293
1294
1295 $rank += 10;
1296 $this->cols['vat'] = array(
1297 'rank' => $rank,
1298 'status' => false,
1299 'width' => 16, // in mm
1300 'title' => array(
1301 'textkey' => 'VAT'
1302 ),
1303 'border-left' => true, // add left line separator
1304 );
1305
1306 if (!getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT') && !getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN')) {
1307 $this->cols['vat']['status'] = true;
1308 }
1309
1310 $rank += 10;
1311 $this->cols['subprice'] = array(
1312 'rank' => $rank,
1313 'width' => 19, // in mm
1314 'status' => true,
1315 'title' => array(
1316 'textkey' => 'PriceUHT'
1317 ),
1318 'border-left' => true, // add left line separator
1319 );
1320
1321 $rank += 10;
1322 $this->cols['qty'] = array(
1323 'rank' => $rank,
1324 'width' => 16, // in mm
1325 'status' => true,
1326 'title' => array(
1327 'textkey' => 'Qty'
1328 ),
1329 'border-left' => true, // add left line separator
1330 );
1331
1332 $rank += 10;
1333 $this->cols['unit'] = array(
1334 'rank' => $rank,
1335 'width' => 11, // in mm
1336 'status' => false,
1337 'title' => array(
1338 'textkey' => 'Unit'
1339 ),
1340 'border-left' => true, // add left line separator
1341 );
1342 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1343 $this->cols['unit']['status'] = true;
1344 }
1345
1346 $rank += 10;
1347 $this->cols['discount'] = array(
1348 'rank' => $rank,
1349 'width' => 13, // in mm
1350 'status' => false,
1351 'title' => array(
1352 'textkey' => 'ReductionShort'
1353 ),
1354 'border-left' => true, // add left line separator
1355 );
1356 if ($this->atleastonediscount) {
1357 $this->cols['discount']['status'] = true;
1358 }
1359
1360 $rank += 1000; // add a big offset to be sure is the last col because default extrafield rank is 100
1361 $this->cols['totalexcltax'] = array(
1362 'rank' => $rank,
1363 'width' => 26, // in mm
1364 'status' => true,
1365 'title' => array(
1366 'textkey' => 'TotalHTShort'
1367 ),
1368 'border-left' => true, // add left line separator
1369 );
1370
1371 // Add extrafields cols
1372 if (!empty($object->lines)) {
1373 $line = reset($object->lines);
1374 $this->defineColumnExtrafield($line, $outputlangs, $hidedetails);
1375 }
1376
1377 $parameters = array(
1378 'object' => $object,
1379 'outputlangs' => $outputlangs,
1380 'hidedetails' => $hidedetails,
1381 'hidedesc' => $hidedesc,
1382 'hideref' => $hideref
1383 );
1384
1385 $reshook = $hookmanager->executeHooks('defineColumnField', $parameters, $this); // Note that $object may have been modified by hook
1386 if ($reshook < 0) {
1387 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1388 } elseif (empty($reshook)) {
1389 // @phan-suppress-next-line PhanPluginSuspiciousParamOrderInternal
1390 $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys
1391 } else {
1392 $this->cols = $hookmanager->resArray;
1393 }
1394 }
1395}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
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
printRect($pdf, $x, $y, $l, $h, $hidetop=0, $hidebottom=0)
Rect pdf.
getExtrafieldContent($object, $extrafieldKey, $outputlangs=null)
get extrafield content for pdf writeHtmlCell compatibility usage for PDF line columns and object note...
defineColumnExtrafield($object, $outputlangs, $hidedetails=0)
Define Array Column Field for extrafields.
Parent class of all other business classes for details of elements (invoices, contracts,...
Class to manage hooks.
Parent class for document models.
Class to manage translations.
Class to manage Dolibarr users.
Class to manage PDF template standard_myobject.
defineColumnField($object, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Define Array Column Field.
_pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis=null)
Show top header of page.
write_file($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0)
Function to build and write pdf to disk.
static liste_modeles($db, $maxfilenamelength=0)
Return list of active generation models.
_tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='', $outputlangsbis=null)
Show table for lines.
_pagefoot(&$pdf, $object, $outputlangs, $hidefreetext=0)
Show footer of page.
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
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...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
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.
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.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
if(!function_exists( 'utf8_encode')) if(!function_exists('utf8_decode')) 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).
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.
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)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
pdf_getFormat($outputlangs=null, $mode='setup')
Return array with format properties of default PDF format.
Definition pdf.lib.php:87
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_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_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_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition pdf.lib.php:268
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_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
pdf_watermark(&$pdf, $outputlangs, $h, $w, $unit, $text)
Add a draft watermark on PDF files.
Definition pdf.lib.php:844
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