dolibarr 24.0.2
pdf_zenith.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-2011 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerke@telenet.be>
5 * Copyright (C) 2010-2014 Juanjo Menent <jmenent@2byte.es>
6 * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
7 * Copyright (C) 2017 Ferran Marcet <fmarcet@2byte.es>
8 * Copyright (C) 2018-2026 Frédéric France <frederic.france@free.fr>
9 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
10 * Copyright (C) 2024 Nick Fragoulis
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24 * or see https://www.gnu.org/
25 */
26
33require_once DOL_DOCUMENT_ROOT.'/core/modules/supplier_proposal/modules_supplier_proposal.php';
34require_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class.php';
35require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
36require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
37require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
38require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
39
40
45{
49 public $db;
50
54 public $name;
55
59 public $description;
60
64 public $update_main_doc_field;
65
69 public $type;
70
75 public $version = 'dolibarr';
76
77
83 public function __construct($db)
84 {
85 global $conf, $langs, $mysoc;
86
87 // Load translation files required by the page
88 $langs->loadLangs(array("main", "bills"));
89
90 $this->db = $db;
91 $this->name = "zenith";
92 $this->description = $langs->trans('DocModelZenithDescription');
93 $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template
94
95 // Page size for A4 format
96 $this->type = 'pdf';
97 $formatarray = pdf_getFormat();
98 $this->page_largeur = $formatarray['width'];
99 $this->page_hauteur = $formatarray['height'];
100 $this->format = array($this->page_largeur, $this->page_hauteur);
101 $this->marge_gauche = getDolGlobalInt('MAIN_PDF_MARGIN_LEFT', 10);
102 $this->marge_droite = getDolGlobalInt('MAIN_PDF_MARGIN_RIGHT', 10);
103 $this->marge_haute = getDolGlobalInt('MAIN_PDF_MARGIN_TOP', 10);
104 $this->marge_basse = getDolGlobalInt('MAIN_PDF_MARGIN_BOTTOM', 10);
105 $this->corner_radius = getDolGlobalInt('MAIN_PDF_FRAME_CORNER_RADIUS', 0);
106 $this->option_logo = 1; // Display logo
107 $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION
108 $this->option_modereg = 1; // Display payment mode
109 $this->option_condreg = 1; // Display payment terms
110 $this->option_multilang = 1; //Available in several languages
111 $this->option_escompte = 0; // Displays if there has been a discount
112 $this->option_credit_note = 0; // Support credit notes
113 $this->option_freetext = 1; // Support add of a personalised text
114 $this->option_draft_watermark = 1; // Support add of a watermark on drafts
115
116 // Define position of columns
117 $this->posxdesc = $this->marge_gauche + 1; // For module retrocompatibility support during PDF transition: TODO remove this at the end
118
119 $this->tabTitleHeight = 5; // default height
120
121 $this->tva = array();
122 $this->tva_array = array();
123 $this->localtax1 = array();
124 $this->localtax2 = array();
125 $this->atleastoneratenotnull = 0;
126 $this->atleastonediscount = 0;
127
128 if ($mysoc === null) {
129 dol_syslog(get_class($this).'::__construct() Global $mysoc should not be null.'. getCallerInfoString(), LOG_ERR);
130 return;
131 }
132
133 // Get source company
134 $this->emetteur = $mysoc;
135 if (empty($this->emetteur->country_code)) {
136 $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined
137 }
138 }
139
140
141 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
153 public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
154 {
155 // phpcs:enable
156 global $user, $langs, $conf, $hookmanager, $mysoc, $nblines;
157
158 if (!is_object($outputlangs)) {
159 $outputlangs = $langs;
160 }
161 // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
162 if (getDolGlobalString('MAIN_USE_FPDF')) {
163 $outputlangs->charset_output = 'ISO-8859-1';
164 }
165
166 // Load translation files required by the page
167 $outputlangs->loadLangs(array("main", "supplier_proposal", "companies", "bills", "dict", "products"));
168
169 global $outputlangsbis;
170 $outputlangsbis = null;
171 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE') && $outputlangs->defaultlang != getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
172 $outputlangsbis = new Translate('', $conf);
173 $outputlangsbis->setDefaultLang(getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE'));
174 $outputlangsbis->loadLangs(array("main", "supplier_proposal", "companies", "bills", "dict", "products"));
175 }
176
177 $nblines = count($object->lines);
178
179 $hidetop = 0;
180 if (getDolGlobalString('MAIN_PDF_DISABLE_COL_HEAD_TITLE')) {
181 $hidetop = getDolGlobalString('MAIN_PDF_DISABLE_COL_HEAD_TITLE');
182 }
183
184 // Loop on each lines to detect if there is at least one image to show
185 $realpatharray = array();
186 if (getDolGlobalString('MAIN_GENERATE_SUPPLIER_PROPOSAL_WITH_PICTURE')) {
187 for ($i = 0; $i < $nblines; $i++) {
188 if (empty($object->lines[$i]->fk_product)) {
189 continue;
190 }
191
192 $objphoto = new Product($this->db);
193 $objphoto->fetch($object->lines[$i]->fk_product);
194
195 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
196 $pdir = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$object->lines[$i]->fk_product."/photos/";
197 $dir = $conf->product->dir_output.'/'.$pdir;
198 } else {
199 $pdir = get_exdir($objphoto->id, 0, 0, 0, $objphoto, 'product');
200 $dir = $conf->product->dir_output.'/'.$pdir;
201 }
202
203 $realpath = '';
204 foreach ($objphoto->liste_photos($dir, 1) as $key => $obj) {
205 if (!getDolGlobalInt('CAT_HIGH_QUALITY_IMAGES')) { // If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo
206 if ($obj['photo_vignette']) {
207 $filename = $obj['photo_vignette'];
208 } else {
209 $filename = $obj['photo'];
210 }
211 } else {
212 $filename = $obj['photo'];
213 }
214 $realpath = $dir.$filename;
215 break;
216 }
217
218 if ($realpath) {
219 $realpatharray[$i] = $realpath;
220 }
221 }
222 }
223 if (count($realpatharray) == 0) {
224 $this->posxpicture = $this->posxtva;
225 }
226
227 if ($conf->supplier_proposal->dir_output) {
228 $object->fetch_thirdparty();
229
230 $deja_regle = 0;
231 $amount_credit_notes_included = 0;
232 $amount_deposits_included = 0;
233 //$amount_credit_notes_included = $object->getSumCreditNotesUsed();
234 //$amount_deposits_included = $object->getSumDepositsUsed();
235
236 // Definition of $dir and $file
237 if ($object->specimen) {
238 $dir = $conf->supplier_proposal->dir_output;
239 $file = $dir."/SPECIMEN.pdf";
240 } else {
241 $objectref = dol_sanitizeFileName($object->ref);
242 $objectrefsupplier = dol_sanitizeFileName($object->ref_supplier);
243 $dir = $conf->supplier_proposal->dir_output.'/'.$objectref;
244 $file = $dir."/".$objectref.".pdf";
245 if (getDolGlobalString('SUPPLIER_REF_IN_NAME')) {
246 $file = $dir."/".$objectref.($objectrefsupplier ? "_".$objectrefsupplier : "").".pdf";
247 }
248 }
249
250 if (!file_exists($dir)) {
251 if (dol_mkdir($dir) < 0) {
252 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
253 return 0;
254 }
255 }
256
257 if (file_exists($dir)) {
258 // Add pdfgeneration hook
259 if (!is_object($hookmanager)) {
260 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
261 $hookmanager = new HookManager($this->db);
262 }
263 $hookmanager->initHooks(array('pdfgeneration'));
264 $parameters = array('file' => $file, 'object' => $object, 'outputlangs' => $outputlangs);
265 global $action;
266 $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
267
268 $nblines = count($object->lines);
269
270 $pdf = pdf_getInstance($this->format);
271 $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
272 $heightforinfotot = 50; // Height reserved to output the info and total part
273 $heightforfreetext = getDolGlobalInt('MAIN_PDF_FREETEXT_HEIGHT', 5); // Height reserved to output the free text on last page
274 $heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin)
275 if (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS')) {
276 $heightforfooter += 6;
277 }
278 $pdf->setAutoPageBreak(true, 0);
279
280 if (class_exists('TCPDF')) {
281 $pdf->setPrintHeader(false);
282 $pdf->setPrintFooter(false);
283 }
284 $pdf->SetFont(pdf_getPDFFont($outputlangs));
285 // Set path to the background PDF File
286 if (getDolGlobalString('MAIN_ADD_PDF_BACKGROUND')) {
287 $pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/' . getDolGlobalString('MAIN_ADD_PDF_BACKGROUND'));
288 $tplidx = $pdf->importPage(1);
289 }
290
291 $pdf->Open();
292 $pagenb = 0;
293 $pdf->SetDrawColor(128, 128, 128);
294
295 $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
296 $pdf->SetSubject($outputlangs->transnoentities("SupplierProposal"));
297 $pdf->SetCreator("Dolibarr ".DOL_VERSION);
298 $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getAnonymisableFullName($outputlangs)));
299 $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("SupplierProposal")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
300 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
301 $pdf->SetCompression(false);
302 }
303
304 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
305 $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
306
307 // Does we have at least one line with discount $this->atleastonediscount
308 foreach ($object->lines as $line) {
309 if ($line->remise_percent) {
310 $this->atleastonediscount = true;
311 break;
312 }
313 }
314
315 // New page
316 $pdf->AddPage();
317 if (!empty($tplidx)) {
318 $pdf->useTemplate($tplidx);
319 }
320 $pagenb++;
321 $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs);
322 $pdf->SetFont('', '', $default_font_size - 1);
323 $pdf->MultiCell(0, 3, ''); // Set interline to 3
324 $pdf->SetTextColor(0, 0, 0);
325
326 $tab_top = 80 + $this->marge_haute + $top_shift;
327 $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 32 + $this->marge_haute + $top_shift : $this->marge_haute);
328
329 $tab_height = $this->page_hauteur - $tab_top - $heightforfooter - $heightforfreetext;
330
331 // Incoterm
332 if (isModEnabled('incoterm')) {
333 $desc_incoterms = $object->getIncotermsForPDF();
334 if ($desc_incoterms) {
335 $tab_top -= 2;
336
337 $pdf->SetFont('', '', $default_font_size - 1);
338 $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($desc_incoterms), 0, 1);
339 $nexY = $pdf->GetY();
340 $height_incoterms = $nexY - $tab_top;
341
342 // Rect takes a length in 3rd parameter
343 $pdf->SetDrawColor(192, 192, 192);
344 $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');
345
346 $tab_top = $nexY + 6;
347 }
348 }
349
350 // Affiche notes
351 $notetoshow = empty($object->note_public) ? '' : $object->note_public;
352
353 // Extrafields in note
354 $extranote = $this->getExtrafieldsInHtml($object, $outputlangs);
355 if (!empty($extranote)) {
356 $notetoshow = dol_concatdesc($notetoshow, $extranote);
357 }
358
359 $pagenb = $pdf->getPage();
360 if ($notetoshow) {
361 $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite;
362 $pageposbeforenote = $pagenb;
363
364 $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
365 complete_substitutions_array($substitutionarray, $outputlangs, $object);
366 $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
367 $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);
368
369 $tab_top -= 2;
370
371 $pdf->startTransaction();
372
373 $pdf->SetFont('', '', $default_font_size - 1);
374 $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
375 // Description
376 $pageposafternote = $pdf->getPage();
377 $posyafter = $pdf->GetY();
378
379 if ($pageposafternote > $pageposbeforenote) {
380 $pdf->rollbackTransaction(true);
381
382 // prepar pages to receive notes
383 while ($pagenb < $pageposafternote) {
384 $pdf->AddPage();
385 $pagenb++;
386 if (!empty($tplidx)) {
387 $pdf->useTemplate($tplidx);
388 }
389 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
390 $this->_pagehead($pdf, $object, 0, $outputlangs);
391 }
392 // $this->_pagefoot($pdf,$object,$outputlangs,1);
393 $pdf->setTopMargin($tab_top_newpage);
394 // The only function to edit the bottom margin of current page to set it.
395 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext);
396 }
397
398 // back to start
399 $pdf->setPage($pageposbeforenote);
400 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext);
401 $pdf->SetFont('', '', $default_font_size - 1);
402 $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
403 $pageposafternote = $pdf->getPage();
404
405 $posyafter = $pdf->GetY();
406
407 if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) { // There is no space left for total+free text
408 $pdf->AddPage('', '', true);
409 $pagenb++;
410 $pageposafternote++;
411 $pdf->setPage($pageposafternote);
412 $pdf->setTopMargin($tab_top_newpage);
413 // The only function to edit the bottom margin of current page to set it.
414 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext);
415 //$posyafter = $tab_top_newpage;
416 }
417
418
419 // apply note frame to previous pages
420 $i = $pageposbeforenote;
421 while ($i < $pageposafternote) {
422 $pdf->setPage($i);
423
424
425 $pdf->SetDrawColor(128, 128, 128);
426 // Draw note frame
427 if ($i > $pageposbeforenote) {
428 $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter);
429 $pdf->RoundedRect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 2, $this->corner_radius, '1234', 'D');
430 } else {
431 $height_note = $this->page_hauteur - ($tab_top + $heightforfooter);
432 $pdf->RoundedRect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 2, $this->corner_radius, '1234', 'D');
433 }
434
435 // Add footer
436 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
437 $this->_pagefoot($pdf, $object, $outputlangs, 1);
438
439 $i++;
440 }
441
442 // apply note frame to last page
443 $pdf->setPage($pageposafternote);
444 if (!empty($tplidx)) {
445 $pdf->useTemplate($tplidx);
446 }
447 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
448 $this->_pagehead($pdf, $object, 0, $outputlangs);
449 }
450 $height_note = $posyafter - $tab_top_newpage;
451 $pdf->RoundedRect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 2, $this->corner_radius, '1234', 'D');
452 } else {
453 // No pagebreak
454 $pdf->commitTransaction();
455 $posyafter = $pdf->GetY();
456 $height_note = $posyafter - $tab_top;
457 $pdf->RoundedRect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 2, $this->corner_radius, '1234', 'D');
458
459
460 if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20))) {
461 // not enough space, need to add page
462 $pdf->AddPage('', '', true);
463 $pagenb++;
464 $pageposafternote++;
465 $pdf->setPage($pageposafternote);
466 if (!empty($tplidx)) {
467 $pdf->useTemplate($tplidx);
468 }
469 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
470 $this->_pagehead($pdf, $object, 0, $outputlangs);
471 }
472
473 $posyafter = $tab_top_newpage;
474 }
475 }
476
477 $tab_height -= $height_note;
478 $tab_top = $posyafter + 6;
479 } else {
480 $height_note = 0;
481 }
482
483 // Use new auto column system
484 $this->prepareArrayColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref);
485
486 $nexY = $tab_top + $this->tabTitleHeight;
487
488 $pageposbeforeprintlines = $pdf->getPage();
489 $pagenb = $pageposbeforeprintlines;
490 $pdf_sub_options = [
491 'titleshowuponpdf' => 1,
492 'titleshowtotalexludingvatonpdf' => 1,
493 ];
494
495 // Loop on each lines
496 for ($i = 0; $i < $nblines; $i++) {
497 $sub_options = $object->lines[$i]->extraparams["subtotal"] ?? array();
498
499 if ($object->lines[$i]->special_code == SUBTOTALS_SPECIAL_CODE) {
500 $level = $object->lines[$i]->qty;
501 if ($sub_options) {
502 if (isset($sub_options['titleshowuponpdf'])) {
503 $pdf_sub_options['titleshowuponpdf'] = isset($pdf_sub_options['titleshowuponpdf']) && $pdf_sub_options['titleshowuponpdf'] < $level ? $pdf_sub_options['titleshowuponpdf'] : $level;
504 } elseif (isset($pdf_sub_options['titleshowuponpdf']) && abs($level) <= $pdf_sub_options['titleshowuponpdf']) {
505 unset($pdf_sub_options['titleshowuponpdf']);
506 }
507 if (isset($sub_options['titleshowtotalexludingvatonpdf'])) {
508 $pdf_sub_options['titleshowtotalexludingvatonpdf'] = isset($pdf_sub_options['titleshowtotalexludingvatonpdf']) && $pdf_sub_options['titleshowtotalexludingvatonpdf'] < $level ? $pdf_sub_options['titleshowtotalexludingvatonpdf'] : $level;
509 } elseif (isset($pdf_sub_options['titleshowtotalexludingvatonpdf']) && abs($level) <= $pdf_sub_options['titleshowtotalexludingvatonpdf']) {
510 unset($pdf_sub_options['titleshowtotalexludingvatonpdf']);
511 }
512 } else {
513 if (isset($pdf_sub_options['titleshowuponpdf']) && abs($level) <= $pdf_sub_options['titleshowuponpdf']) {
514 unset($pdf_sub_options['titleshowuponpdf']);
515 }
516 if (isset($pdf_sub_options['titleshowtotalexludingvatonpdf']) && abs($level) <= $pdf_sub_options['titleshowtotalexludingvatonpdf']) {
517 unset($pdf_sub_options['titleshowtotalexludingvatonpdf']);
518 }
519 }
520 }
521 $curY = $nexY;
522 $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
523 $pdf->SetTextColor(0, 0, 0);
524
525 // Define size of image if we need it
526 $imglinesize = array();
527 if (!empty($realpatharray[$i])) {
528 $imglinesize = pdf_getSizeForImage($realpatharray[$i]);
529 }
530
531 $pdf->setTopMargin($tab_top_newpage);
532 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext + $heightforinfotot); // The only function to edit the bottom margin of current page to set it.
533 $pageposbefore = $pdf->getPage();
534
535 $showpricebeforepagebreak = 1;
536 $posYAfterImage = 0;
537 $posYAfterDescription = 0;
538
539 // We start with Photo of product line
540 if ($this->getColumnStatus('photo')) {
541 // We start with Photo of product line
542 if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) { // If photo too high, we moved completely on new page
543 $pdf->AddPage('', '', true);
544 if (!empty($tplidx)) {
545 $pdf->useTemplate($tplidx);
546 }
547 $pdf->setPage($pageposbefore + 1);
548
549 $curY = $tab_top_newpage;
550
551 // Allows data in the first page if description is long enough to break in multiples pages
552 if (getDolGlobalString('MAIN_PDF_DATA_ON_FIRST_PAGE')) {
553 $showpricebeforepagebreak = 1;
554 } else {
555 $showpricebeforepagebreak = 0;
556 }
557 }
558
559 if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height'])) {
560 $pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY + 1, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi
561 // $pdf->Image does not increase value return by getY, so we save it manually
562 $posYAfterImage = $curY + $imglinesize['height'];
563 }
564 }
565 // Description of product line
566 $curX = $this->posxdesc - 1;
567 $showpricebeforepagebreak = 1;
568
569 if ($this->getColumnStatus('desc') && $object->lines[$i]->special_code == SUBTOTALS_SPECIAL_CODE) {
570 // Title or subtotal line: colored banner, like on other documents (pdf_render_subtotals() manages its own transaction)
571 $bg_color = colorStringToArray(getDolGlobalString("SUBTOTAL_BACK_COLOR_LEVEL_".abs($object->lines[$i]->qty), 'ffffff'));
572 pdf_render_subtotals($pdf, $this, $curY, $object, $i, $outputlangs, $hideref, $hidedesc, $bg_color, true, true);
573 $posYAfterDescription = $pdf->GetY();
574 } elseif ($this->getColumnStatus('desc')) {
575 $pdf->startTransaction();
576 $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc, 1);
577
578 $pageposafter = $pdf->getPage();
579 if ($pageposafter > $pageposbefore) { // There is a pagebreak
580 $pdf->rollbackTransaction(true);
581
582 $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc, 1);
583
584 $pageposafter = $pdf->getPage();
585 $posyafter = $pdf->GetY();
586 if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) { // There is no space left for total+free text
587 if ($i == ($nblines - 1)) { // No more lines, and no space left to show total, so we create a new page
588 $pdf->AddPage('', '', true);
589 if (!empty($tplidx)) {
590 $pdf->useTemplate($tplidx);
591 }
592 //if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) $this->_pagehead($pdf, $object, 0, $outputlangs);
593 $pdf->setPage($pageposafter + 1);
594 }
595 } else {
596 // We found a page break
597 // Allows data in the first page if description is long enough to break in multiples pages
598 if (getDolGlobalString('MAIN_PDF_DATA_ON_FIRST_PAGE')) {
599 $showpricebeforepagebreak = 1;
600 } else {
601 $showpricebeforepagebreak = 0;
602 }
603 }
604 } else { // No pagebreak
605 $pdf->commitTransaction();
606 }
607 $posYAfterDescription = $pdf->GetY();
608 }
609
610 $nexY = $pdf->GetY();
611 $pageposafter = $pdf->getPage();
612 $pdf->setPage($pageposbefore);
613 $pdf->setTopMargin($this->marge_haute);
614 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
615
616 // We suppose that a too long description is moved completely on next page
617 if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
618 $pdf->setPage($pageposafter);
619 $curY = $tab_top_newpage;
620 }
621
622 $pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par default
623
624 // VAT Rate
625 if ($this->getColumnStatus('vat') && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
626 $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
627 $this->printStdColumnContent($pdf, $curY, 'vat', $vat_rate);
628 $nexY = max($pdf->GetY(), $nexY);
629 }
630
631 // Unit price before discount
632 if ($this->getColumnStatus('subprice') && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE && isset($pdf_sub_options['titleshowuponpdf'])) {
633 $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);
634 $this->printStdColumnContent($pdf, $curY, 'subprice', $up_excl_tax);
635 $nexY = max($pdf->GetY(), $nexY);
636 }
637
638 // Quantity
639 // Enough for 6 chars
640 if ($this->getColumnStatus('qty') && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
641 $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
642 $this->printStdColumnContent($pdf, $curY, 'qty', $qty);
643 $nexY = max($pdf->GetY(), $nexY);
644 }
645
646
647 // Unit
648 if ($this->getColumnStatus('unit') && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
649 $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails);
650 $this->printStdColumnContent($pdf, $curY, 'unit', $unit);
651 $nexY = max($pdf->GetY(), $nexY);
652 }
653
654 // Discount on line
655 if ($this->getColumnStatus('discount') && $object->lines[$i]->remise_percent && $object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE) {
656 $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);
657 $this->printStdColumnContent($pdf, $curY, 'discount', $remise_percent);
658 $nexY = max($pdf->GetY(), $nexY);
659 }
660
661 // Total HT line
662 if ($this->getColumnStatus('totalexcltax')) {
663 if ($object->lines[$i]->special_code != SUBTOTALS_SPECIAL_CODE && isset($pdf_sub_options['titleshowtotalexludingvatonpdf'])) {
664 $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails);
665 $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax);
666 } elseif ($object->lines[$i]->qty < 0 && isset($sub_options['subtotalshowtotalexludingvatonpdf'])) {
667 if (isModEnabled('multicurrency') && $object->multicurrency_code != $conf->currency) {
668 $total_excl_tax = $object->getSubtotalLineMulticurrencyAmount($object->lines[$i]);
669 } else {
670 $total_excl_tax = $object->getSubtotalLineAmount($object->lines[$i]);
671 }
672 $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax);
673 }
674 $nexY = max($pdf->GetY(), $nexY);
675 }
676
677 // Extrafields
678 if (!empty($object->lines[$i]->array_options)) {
679 foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) {
680 if ($this->getColumnStatus($extrafieldColKey)) {
681 $extrafieldValue = $this->getExtrafieldContent($object->lines[$i], $extrafieldColKey, $outputlangs);
682 $this->printStdColumnContent($pdf, $curY, $extrafieldColKey, $extrafieldValue);
683 $nexY = max($pdf->GetY(), $nexY);
684 }
685 }
686 }
687
688 $parameters = array(
689 'object' => $object,
690 'i' => $i,
691 'pdf' => & $pdf,
692 'curY' => & $curY,
693 'nexY' => & $nexY,
694 'outputlangs' => $outputlangs,
695 'hidedetails' => $hidedetails
696 );
697 $reshook = $hookmanager->executeHooks('printPDFline', $parameters, $this); // Note that $object may have been modified by hook
698
699
700 // // Collect total by value of vat rate into $this->tva["taux"]=total_tva
701 if (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) {
702 $tvaligne = $object->lines[$i]->multicurrency_total_tva;
703 } else {
704 $tvaligne = $object->lines[$i]->total_tva;
705 }
706
707 $localtax1ligne = $object->lines[$i]->total_localtax1;
708 $localtax2ligne = $object->lines[$i]->total_localtax2;
709 $localtax1_rate = $object->lines[$i]->localtax1_tx;
710 $localtax2_rate = $object->lines[$i]->localtax2_tx;
711 $localtax1_type = $object->lines[$i]->localtax1_type;
712 $localtax2_type = $object->lines[$i]->localtax2_type;
713
714 // TODO remise_percent is an obsolete field for object parent
715 /*if (!empty($object->remise_percent)) {
716 $tvaligne -= ($tvaligne * $object->remise_percent) / 100;
717 }
718 if (!empty($object->remise_percent)) {
719 $localtax1ligne -= ($localtax1ligne * $object->remise_percent) / 100;
720 }
721 if (!empty($object->remise_percent)) {
722 $localtax2ligne -= ($localtax2ligne * $object->remise_percent) / 100;
723 }*/
724
725 $vatrate = (string) $object->lines[$i]->tva_tx;
726
727 // Retrieve type from database for backward compatibility with old records
728 if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined
729 && (!empty($localtax1_rate) || !empty($localtax2_rate))) { // and there is local tax
730 $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $mysoc, $object->thirdparty);
731 $localtax1_type = isset($localtaxtmp_array[0]) ? $localtaxtmp_array[0] : '';
732 $localtax2_type = isset($localtaxtmp_array[2]) ? $localtaxtmp_array[2] : '';
733 }
734
735 // retrieve global local tax
736 if ($localtax1_type && $localtax1ligne != 0) {
737 if (empty($this->localtax1[$localtax1_type][$localtax1_rate])) {
738 $this->localtax1[$localtax1_type][$localtax1_rate] = $localtax1ligne;
739 } else {
740 $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne;
741 }
742 }
743 if ($localtax2_type && $localtax2ligne != 0) {
744 if (empty($this->localtax2[$localtax2_type][$localtax2_rate])) {
745 $this->localtax2[$localtax2_type][$localtax2_rate] = (float) $localtax2ligne;
746 } else {
747 $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne;
748 }
749 }
750
751 if (($object->lines[$i]->info_bits & 0x01) == 0x01) {
752 $vatrate .= '*';
753 }
754
755 // Fill $this->tva and $this->tva_array
756 if (!isset($this->tva[$vatrate])) {
757 $this->tva[$vatrate] = 0;
758 }
759 $this->tva[$vatrate] += $tvaligne;
760 $vatcode = $object->lines[$i]->vat_src_code;
761 if (empty($this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'])) {
762 $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] = 0;
763 }
764 $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')] = array('vatrate' => $vatrate, 'vatcode' => $vatcode, 'amount' => $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] + $tvaligne);
765
766 if ($posYAfterImage > $posYAfterDescription) {
767 $nexY = $posYAfterImage;
768 }
769
770 // Add line
771 if (getDolGlobalString('MAIN_PDF_DASH_BETWEEN_LINES') && $i < ($nblines - 1)) {
772 $pdf->setPage($pageposafter);
773 $pdf->SetLineStyle(array('dash' => '1,1', 'color' => array(80, 80, 80)));
774 //$pdf->SetDrawColor(190,190,200);
775 $pdf->line($this->marge_gauche, $nexY, $this->page_largeur - $this->marge_droite, $nexY);
776 $pdf->SetLineStyle(array('dash' => 0));
777 }
778
779 // Detect if some page were added automatically and output _tableau for past pages
780 while ($pagenb < $pageposafter) {
781 $pdf->setPage($pagenb);
782 if ($pagenb == $pageposbeforeprintlines) {
783 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code);
784 } else {
785 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
786 }
787 $this->_pagefoot($pdf, $object, $outputlangs, 1);
788 $pagenb++;
789 $pdf->setPage($pagenb);
790 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
791 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
792 $this->_pagehead($pdf, $object, 0, $outputlangs);
793 }
794 if (!empty($tplidx)) {
795 $pdf->useTemplate($tplidx);
796 }
797 }
798 if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) { // @phan-suppress-current-line PhanUndeclaredProperty
799 if ($pagenb == $pageposafter) {
800 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code);
801 } else {
802 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
803 }
804 $this->_pagefoot($pdf, $object, $outputlangs, 1);
805 // New page
806 $pdf->AddPage();
807 if (!empty($tplidx)) {
808 $pdf->useTemplate($tplidx);
809 }
810 $pagenb++;
811 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
812 $this->_pagehead($pdf, $object, 0, $outputlangs);
813 }
814 }
815 }
816
817 // Show square
818 if ($pagenb == $pageposbeforeprintlines) {
819 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, $hidetop, 0, $object->multicurrency_code);
820 $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
821 } else {
822 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code);
823 $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
824 }
825
826 // Affiche zone infos
827 $posy = $this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs);
828
829 // Affiche zone totaux
830 $posy = $this->_tableau_tot($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs);
831
832 // Affiche zone versements
833 if ($deja_regle || $amount_credit_notes_included || $amount_deposits_included) {
834 $posy = $this->_tableau_versements($pdf, $object, $posy, $outputlangs);
835 }
836
837 // Pied de page
838 $this->_pagefoot($pdf, $object, $outputlangs);
839 if (method_exists($pdf, 'AliasNbPages')) {
840 $pdf->AliasNbPages(); // @phan-suppress-current-line PhanUndeclaredMethod
841 }
842
843 $pdf->Close();
844
845 $pdf->Output($file, 'F');
846
847 // Add pdfgeneration hook
848 $hookmanager->initHooks(array('pdfgeneration'));
849 $parameters = array('file' => $file, 'object' => $object, 'outputlangs' => $outputlangs);
850 global $action;
851 $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
852 $this->warnings = $hookmanager->warnings;
853 if ($reshook < 0) {
854 $this->error = $hookmanager->error;
855 $this->errors = $hookmanager->errors;
856 dolChmod($file);
857 return -1;
858 }
859
860 dolChmod($file);
861
862 $this->result = array('fullpath' => $file);
863
864 return 1; // No error
865 } else {
866 $this->error = $langs->trans("ErrorCanNotCreateDir", $dir);
867 return 0;
868 }
869 } else {
870 $this->error = $langs->trans("ErrorConstantNotDefined", "SUPPLIER_OUTPUTDIR");
871 return 0;
872 }
873 }
874
875 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
876 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
886 protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs)
887 {
888 // phpcs:enable
889 return 1;
890 }
891
892 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
893 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
903 protected function _tableau_info(&$pdf, $object, $posy, $outputlangs)
904 {
905 // phpcs:enable
906 global $conf, $mysoc;
907 $default_font_size = pdf_getPDFFontSize($outputlangs);
908
909 $diffsizetitle = getDolGlobalInt('PDF_DIFFSIZE_TITLE', 3);
910
911 // If France, show VAT mention if not applicable
912 if ($this->emetteur->country_code == 'FR' && empty($mysoc->tva_assuj)) {
913 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
914 $pdf->SetXY($this->marge_gauche, $posy);
915 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', false);
916
917 $posy = $pdf->GetY() + 4;
918 }
919
920 $posxval = 52;
921
922 // Show payments conditions
923 if (!empty($object->cond_reglement_code) || $object->cond_reglement) {
924 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
925 $pdf->SetXY($this->marge_gauche, $posy);
926 $titre = $outputlangs->transnoentities("PaymentConditions").':';
927 $pdf->MultiCell(80, 4, $titre, 0, 'L');
928
929 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
930 $pdf->SetXY($posxval, $posy);
931 $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);
932 $lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
933 if ($object->deposit_percent > 0) {
934 $lib_condition_paiement = str_replace('__DEPOSIT_PERCENT__', $object->deposit_percent, $lib_condition_paiement);
935 }
936 $pdf->MultiCell(80, 4, $lib_condition_paiement, 0, 'L');
937
938 $posy = $pdf->GetY() + 3;
939 }
940
941 // Show payment mode
942 if (!empty($object->mode_reglement_code)) {
943 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
944 $pdf->SetXY($this->marge_gauche, $posy);
945 $titre = $outputlangs->transnoentities("PaymentMode").':';
946 $pdf->MultiCell(80, 5, $titre, 0, 'L');
947
948 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
949 $pdf->SetXY($posxval, $posy);
950 $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);
951 $pdf->MultiCell(80, 5, $lib_mode_reg, 0, 'L');
952
953 $posy = $pdf->GetY() + 2;
954 }
955
956
957 return $posy;
958 }
959
960 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
961 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
972 protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs)
973 {
974 // phpcs:enable
975 global $conf, $mysoc;
976
977 $default_font_size = pdf_getPDFFontSize($outputlangs);
978
979 $tab2_top = $posy;
980 $tab2_hl = 4;
981 $pdf->SetFont('', '', $default_font_size - 1);
982
983 // Tableau total
984 $col1x = 120;
985 $col2x = 170;
986 if ($this->page_largeur < 210) { // To work with US executive format
987 $col2x -= 20;
988 }
989 $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
990
991 $useborder = 0;
992 $index = 0;
993
994 // Total HT
995 $pdf->SetFillColor(255, 255, 255);
996 $pdf->SetXY($col1x, $tab2_top);
997 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', true);
998
999 $total_ht = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht);
1000 $pdf->SetXY($col2x, $tab2_top);
1001 $pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + (!empty($object->remise) ? $object->remise : 0)), 0, 'R', true);
1002
1003 // Show VAT by rates and total
1004 $pdf->SetFillColor(248, 248, 248);
1005
1006 $this->atleastoneratenotnull = 0;
1007 foreach ($this->tva as $tvakey => $tvaval) {
1008 if ($tvakey > 0) { // On affiche pas taux 0
1009 $this->atleastoneratenotnull++;
1010
1011 $index++;
1012 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1013
1014 $tvacompl = '';
1015
1016 if (preg_match('/\*/', $tvakey)) {
1017 $tvakey = str_replace('*', '', $tvakey);
1018 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1019 }
1020
1021 $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).' ';
1022 $totalvat .= vatrate($tvakey, true).$tvacompl;
1023 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1024
1025 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1026 $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval), 0, 'R', true);
1027 }
1028 }
1029 if (!$this->atleastoneratenotnull) { // If no vat at all
1030 $index++;
1031 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1032 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code), 0, 'L', true);
1033
1034 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1035 $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_tva), 0, 'R', true);
1036
1037 // Total LocalTax1
1038 if (getDolGlobalString('FACTURE_LOCAL_TAX1_OPTION') == 'localtax1on' && $object->total_localtax1 > 0) {
1039 $index++;
1040 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1041 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code), 0, 'L', true);
1042 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1043 $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_localtax1), $useborder, 'R', true);
1044 }
1045
1046 // Total LocalTax2
1047 if (getDolGlobalString('FACTURE_LOCAL_TAX2_OPTION') == 'localtax2on' && $object->total_localtax2 > 0) {
1048 $index++;
1049 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1050 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code), 0, 'L', true);
1051 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1052 $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_localtax2), $useborder, 'R', true);
1053 }
1054 } else {
1055 //if (getDolGlobalString('FACTURE_LOCAL_TAX1_OPTION') && getDolGlobalString('FACTURE_LOCAL_TAX1_OPTION') == 'localtax1on')
1056 //{
1057 //Local tax 1
1058 foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1059 if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1060 continue;
1061 }
1062
1063 foreach ($localtax_rate as $tvakey => $tvaval) {
1064 if ($tvakey != 0) { // On affiche pas taux 0
1065 //$this->atleastoneratenotnull++;
1066
1067 $index++;
1068 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1069
1070 $tvacompl = '';
1071 if (preg_match('/\*/', $tvakey)) {
1072 $tvakey = str_replace('*', '', $tvakey);
1073 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1074 }
1075 $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).' ';
1076 $totalvat .= vatrate((string) abs((float) $tvakey), true).$tvacompl;
1077 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1078
1079 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1080 $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', true);
1081 }
1082 }
1083 }
1084
1085 //if (getDolGlobalString('FACTURE_LOCAL_TAX2_OPTION') && getDolGlobalString('FACTURE_LOCAL_TAX2_OPTION') == 'localtax2on')
1086 //{
1087 //Local tax 2
1088 foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1089 if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1090 continue;
1091 }
1092
1093 foreach ($localtax_rate as $tvakey => $tvaval) {
1094 if ($tvakey != 0) { // On affiche pas taux 0
1095 //$this->atleastoneratenotnull++;
1096
1097 $index++;
1098 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1099
1100 $tvacompl = '';
1101 if (preg_match('/\*/', $tvakey)) {
1102 $tvakey = str_replace('*', '', $tvakey);
1103 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1104 }
1105 $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' ';
1106 $totalvat .= vatrate((string) abs((float) $tvakey), true).$tvacompl;
1107 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true);
1108
1109 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1110 $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval), 0, 'R', true);
1111 }
1112 }
1113 }
1114 }
1115
1116 // Total TTC
1117 $index++;
1118 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1119 $pdf->SetTextColor(0, 0, 60);
1120 $pdf->SetFillColor(224, 224, 224);
1121 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', true);
1122
1123 $total_ttc = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
1124 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1125 $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc), $useborder, 'R', true);
1126 $pdf->SetFont('', '', $default_font_size - 1);
1127 $pdf->SetTextColor(0, 0, 0);
1128
1129 $creditnoteamount = 0;
1130 $depositsamount = 0;
1131 //$creditnoteamount=$object->getSumCreditNotesUsed();
1132 //$depositsamount=$object->getSumDepositsUsed();
1133 //print "x".$creditnoteamount."-".$depositsamount;exit;
1134 $resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT');
1135 if (!empty($object->paye)) {
1136 $resteapayer = 0;
1137 }
1138
1139 if ($deja_regle > 0) {
1140 // Already paid + Deposits
1141 $index++;
1142
1143 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1144 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid"), 0, 'L', false);
1145 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1146 $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle), 0, 'R', false);
1147
1148 $index++;
1149 $pdf->SetTextColor(0, 0, 60);
1150 $pdf->SetFillColor(224, 224, 224);
1151 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1152 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', true);
1153
1154 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1155 $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer), $useborder, 'R', true);
1156
1157 $pdf->SetFont('', '', $default_font_size - 1);
1158 $pdf->SetTextColor(0, 0, 0);
1159 }
1160
1161 $index++;
1162 return ($tab2_top + ($tab2_hl * $index));
1163 }
1164
1165 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1179 protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '')
1180 {
1181 global $conf;
1182
1183 // Force to disable hidetop and hidebottom
1184 $hidebottom = 0;
1185 if ($hidetop) {
1186 $hidetop = -1;
1187 }
1188
1189 $currency = !empty($currency) ? $currency : $conf->currency;
1190 $default_font_size = pdf_getPDFFontSize($outputlangs);
1191
1192 // Amount in (at tab_top - 1)
1193 $pdf->SetTextColor(0, 0, 0);
1194 $pdf->SetFont('', '', $default_font_size - 2);
1195
1196 if (empty($hidetop)) {
1197 $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
1198 $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
1199 $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
1200
1201 //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
1202 if (getDolGlobalString('MAIN_PDF_TITLE_BACKGROUND_COLOR')) {
1203 $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')));
1204 }
1205 }
1206
1207 $pdf->SetDrawColor(128, 128, 128);
1208 $pdf->SetFont('', '', $default_font_size - 1);
1209
1210 // Output Rect
1211 $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
1212
1213 $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop);
1214
1215 if (empty($hidetop)) {
1216 $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
1217 }
1218 }
1219
1220 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1230 protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs)
1231 {
1232 global $langs, $conf, $mysoc;
1233
1234 $ltrdirection = 'L';
1235 if ($outputlangs->trans("DIRECTION") == 'rtl') {
1236 $ltrdirection = 'R';
1237 }
1238
1239 // Load translation files required by the page
1240 $outputlangs->loadLangs(array("main", "supplier_proposal", "companies", "bills", "sendings"));
1241
1242 $default_font_size = pdf_getPDFFontSize($outputlangs);
1243
1244 // Do not add the BACKGROUND as this is for suppliers
1245 //pdf_pagehead($pdf,$outputlangs,$this->page_hauteur);
1246
1247 //Affiche le filigrane brouillon - Print Draft Watermark
1248 /*if($object->statut==0 && getDolGlobalString('COMMANDE_DRAFT_WATERMARK'))
1249 {
1250 pdf_watermark($pdf,$outputlangs,$this->page_hauteur,$this->page_largeur,'mm',getDolGlobalString('COMMANDE_DRAFT_WATERMARK'));
1251 }*/
1252 //Print content
1253
1254 $pdf->SetTextColor(0, 0, 60);
1255 $pdf->SetFont('', 'B', $default_font_size + 3);
1256
1257 $w = 110;
1258
1259 $posx = $this->page_largeur - $this->marge_droite - $w;
1260 $posy = $this->marge_haute;
1261
1262 $pdf->SetXY($this->marge_gauche, $posy);
1263
1264 // Logo
1265 if (!getDolGlobalInt('PDF_DISABLE_MYCOMPANY_LOGO')) {
1266 if ($this->emetteur->logo) {
1267 $logodir = $conf->mycompany->dir_output;
1268 if (!empty($conf->mycompany->multidir_output[$object->entity ?? $conf->entity])) {
1269 $logodir = $conf->mycompany->multidir_output[$object->entity ?? $conf->entity];
1270 }
1271 if (!getDolGlobalInt('MAIN_PDF_USE_LARGE_LOGO')) {
1272 $logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
1273 } else {
1274 $logo = $logodir.'/logos/'.$this->emetteur->logo;
1275 }
1276 if (is_readable($logo)) {
1277 $height = pdf_getHeightForLogo($logo);
1278 $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
1279 } else {
1280 $pdf->SetTextColor(200, 0, 0);
1281 $pdf->SetFont('', 'B', $default_font_size - 2);
1282 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
1283 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
1284 }
1285 } else {
1286 $text = $this->emetteur->name;
1287 $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);
1288 }
1289 }
1290
1291 $pdf->SetFont('', 'B', $default_font_size + 3);
1292 $pdf->SetXY($posx, $posy);
1293 $pdf->SetTextColor(0, 0, 60);
1294 $title = $outputlangs->transnoentities("SupplierProposal")." ".$outputlangs->convToOutputCharset($object->ref);
1295 $pdf->MultiCell($w, 3, $title, '', 'R');
1296 $posy += 1;
1297
1298 if ($object->ref_supplier) {
1299 $posy += 4;
1300 $pdf->SetFont('', 'B', $default_font_size);
1301 $pdf->SetXY($posx, $posy);
1302 $pdf->SetTextColor(0, 0, 60);
1303 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefSupplier")." : ".$outputlangs->convToOutputCharset($object->ref_supplier), '', 'R');
1304 $posy += 1;
1305 }
1306
1307 $pdf->SetFont('', '', $default_font_size - 1);
1308
1309 if (getDolGlobalString('PDF_SHOW_PROJECT_TITLE')) {
1310 $object->fetchProject();
1311 if (!empty($object->project->ref)) {
1312 $posy += 3;
1313 $pdf->SetXY($posx, $posy);
1314 $pdf->SetTextColor(0, 0, 60);
1315 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : dol_trunc($object->project->title, 50)), '', 'R');
1316 }
1317 }
1318
1319 if (getDolGlobalString('PDF_SHOW_PROJECT')) {
1320 $object->fetchProject();
1321 if (!empty($object->project->ref)) {
1322 $outputlangs->load("projects");
1323 $posy += 4;
1324 $pdf->SetXY($posx, $posy);
1325 $langs->load("projects");
1326 $pdf->SetTextColor(0, 0, 60);
1327 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R');
1328 }
1329 }
1330
1331 if (!empty($object->date)) {
1332 $posy += 5;
1333 $pdf->SetXY($posx, $posy);
1334 $pdf->SetTextColor(0, 0, 60);
1335 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Date")." : ".dol_print_date($object->date, "day", false, $outputlangs, true), '', 'R');
1336 } else {
1337 $posy += 5;
1338 $pdf->SetXY($posx, $posy);
1339 $pdf->SetTextColor(255, 0, 0);
1340 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Draft"), '', 'R');
1341 }
1342
1343 $pdf->SetTextColor(0, 0, 60);
1344 $usehourmin = 'day';
1345 if (getDolGlobalString('SUPPLIER_PROPOSAL_USE_HOUR_FOR_DELIVERY_DATE')) {
1346 $usehourmin = 'dayhour';
1347 }
1348 if (!empty($object->delivery_date)) {
1349 $posy += 4;
1350 $pdf->SetXY($posx - 90, $posy);
1351 $pdf->MultiCell(190, 3, $outputlangs->transnoentities("DateDeliveryPlanned")." : ".dol_print_date($object->delivery_date, $usehourmin, false, $outputlangs, true), '', 'R');
1352 }
1353
1354 if ($object->thirdparty->code_fournisseur) {
1355 $posy += 4;
1356 $pdf->SetXY($posx, $posy);
1357 $pdf->SetTextColor(0, 0, 60);
1358 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("SupplierCode")." : ".$outputlangs->transnoentities((string) $object->thirdparty->code_fournisseur), '', 'R');
1359 }
1360
1361 // Get contact
1362 if (getDolGlobalString('DOC_SHOW_FIRST_SALES_REP')) {
1363 $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1364
1365 if (is_array($arrayidcontact) && count($arrayidcontact) > 0) {
1366 $usertmp = new User($this->db);
1367 $usertmp->fetch($arrayidcontact[0]);
1368 $posy += 4;
1369 $pdf->SetXY($posx, $posy);
1370 $pdf->SetTextColor(0, 0, 60);
1371 $pdf->MultiCell($w, 3, $langs->trans("BuyerName")." : ".$usertmp->getFullName($langs), '', 'R');
1372 }
1373 }
1374
1375 $posy += 1;
1376 $pdf->SetTextColor(0, 0, 60);
1377
1378 $top_shift = 0;
1379 // Show list of linked objects
1380 $current_y = $pdf->getY();
1381 $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size);
1382 if ($current_y < $pdf->getY()) {
1383 $top_shift = $pdf->getY() - $current_y;
1384 }
1385
1386 if ($showaddress) {
1387 // Sender properties
1388 $carac_emetteur = '';
1389 // Add internal contact of object if defined
1390 $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1391 if (count($arrayidcontact) > 0) {
1392 $object->fetch_user($arrayidcontact[0]);
1393 $labelbeforecontactname = ($outputlangs->transnoentities("FromContactName") != 'FromContactName' ? $outputlangs->transnoentities("FromContactName") : $outputlangs->transnoentities("Name"));
1394 $carac_emetteur .= ($carac_emetteur ? "\n" : '').$labelbeforecontactname.": ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs));
1395 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ' (' : '';
1396 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && !empty($object->user->office_phone)) ? $object->user->office_phone : '';
1397 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ', ' : '';
1398 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT') && !empty($object->user->email)) ? $object->user->email : '';
1399 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ')' : '';
1400 $carac_emetteur .= "\n";
1401 }
1402
1403 $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
1404
1405 // Show sender
1406 $posy = 32 + $this->marge_haute + $top_shift;
1407 $posx = $this->marge_gauche;
1408 if (getDolGlobalString('MAIN_INVERT_SENDER_RECIPIENT')) {
1409 $posx = $this->page_largeur - $this->marge_droite - 80;
1410 }
1411 $hautcadre = 40;
1412
1413 // Show sender frame
1414 $pdf->SetTextColor(0, 0, 0);
1415 $pdf->SetFont('', '', $default_font_size - 2);
1416 $pdf->SetXY($posx, $posy - 5);
1417 $pdf->MultiCell(80, 5, $outputlangs->transnoentities("BillFrom"), 0, $ltrdirection);
1418 $pdf->SetXY($posx, $posy);
1419 $pdf->SetFillColor(230, 230, 230);
1420 $pdf->RoundedRect($posx, $posy, 82, $hautcadre, $this->corner_radius, '1234', 'F');
1421 $pdf->SetTextColor(0, 0, 60);
1422
1423 // Show sender name
1424 $pdf->SetXY($posx + 2, $posy + 3);
1425 $pdf->SetFont('', 'B', $default_font_size);
1426 $pdf->MultiCell(80, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, $ltrdirection);
1427 $posy = $pdf->getY();
1428
1429 // Show sender information
1430 $pdf->SetXY($posx + 2, $posy);
1431 $pdf->SetFont('', '', $default_font_size - 1);
1432 $pdf->MultiCell(80, 4, $carac_emetteur, 0, $ltrdirection);
1433
1434
1435
1436 // If CUSTOMER contact defined on proposal, we use it. Note: Even if this is a supplier object, the code for external contact that follow-up a supplier proposal is 'CUSTOMER'
1437 $usecontact = false;
1438 if (!getDolGlobalInt('SUPPLIER_PROPOSAL_ADD_BILLING_CONTACT')) {
1439 $arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
1440 } else {
1441 $arrayidcontact = array_merge($object->getIdContact('external', 'CUSTOMER'), $object->getIdContact('external', 'BILLING'));
1442 }
1443 if (is_array($arrayidcontact) && count($arrayidcontact) > 0) {
1444 $usecontact = true;
1445 $result = $object->fetch_contact($arrayidcontact[0]);
1446 }
1447
1448 // Recipient name
1449 if ($usecontact && ($object->contact->socid != $object->thirdparty->id && (!isset($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT) || getDolGlobalString('MAIN_USE_COMPANY_NAME_OF_CONTACT')))) {
1450 $thirdparty = $object->contact;
1451 } else {
1452 $thirdparty = $object->thirdparty;
1453 }
1454
1455 $carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);
1456
1457 $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), ($usecontact ? 1 : 0), 'target', $object);
1458
1459 // Show recipient
1460 $widthrecbox = 100;
1461 if ($this->page_largeur < 210) {
1462 $widthrecbox = 84; // To work with US executive format
1463 }
1464 $posy = 32 + $this->marge_haute + $top_shift;
1465 $posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
1466 if (getDolGlobalString('MAIN_INVERT_SENDER_RECIPIENT')) {
1467 $posx = $this->marge_gauche;
1468 }
1469
1470 // Show recipient frame
1471 $pdf->SetTextColor(0, 0, 0);
1472 $pdf->SetFont('', '', $default_font_size - 2);
1473 $pdf->SetXY($posx + 2, $posy - 5);
1474 $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo"), 0, $ltrdirection);
1475 $pdf->RoundedRect($posx, $posy, $widthrecbox, $hautcadre, $this->corner_radius, '1234', 'D');
1476
1477 // Show recipient name
1478 $pdf->SetXY($posx + 2, $posy + 3);
1479 $pdf->SetFont('', 'B', $default_font_size);
1480 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
1481 $pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, $ltrdirection);
1482
1483 $posy = $pdf->getY();
1484
1485 // Show recipient information
1486 $pdf->SetFont('', '', $default_font_size - 1);
1487 $pdf->SetXY($posx + 2, $posy);
1488 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
1489 $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, $ltrdirection);
1490 }
1491
1492 return $top_shift;
1493 }
1494
1495 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1505 protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
1506 {
1507 $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0);
1508 return pdf_pagefoot($pdf, $outputlangs, 'SUPPLIER_PROPOSAL_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext);
1509 }
1510
1511
1512
1523 public function defineColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1524 {
1525 global $hookmanager;
1526
1527 // Default field style for content
1528 $this->defaultContentsFieldsStyle = array(
1529 'align' => 'R', // R,C,L
1530 'padding' => array(1, 0.5, 1, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1531 );
1532
1533 // Default field style for content
1534 $this->defaultTitlesFieldsStyle = array(
1535 'align' => 'C', // R,C,L
1536 'padding' => array(0.5, 0, 0.5, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1537 );
1538
1539 $rank = 0; // do not use negative rank
1540 $this->cols['desc'] = array(
1541 'rank' => $rank,
1542 'width' => false, // only for desc
1543 'status' => true,
1544 'title' => array(
1545 'textkey' => 'Designation', // use lang key is useful in some case with module
1546 'align' => 'L',
1547 // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
1548 // 'label' => ' ', // the final label
1549 'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1550 ),
1551 'content' => array(
1552 'align' => 'L',
1553 'padding' => array(1.0, 0.5, 1.0, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1554 ),
1555 );
1556
1557 $rank += 10;
1558 $this->cols['photo'] = array(
1559 'rank' => $rank,
1560 'width' => (float) getDolGlobalInt('MAIN_DOCUMENTS_WITH_PICTURE_WIDTH', 20), // in mm
1561 'status' => false,
1562 'title' => array(
1563 'textkey' => 'Photo',
1564 'label' => ' '
1565 ),
1566 'content' => array(
1567 'padding' => array(0.0, 0.0, 0.0, 0.0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
1568 ),
1569 'border-left' => false, // remove left line separator
1570 );
1571
1572 if (getDolGlobalString('MAIN_GENERATE_SUPPLIER_PROPOSAL_WITH_PICTURE')) {
1573 $this->cols['photo']['status'] = true;
1574 }
1575
1576
1577 $rank += 10;
1578 $this->cols['vat'] = array(
1579 'rank' => $rank,
1580 'status' => false,
1581 'width' => 16.0, // in mm
1582 'title' => array(
1583 'textkey' => 'VAT'
1584 ),
1585 'border-left' => true, // add left line separator
1586 );
1587
1588 if (!getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT') && !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN')) {
1589 $this->cols['vat']['status'] = true;
1590 }
1591
1592 $rank += 10;
1593 $this->cols['subprice'] = array(
1594 'rank' => $rank,
1595 'width' => 19.0, // in mm
1596 'status' => false,
1597 'title' => array(
1598 'textkey' => 'PriceUHT'
1599 ),
1600 'border-left' => true, // add left line separator
1601 );
1602
1603 if (!getDolGlobalString('MAIN_GENERATE_DOCUMENTS_SUPPLIER_PROPOSAL_WITHOUT_UNIT_PRICE')) {
1604 $this->cols['subprice']['status'] = true;
1605 }
1606
1607 $rank += 10;
1608 $this->cols['qty'] = array(
1609 'rank' => $rank,
1610 'width' => 16.0, // in mm
1611 'status' => true,
1612 'title' => array(
1613 'textkey' => 'Qty'
1614 ),
1615 'border-left' => true, // add left line separator
1616 );
1617
1618 $rank += 10;
1619 $this->cols['unit'] = array(
1620 'rank' => $rank,
1621 'width' => 11.0, // in mm
1622 'status' => false,
1623 'title' => array(
1624 'textkey' => 'Unit'
1625 ),
1626 'border-left' => true, // add left line separator
1627 );
1628 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1629 $this->cols['unit']['status'] = true;
1630 }
1631
1632 $rank += 10;
1633 $this->cols['discount'] = array(
1634 'rank' => $rank,
1635 'width' => 13.0, // in mm
1636 'status' => false,
1637 'title' => array(
1638 'textkey' => 'ReductionShort'
1639 ),
1640 'border-left' => true, // add left line separator
1641 );
1642 if ($this->atleastonediscount) {
1643 $this->cols['discount']['status'] = true;
1644 }
1645
1646 $rank += 1000; // add a big offset to be sure is the last col because default extrafield rank is 100
1647 $this->cols['totalexcltax'] = array(
1648 'rank' => $rank,
1649 'width' => 26.0, // in mm
1650 'status' => false,
1651 'title' => array(
1652 'textkey' => 'TotalHT'
1653 ),
1654 'border-left' => true, // add left line separator
1655 );
1656
1657 if (!getDolGlobalString('MAIN_GENERATE_DOCUMENTS_SUPPLIER_PROPOSAL_WITHOUT_TOTAL_COLUMN')) {
1658 $this->cols['totalexcltax']['status'] = true;
1659 }
1660
1661 // Add extrafields cols
1662 if (!empty($object->lines)) {
1663 $line = reset($object->lines);
1664 $this->defineColumnExtrafield($line, $outputlangs, $hidedetails);
1665 }
1666
1667 $parameters = array(
1668 'object' => $object,
1669 'outputlangs' => $outputlangs,
1670 'hidedetails' => $hidedetails,
1671 'hidedesc' => $hidedesc,
1672 'hideref' => $hideref
1673 );
1674
1675 $reshook = $hookmanager->executeHooks('defineColumnField', $parameters, $this); // Note that $object may have been modified by hook
1676 if ($reshook < 0) {
1677 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1678 } elseif (empty($reshook)) {
1679 // @phan-suppress-next-line PhanPluginSuspiciousParamOrderInternal
1680 $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys
1681 } else {
1682 $this->cols = $hookmanager->resArray;
1683 }
1684 }
1685}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
prepareArrayColumnField($object, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Prepare Array Column Field.
getColumnStatus($colKey)
get column status from column key
printStdColumnContent($pdf, &$curY, $colKey, $columnText='')
print standard column content
printColDescContent($pdf, &$curY, $colKey, $object, $i, $outputlangs, $hideref=0, $hidedesc=0, $issupplierline=0)
print description column content
getColumnContentXStart($colKey)
get column content X (abscissa) left position from column key
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.
defineColumnExtrafield($object, $outputlangs, $hidedetails=0)
Define Array Column Field for extrafields.
Class to manage hooks.
Perent class of the Proposal models.
Class to manage products or services.
Class to manage translations.
Class to manage Dolibarr users.
Class to generate the supplier proposals with the zenith model.
_pagehead(&$pdf, $object, $showaddress, $outputlangs)
Show top header of page.
_tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='')
Show table for lines.
_tableau_info(&$pdf, $object, $posy, $outputlangs)
Show miscellaneous information (payment mode, payment term, ...)
write_file($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0)
Function to build pdf onto disk.
__construct($db)
Constructor.
_pagefoot(&$pdf, $object, $outputlangs, $hidefreetext=0)
Show footer of page.
_tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs)
Show total to pay.
defineColumnField($object, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Define Array Column Field.
_tableau_versements(&$pdf, $object, $posy, $outputlangs)
Show payments table.
global $mysoc
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!function_exists( 'dolEscapeXML')) convertBackOfficeMediasLinksToPublicLinks($notetoshow)
Convert links to local wrapper to medias files into a string into a public external URL readable on i...
colorStringToArray($stringcolor, $colorifnotfound=array(88, 88, 88))
Convert a string RGB value ('FFFFFF', '255,255,255') into an array RGB array(255,255,...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
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.
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).
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '...' if string larger than length.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
pdf_getSizeForImage($realpath)
Return dimensions to use for images onto PDF checking that width and height are not higher than maxim...
Definition pdf.lib.php:3192
pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line total excluding tax.
Definition pdf.lib.php:2893
pdf_getFormat($outputlangs=null, $mode='setup')
Return array with format properties of default PDF format.
Definition pdf.lib.php:87
pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, $h, $align, $default_font_size)
Show linked objects for PDF generation.
Definition pdf.lib.php:1810
pdf_getPDFFontSize($outputlangs)
Return font size to use for PDF generation.
Definition pdf.lib.php:294
pdf_getHeightForLogo($logo, $url=false)
Return height to use for Logo onto PDF.
Definition pdf.lib.php:317
pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line unit price excluding tax.
Definition pdf.lib.php:2482
pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails=0)
Return line vat rate.
Definition pdf.lib.php:2420
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:1423
pdf_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition pdf.lib.php:273
pdf_render_subtotals(TCPDF $pdf, CommonDocGenerator $generator, float $curY, CommonObject $object, int $i, Translate $outputlangs, int $hideref, int $hidedesc, array $bgColor, bool $isSubtotal=false, bool $applySubtotalLogic=true)
Render subtotals line with a colored background and adapted text color .
Definition pdf.lib.php:3322
pdf_build_address($outputlangs, $sourcecompany, $targetcompany='', $targetcontact='', $usecontact=0, $mode='source', $object=null)
Return a string with full address formatted for output on PDF documents.
Definition pdf.lib.php:438
pdf_getlineunit($object, $i, $outputlangs, $hidedetails=0)
Return line unit.
Definition pdf.lib.php:2727
pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails=0)
Return line remise percent.
Definition pdf.lib.php:2770
pdf_getlineqty($object, $i, $outputlangs, $hidedetails=0)
Return line quantity.
Definition pdf.lib.php:2567
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:1137
pdf_getInstance($format='', $metric='mm', $pagetype='P')
Return a PDF instance object.
Definition pdf.lib.php:129
pdfBuildThirdpartyName($thirdparty, Translate $outputlangs, $includealias=0)
Returns the name of the thirdparty.
Definition pdf.lib.php:393
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:137
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:140