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