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