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