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