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