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