dolibarr 18.0.6
pdf_azur.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-2018 Ferran Marcet <fmarcet@2byte.es>
10 * Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
11 * Copyright (C) 2019 Pierre Ardoin <mapiolca@me.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25 * or see https://www.gnu.org/
26 */
27
34require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php';
35require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
36require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
37require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
38require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
39
40
45{
49 public $db;
50
54 public $entity;
55
59 public $name;
60
64 public $description;
65
69 public $update_main_doc_field;
70
74 public $type;
75
80 public $version = 'dolibarr';
81
85 public $page_largeur;
86
90 public $page_hauteur;
91
95 public $format;
96
100 public $marge_gauche;
101
105 public $marge_droite;
106
110 public $marge_haute;
111
115 public $marge_basse;
116
121 public $emetteur;
122
123
129 public function __construct($db)
130 {
131 global $conf, $langs, $mysoc;
132
133 // Translations
134 $langs->loadLangs(array("main", "bills"));
135
136 $this->db = $db;
137 $this->name = "azur";
138 $this->description = $langs->trans('DocModelAzurDescription');
139 $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template
140
141 // Dimension page
142 $this->type = 'pdf';
143 $formatarray = pdf_getFormat();
144 $this->page_largeur = $formatarray['width'];
145 $this->page_hauteur = $formatarray['height'];
146 $this->format = array($this->page_largeur, $this->page_hauteur);
147 $this->marge_gauche = getDolGlobalInt('MAIN_PDF_MARGIN_LEFT', 10);
148 $this->marge_droite = getDolGlobalInt('MAIN_PDF_MARGIN_RIGHT', 10);
149 $this->marge_haute = getDolGlobalInt('MAIN_PDF_MARGIN_TOP', 10);
150 $this->marge_basse = getDolGlobalInt('MAIN_PDF_MARGIN_BOTTOM', 10);
151
152 $this->option_logo = 1; // Display logo
153 $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION
154 $this->option_modereg = 1; // Display payment mode
155 $this->option_condreg = 1; // Display payment terms
156 $this->option_multilang = 1; // Available in several languages
157 $this->option_escompte = 0; // Displays if there has been a discount
158 $this->option_credit_note = 0; // Support credit notes
159 $this->option_freetext = 1; // Support add of a personalised text
160 $this->option_draft_watermark = 1; // Support add of a watermark on drafts
161 $this->watermark = '';
162
163 // Get source company
164 $this->emetteur = $mysoc;
165 if (empty($this->emetteur->country_code)) {
166 $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined
167 }
168
169 // Define position of columns
170 $this->posxdesc = $this->marge_gauche + 1;
171 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
172 $this->posxtva = 101;
173 $this->posxup = 118;
174 $this->posxqty = 135;
175 $this->posxunit = 151;
176 } else {
177 $this->posxtva = 106;
178 $this->posxup = 122;
179 $this->posxqty = 145;
180 $this->posxunit = 162;
181 }
182 $this->posxdiscount = 162;
183 $this->postotalht = 174;
184 if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) || !empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
185 $this->posxtva = $this->posxup;
186 }
187 $this->posxpicture = $this->posxtva - (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH) ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH); // width of images
188 if ($this->page_largeur < 210) { // To work with US executive format
189 $this->posxpicture -= 20;
190 $this->posxtva -= 20;
191 $this->posxup -= 20;
192 $this->posxqty -= 20;
193 $this->posxunit -= 20;
194 $this->posxdiscount -= 20;
195 $this->postotalht -= 20;
196 }
197
198 $this->tva = array();
199 $this->tva_array = array();
200 $this->localtax1 = array();
201 $this->localtax2 = array();
202 $this->atleastoneratenotnull = 0;
203 $this->atleastonediscount = 0;
204 }
205
206 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
218 public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
219 {
220 // phpcs:enable
221 global $user, $langs, $conf, $mysoc, $db, $hookmanager, $nblines;
222
223 dol_syslog("write_file outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null'));
224
225 if (!is_object($outputlangs)) {
226 $outputlangs = $langs;
227 }
228 // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
229 if (!empty($conf->global->MAIN_USE_FPDF)) {
230 $outputlangs->charset_output = 'ISO-8859-1';
231 }
232
233 // Load translation files required by page
234 $outputlangs->loadLangs(array("main", "dict", "companies", "bills", "propal", "products"));
235
236 global $outputlangsbis;
237 $outputlangsbis = null;
238 if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) {
239 $outputlangsbis = new Translate('', $conf);
240 $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE);
241 $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal"));
242 }
243
244 // Show Draft Watermark
245 if ($object->statut == $object::STATUS_DRAFT && getDolGlobalString('PROPALE_DRAFT_WATERMARK')) {
246 $this->watermark = getDolGlobalString('PROPALE_DRAFT_WATERMARK');
247 }
248
249 $nblines = count($object->lines);
250
251 // Loop on each lines to detect if there is at least one image to show
252 $realpatharray = array();
253 $this->atleastonephoto = false;
254 if (!empty($conf->global->MAIN_GENERATE_PROPOSALS_WITH_PICTURE)) {
255 $objphoto = new Product($this->db);
256
257 for ($i = 0; $i < $nblines; $i++) {
258 if (empty($object->lines[$i]->fk_product)) {
259 continue;
260 }
261
262 $objphoto->fetch($object->lines[$i]->fk_product);
263 //var_dump($objphoto->ref);exit;
264 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
265 $pdir[0] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/";
266 $pdir[1] = get_exdir(0, 0, 0, 0, $objphoto, 'product').dol_sanitizeFileName($objphoto->ref).'/';
267 } else {
268 $pdir[0] = get_exdir(0, 0, 0, 0, $objphoto, 'product'); // default
269 $pdir[1] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/"; // alternative
270 }
271
272 $arephoto = false;
273 $realpath = '';
274 foreach ($pdir as $midir) {
275 if (!$arephoto) {
276 if ($conf->entity != $objphoto->entity) {
277 $dir = $conf->product->multidir_output[$objphoto->entity].'/'.$midir; //Check repertories of current entities
278 } else {
279 $dir = $conf->product->dir_output.'/'.$midir; //Check repertory of the current product
280 }
281 foreach ($objphoto->liste_photos($dir, 1) as $key => $obj) {
282 if (!getDolGlobalInt('CAT_HIGH_QUALITY_IMAGES')) { // If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo
283 if ($obj['photo_vignette']) {
284 $filename = $obj['photo_vignette'];
285 } else {
286 $filename = $obj['photo'];
287 }
288 } else {
289 $filename = $obj['photo'];
290 }
291
292 $realpath = $dir.$filename;
293 $arephoto = true;
294 $this->atleastonephoto = true;
295 }
296 }
297 }
298
299 if ($realpath && $arephoto) {
300 $realpatharray[$i] = $realpath;
301 }
302 }
303 }
304
305 if (count($realpatharray) == 0) {
306 $this->posxpicture = $this->posxtva;
307 }
308
309 if ($conf->propal->multidir_output[$conf->entity]) {
310 $object->fetch_thirdparty();
311
312 $deja_regle = 0;
313
314 // Definition of $dir and $file
315 if ($object->specimen) {
316 $dir = $conf->propal->multidir_output[$conf->entity];
317 $file = $dir."/SPECIMEN.pdf";
318 } else {
319 $objectref = dol_sanitizeFileName($object->ref);
320 $dir = $conf->propal->multidir_output[$object->entity]."/".$objectref;
321 $file = $dir."/".$objectref.".pdf";
322 }
323
324 if (!file_exists($dir)) {
325 if (dol_mkdir($dir) < 0) {
326 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
327 return 0;
328 }
329 }
330
331 if (file_exists($dir)) {
332 // Add pdfgeneration hook
333 if (!is_object($hookmanager)) {
334 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
335 $hookmanager = new HookManager($this->db);
336 }
337 $hookmanager->initHooks(array('pdfgeneration'));
338 $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
339 global $action;
340 $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
341
342 // Set nblines with the new content of lines after hook
343 $nblines = count($object->lines);
344 //$nbpayments = count($object->getListOfPayments());
345
346 // Create pdf instance
347 $pdf = pdf_getInstance($this->format);
348 $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
349 $pdf->SetAutoPageBreak(1, 0);
350
351 if (class_exists('TCPDF')) {
352 $pdf->setPrintHeader(false);
353 $pdf->setPrintFooter(false);
354 }
355 $pdf->SetFont(pdf_getPDFFont($outputlangs));
356 // Set path to the background PDF File
357 if (!empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) {
358 $logodir = $conf->mycompany->dir_output;
359 if (!empty($conf->mycompany->multidir_output[$object->entity])) {
360 $logodir = $conf->mycompany->multidir_output[$object->entity];
361 }
362 $pagecount = $pdf->setSourceFile($logodir.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND);
363 $tplidx = $pdf->importPage(1);
364 }
365
366 $pdf->Open();
367 $pagenb = 0;
368 $pdf->SetDrawColor(128, 128, 128);
369
370 $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
371 $pdf->SetSubject($outputlangs->transnoentities("PdfCommercialProposalTitle"));
372 $pdf->SetCreator("Dolibarr ".DOL_VERSION);
373 $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
374 $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfCommercialProposalTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
375 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
376 $pdf->SetCompression(false);
377 }
378
379 $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
380
381 // Set $this->atleastonediscount if you have at least one discount
382 for ($i = 0; $i < $nblines; $i++) {
383 if ($object->lines[$i]->remise_percent) {
384 $this->atleastonediscount++;
385 }
386 }
387 if (empty($this->atleastonediscount)) {
388 $delta = ($this->postotalht - $this->posxdiscount);
389 $this->posxpicture += $delta;
390 $this->posxtva += $delta;
391 $this->posxup += $delta;
392 $this->posxqty += $delta;
393 $this->posxunit += $delta;
394 $this->posxdiscount += $delta;
395 // post of fields after are not modified, stay at same position
396 }
397
398 // New page
399 $pdf->AddPage();
400 if (!empty($tplidx)) {
401 $pdf->useTemplate($tplidx);
402 }
403 $pagenb++;
404
405 $heightforinfotot = 40; // Height reserved to output the info and total part
406 $heightforsignature = empty($conf->global->PROPAL_DISABLE_SIGNATURE) ? (pdfGetHeightForHtmlContent($pdf, $outputlangs->transnoentities("ProposalCustomerSignature")) + 10) : 0;
407 $heightforfreetext = (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT) ? $conf->global->MAIN_PDF_FREETEXT_HEIGHT : 5); // Height reserved to output the free text on last page
408 $heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin)
409 if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)) {
410 $heightforfooter += 6;
411 }
412 //print $heightforinfotot + $heightforsignature + $heightforfreetext + $heightforfooter;exit;
413
414 $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis);
415 $pdf->SetFont('', '', $default_font_size - 1);
416 $pdf->MultiCell(0, 3, ''); // Set interline to 3
417 $pdf->SetTextColor(0, 0, 0);
418
419
420 $tab_top = 90 + $top_shift;
421 $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
422
423 // Incoterm
424 $height_incoterms = 0;
425 if (isModEnabled('incoterm')) {
426 $desc_incoterms = $object->getIncotermsForPDF();
427 if ($desc_incoterms) {
428 $tab_top -= 2;
429
430 $pdf->SetFont('', '', $default_font_size - 1);
431 $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($desc_incoterms), 0, 1);
432 $nexY = $pdf->GetY();
433 $height_incoterms = $nexY - $tab_top;
434
435 // Rect takes a length in 3rd parameter
436 $pdf->SetDrawColor(192, 192, 192);
437 $pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_incoterms + 1);
438
439 $tab_top = $nexY + 6;
440 $height_incoterms += 4;
441 }
442 }
443
444 // Displays notes
445 $notetoshow = empty($object->note_public) ? '' : $object->note_public;
446 if (!empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE)) {
447 // Get first sale rep
448 if (is_object($object->thirdparty)) {
449 $salereparray = $object->thirdparty->getSalesRepresentatives($user);
450 $salerepobj = new User($this->db);
451 $salerepobj->fetch($salereparray[0]['id']);
452 if (!empty($salerepobj->signature)) {
453 $notetoshow = dol_concatdesc($notetoshow, $salerepobj->signature);
454 }
455 }
456 }
457 // Extrafields in note
458 $extranote = $this->getExtrafieldsInHtml($object, $outputlangs);
459 if (!empty($extranote)) {
460 $notetoshow = dol_concatdesc($notetoshow, $extranote);
461 }
462 if (!empty($conf->global->MAIN_ADD_CREATOR_IN_NOTE) && $object->user_author_id > 0) {
463 $tmpuser = new User($this->db);
464 $tmpuser->fetch($object->user_author_id);
465
466
467 $creator_info = $langs->trans("CaseFollowedBy").' '.$tmpuser->getFullName($langs);
468 if ($tmpuser->email) $creator_info .= ', '.$langs->trans("EMail").': '.$tmpuser->email;
469 if ($tmpuser->office_phone) $creator_info .= ', '.$langs->trans("Phone").': '.$tmpuser->office_phone;
470
471 $notetoshow = dol_concatdesc($notetoshow, $creator_info);
472 }
473
474 if ($notetoshow) {
475 $tab_top -= 2;
476
477 $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
478 complete_substitutions_array($substitutionarray, $outputlangs, $object);
479 $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
480 $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);
481
482 $pdf->SetFont('', '', $default_font_size - 1);
483 $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($notetoshow), 0, 1);
484 $nexY = $pdf->GetY();
485 $height_note = $nexY - $tab_top;
486
487 // Rect takes a length in 3rd parameter
488 $pdf->SetDrawColor(192, 192, 192);
489 $pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_note + 1);
490
491 $tab_top = $nexY + 6;
492 }
493
494 $iniY = $tab_top + 7;
495 $curY = $tab_top + 7;
496 $nexY = $tab_top + 7;
497
498 // Loop on each lines
499 for ($i = 0; $i < $nblines; $i++) {
500 $curY = $nexY;
501 $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
502 $pdf->SetTextColor(0, 0, 0);
503
504 // Define size of image if we need it
505 $imglinesize = array();
506 if (!empty($realpatharray[$i])) {
507 $imglinesize = pdf_getSizeForImage($realpatharray[$i]);
508 }
509
510 $pdf->setTopMargin($tab_top_newpage);
511 $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext + $heightforsignature + $heightforinfotot); // The only function to edit the bottom margin of current page to set it.
512 $pageposbefore = $pdf->getPage();
513
514 $showpricebeforepagebreak = 1;
515 $posYAfterImage = 0;
516 $posYAfterDescription = 0;
517
518 // We start with Photo of product line
519 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
520 $pdf->AddPage('', '', true);
521 if (!empty($tplidx)) {
522 $pdf->useTemplate($tplidx);
523 }
524 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
525 $this->_pagehead($pdf, $object, 0, $outputlangs);
526 }
527 $pdf->setPage($pageposbefore + 1);
528
529 $curY = $tab_top_newpage;
530
531 // Allows data in the first page if description is long enough to break in multiples pages
532 if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {
533 $showpricebeforepagebreak = 1;
534 } else {
535 $showpricebeforepagebreak = 0;
536 }
537 }
538
539 if (isset($imglinesize['width']) && isset($imglinesize['height'])) {
540 $curX = $this->posxpicture - 1;
541 $pdf->Image($realpatharray[$i], $curX + (($this->posxtva - $this->posxpicture - $imglinesize['width']) / 2), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi
542 // $pdf->Image does not increase value return by getY, so we save it manually
543 $posYAfterImage = $curY + $imglinesize['height'];
544 }
545
546 // Description of product line
547 $curX = $this->posxdesc - 1;
548
549 $pdf->startTransaction();
550 pdf_writelinedesc($pdf, $object, $i, $outputlangs, $this->posxpicture - $curX, 3, $curX, $curY, $hideref, $hidedesc);
551 $pageposafter = $pdf->getPage();
552 if ($pageposafter > $pageposbefore) { // There is a pagebreak
553 $pdf->rollbackTransaction(true);
554 $pageposafter = $pageposbefore;
555 //print $pageposafter.'-'.$pageposbefore;exit;
556 $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
557 pdf_writelinedesc($pdf, $object, $i, $outputlangs, $this->posxpicture - $curX, 3, $curX, $curY, $hideref, $hidedesc);
558
559 $pageposafter = $pdf->getPage();
560 $posyafter = $pdf->GetY();
561 //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit;
562 if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforsignature + $heightforinfotot))) { // There is no space left for total+free text
563 if ($i == ($nblines - 1)) { // No more lines, and no space left to show total, so we create a new page
564 $pdf->AddPage('', '', true);
565 if (!empty($tplidx)) {
566 $pdf->useTemplate($tplidx);
567 }
568 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
569 $this->_pagehead($pdf, $object, 0, $outputlangs);
570 }
571 $pdf->setPage($pageposafter + 1);
572 }
573 } else {
574 // We found a page break
575
576 // Allows data in the first page if description is long enough to break in multiples pages
577 if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {
578 $showpricebeforepagebreak = 1;
579 } else {
580 $showpricebeforepagebreak = 0;
581 }
582 }
583 } else // No pagebreak
584 {
585 $pdf->commitTransaction();
586 }
587 $posYAfterDescription = $pdf->GetY();
588
589 $nexY = $pdf->GetY();
590 $pageposafter = $pdf->getPage();
591
592 $pdf->setPage($pageposbefore);
593 $pdf->setTopMargin($this->marge_haute);
594 $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
595
596 // We suppose that a too long description or photo were moved completely on next page
597 if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
598 $pdf->setPage($pageposafter);
599 $curY = $tab_top_newpage;
600 }
601
602 $pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par defaut
603
604 // VAT Rate
605 if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
606 $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
607 $pdf->SetXY($this->posxtva - 5, $curY);
608 $pdf->MultiCell($this->posxup - $this->posxtva + 4, 3, $vat_rate, 0, 'R');
609 }
610
611 // Unit price before discount
612 $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);
613 $pdf->SetXY($this->posxup, $curY);
614 $pdf->MultiCell($this->posxqty - $this->posxup - 0.8, 3, $up_excl_tax, 0, 'R', 0);
615
616 // Quantity
617 $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
618 $pdf->SetXY($this->posxqty, $curY);
619 $pdf->MultiCell($this->posxunit - $this->posxqty - 0.8, 4, $qty, 0, 'R'); // Enough for 6 chars
620
621 // Unit
622 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
623 $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager);
624 $pdf->SetXY($this->posxunit, $curY);
625 $pdf->MultiCell($this->posxdiscount - $this->posxunit - 0.8, 4, $unit, 0, 'L');
626 }
627
628 // Discount on line
629 $pdf->SetXY($this->posxdiscount, $curY);
630 if ($object->lines[$i]->remise_percent) {
631 $pdf->SetXY($this->posxdiscount - 2, $curY);
632 $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);
633 $pdf->MultiCell($this->postotalht - $this->posxdiscount + 2, 3, $remise_percent, 0, 'R');
634 }
635
636 // Total HT line
637 $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails);
638 $pdf->SetXY($this->postotalht, $curY);
639 $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->postotalht, 3, $total_excl_tax, 0, 'R', 0);
640
641 // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva
642 if (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) {
643 $tvaligne = $object->lines[$i]->multicurrency_total_tva;
644 } else {
645 $tvaligne = $object->lines[$i]->total_tva;
646 }
647
648 $localtax1ligne = $object->lines[$i]->total_localtax1;
649 $localtax2ligne = $object->lines[$i]->total_localtax2;
650 $localtax1_rate = $object->lines[$i]->localtax1_tx;
651 $localtax2_rate = $object->lines[$i]->localtax2_tx;
652 $localtax1_type = $object->lines[$i]->localtax1_type;
653 $localtax2_type = $object->lines[$i]->localtax2_type;
654
655 // TODO remise_percent is an obsolete field for object parent
656 /*if ($object->remise_percent) {
657 $tvaligne -= ($tvaligne * $object->remise_percent) / 100;
658 }
659 if ($object->remise_percent) {
660 $localtax1ligne -= ($localtax1ligne * $object->remise_percent) / 100;
661 }
662 if ($object->remise_percent) {
663 $localtax2ligne -= ($localtax2ligne * $object->remise_percent) / 100;
664 }*/
665
666 $vatrate = (string) $object->lines[$i]->tva_tx;
667
668 // Retrieve type from database for backward compatibility with old records
669 if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined
670 && (!empty($localtax1_rate) || !empty($localtax2_rate))) { // and there is local tax
671 $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $object->thirdparty, $mysoc);
672 $localtax1_type = isset($localtaxtmp_array[0]) ? $localtaxtmp_array[0] : '';
673 $localtax2_type = isset($localtaxtmp_array[2]) ? $localtaxtmp_array[2] : '';
674 }
675
676 // retrieve global local tax
677 if ($localtax1_type && $localtax1ligne != 0) {
678 if (empty($this->localtax1[$localtax1_type][$localtax1_rate])) {
679 $this->localtax1[$localtax1_type][$localtax1_rate] = $localtax1ligne;
680 } else {
681 $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne;
682 }
683 }
684 if ($localtax2_type && $localtax2ligne != 0) {
685 if (empty($this->localtax2[$localtax2_type][$localtax2_rate])) {
686 $this->localtax2[$localtax2_type][$localtax2_rate] = $localtax2ligne;
687 } else {
688 $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne;
689 }
690 }
691
692 if (($object->lines[$i]->info_bits & 0x01) == 0x01) {
693 $vatrate .= '*';
694 }
695
696 // Fill $this->tva and $this->tva_array
697 if (!isset($this->tva[$vatrate])) {
698 $this->tva[$vatrate] = 0;
699 }
700 $this->tva[$vatrate] += $tvaligne;
701 $vatcode = $object->lines[$i]->vat_src_code;
702 if (empty($this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'])) {
703 $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] = 0;
704 }
705 $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')] = array('vatrate'=>$vatrate, 'vatcode'=>$vatcode, 'amount'=> $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] + $tvaligne);
706
707 if ($posYAfterImage > $posYAfterDescription) {
708 $nexY = $posYAfterImage;
709 }
710
711 // Add line
712 if (!empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblines - 1)) {
713 $pdf->setPage($pageposafter);
714 $pdf->SetLineStyle(array('dash'=>'1,1', 'color'=>array(80, 80, 80)));
715 //$pdf->SetDrawColor(190,190,200);
716 $pdf->line($this->marge_gauche, $nexY + 1, $this->page_largeur - $this->marge_droite, $nexY + 1);
717 $pdf->SetLineStyle(array('dash'=>0));
718 }
719
720 $nexY += 2; // Add space between lines
721
722 // Detect if some page were added automatically and output _tableau for past pages
723 while ($pagenb < $pageposafter) {
724 $pdf->setPage($pagenb);
725 if ($pagenb == 1) {
726 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
727 } else {
728 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
729 }
730 $this->_pagefoot($pdf, $object, $outputlangs, 1);
731 $pagenb++;
732 $pdf->setPage($pagenb);
733 $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
734 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
735 $this->_pagehead($pdf, $object, 0, $outputlangs);
736 }
737 if (!empty($tplidx)) {
738 $pdf->useTemplate($tplidx);
739 }
740 }
741 if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) {
742 if ($pagenb == 1) {
743 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
744 } else {
745 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
746 }
747 $this->_pagefoot($pdf, $object, $outputlangs, 1);
748 // New page
749 $pdf->AddPage();
750 if (!empty($tplidx)) {
751 $pdf->useTemplate($tplidx);
752 }
753 $pagenb++;
754 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
755 $this->_pagehead($pdf, $object, 0, $outputlangs);
756 }
757 }
758 }
759
760 // Show square
761 if ($pagenb == 1) {
762 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code);
763 $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter + 1;
764 } else {
765 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code);
766 $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter + 1;
767 }
768
769 // Affiche zone infos
770 $posy = $this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs);
771
772 // Affiche zone totaux
773 $posy = $this->_tableau_tot($pdf, $object, 0, $bottomlasttab, $outputlangs);
774
775 // Affiche zone versements
776 /*
777 if ($deja_regle || $amount_credit_notes_included || $amount_deposits_included)
778 {
779 $posy=$this->_tableau_versements($pdf, $object, $posy, $outputlangs);
780 }
781 */
782
783 // Customer signature area
784 if (empty($conf->global->PROPAL_DISABLE_SIGNATURE)) {
785 $posy = $this->_signature_area($pdf, $object, $posy, $outputlangs);
786 }
787
788 // Pied de page
789 $this->_pagefoot($pdf, $object, $outputlangs);
790 if (method_exists($pdf, 'AliasNbPages')) {
791 $pdf->AliasNbPages();
792 }
793
794 //If propal merge product PDF is active
795 if (!empty($conf->global->PRODUIT_PDF_MERGE_PROPAL)) {
796 require_once DOL_DOCUMENT_ROOT.'/product/class/propalmergepdfproduct.class.php';
797
798 $already_merged = array();
799 foreach ($object->lines as $line) {
800 if (!empty($line->fk_product) && !(in_array($line->fk_product, $already_merged))) {
801 // Find the desire PDF
802 $filetomerge = new Propalmergepdfproduct($this->db);
803
804 if (getDolGlobalInt('MAIN_MULTILANGS')) {
805 $filetomerge->fetch_by_product($line->fk_product, $outputlangs->defaultlang);
806 } else {
807 $filetomerge->fetch_by_product($line->fk_product);
808 }
809
810 $already_merged[] = $line->fk_product;
811
812 $product = new Product($this->db);
813 $product->fetch($line->fk_product);
814
815 if ($product->entity != $conf->entity) {
816 $entity_product_file = $product->entity;
817 } else {
818 $entity_product_file = $conf->entity;
819 }
820
821 // If PDF is selected and file is not empty
822 if (count($filetomerge->lines) > 0) {
823 foreach ($filetomerge->lines as $linefile) {
824 if (!empty($linefile->id) && !empty($linefile->file_name)) {
825 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
826 if (isModEnabled("product")) {
827 $filetomerge_dir = $conf->product->multidir_output[$entity_product_file].'/'.get_exdir($product->id, 2, 0, 0, $product, 'product').$product->id."/photos";
828 } elseif (isModEnabled("service")) {
829 $filetomerge_dir = $conf->service->multidir_output[$entity_product_file].'/'.get_exdir($product->id, 2, 0, 0, $product, 'product').$product->id."/photos";
830 }
831 } else {
832 if (isModEnabled("product")) {
833 $filetomerge_dir = $conf->product->multidir_output[$entity_product_file].'/'.get_exdir(0, 0, 0, 0, $product, 'product');
834 } elseif (isModEnabled("service")) {
835 $filetomerge_dir = $conf->service->multidir_output[$entity_product_file].'/'.get_exdir(0, 0, 0, 0, $product, 'product');
836 }
837 }
838
839 dol_syslog(get_class($this).':: upload_dir='.$filetomerge_dir, LOG_DEBUG);
840
841 $infile = $filetomerge_dir.'/'.$linefile->file_name;
842 if (file_exists($infile) && is_readable($infile)) {
843 $pagecount = $pdf->setSourceFile($infile);
844 for ($i = 1; $i <= $pagecount; $i++) {
845 $tplIdx = $pdf->importPage($i);
846 if ($tplIdx !== false) {
847 $s = $pdf->getTemplatesize($tplIdx);
848 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
849 $pdf->useTemplate($tplIdx);
850 } else {
851 setEventMessages(null, array($infile.' cannot be added, probably protected PDF'), 'warnings');
852 }
853 }
854 }
855 }
856 }
857 }
858 }
859 }
860 }
861
862 $pdf->Close();
863
864 $pdf->Output($file, 'F');
865
866 //Add pdfgeneration hook
867 $hookmanager->initHooks(array('pdfgeneration'));
868 $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
869 global $action;
870 $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
871 if ($reshook < 0) {
872 $this->error = $hookmanager->error;
873 $this->errors = $hookmanager->errors;
874 }
875
876 dolChmod($file);
877
878 $this->result = array('fullpath'=>$file);
879
880 return 1; // No error
881 } else {
882 $this->error = $langs->trans("ErrorCanNotCreateDir", $dir);
883 return 0;
884 }
885 } else {
886 $this->error = $langs->trans("ErrorConstantNotDefined", "PROP_OUTPUTDIR");
887 return 0;
888 }
889 }
890
891 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
892 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
902 protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs)
903 {
904 // phpcs:enable
905 return 1;
906 }
907
908 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
909 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
919 protected function _tableau_info(&$pdf, $object, $posy, $outputlangs)
920 {
921 // phpcs:enable
922 global $conf, $mysoc;
923 $default_font_size = pdf_getPDFFontSize($outputlangs);
924
925 $pdf->SetFont('', '', $default_font_size - 1);
926
927 $diffsizetitle = (empty($conf->global->PDF_DIFFSIZE_TITLE) ? 3 : $conf->global->PDF_DIFFSIZE_TITLE);
928
929 // If France, show VAT mention if not applicable
930 if ($this->emetteur->country_code == 'FR' && empty($mysoc->tva_assuj)) {
931 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
932 $pdf->SetXY($this->marge_gauche, $posy);
933 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0);
934
935 $posy = $pdf->GetY() + 4;
936 }
937
938 $posxval = 52;
939 if (!empty($conf->global->MAIN_PDF_DELIVERY_DATE_TEXT)) {
940 $displaydate = "daytext";
941 } else {
942 $displaydate = "day";
943 }
944
945 // Show shipping date
946 if (!empty($object->delivery_date)) {
947 $outputlangs->load("sendings");
948 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
949 $pdf->SetXY($this->marge_gauche, $posy);
950 $titre = $outputlangs->transnoentities("DateDeliveryPlanned").':';
951 $pdf->MultiCell(80, 4, $titre, 0, 'L');
952 $pdf->SetFont('', '', $default_font_size -$diffsizetitle);
953 $pdf->SetXY($posxval, $posy);
954 $dlp = dol_print_date($object->delivery_date, $displaydate, false, $outputlangs, true);
955 $pdf->MultiCell(80, 4, $dlp, 0, 'L');
956
957 $posy = $pdf->GetY() + 1;
958 } elseif ($object->availability_code || $object->availability) { // Show availability conditions
959 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
960 $pdf->SetXY($this->marge_gauche, $posy);
961 $titre = $outputlangs->transnoentities("AvailabilityPeriod").':';
962 $pdf->MultiCell(80, 4, $titre, 0, 'L');
963 $pdf->SetTextColor(0, 0, 0);
964 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
965 $pdf->SetXY($posxval, $posy);
966 $lib_availability = $outputlangs->transnoentities("AvailabilityType".$object->availability_code) != ('AvailabilityType'.$object->availability_code) ? $outputlangs->transnoentities("AvailabilityType".$object->availability_code) : $outputlangs->convToOutputCharset($object->availability);
967 $lib_availability = str_replace('\n', "\n", $lib_availability);
968 $pdf->MultiCell(80, 4, $lib_availability, 0, 'L');
969
970 $posy = $pdf->GetY() + 1;
971 }
972
973 // Show delivery mode
974 if (empty($conf->global->PROPOSAL_PDF_HIDE_DELIVERYMODE) && $object->shipping_method_id > 0) {
975 $outputlangs->load("sendings");
976
977 $shipping_method_id = $object->shipping_method_id;
978 if (!empty($conf->global->SOCIETE_ASK_FOR_SHIPPING_METHOD) && !empty($this->emetteur->shipping_method_id)) {
979 $shipping_method_id = $this->emetteur->shipping_method_id;
980 }
981 $shipping_method_code = dol_getIdFromCode($this->db, $shipping_method_id, 'c_shipment_mode', 'rowid', 'code');
982 $shipping_method_label = dol_getIdFromCode($this->db, $shipping_method_id, 'c_shipment_mode', 'rowid', 'libelle');
983
984 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
985 $pdf->SetXY($this->marge_gauche, $posy);
986 $titre = $outputlangs->transnoentities("SendingMethod").':';
987 $pdf->MultiCell(43, 4, $titre, 0, 'L');
988
989 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
990 $pdf->SetXY($posxval, $posy);
991 $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;
992 $lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
993 $pdf->MultiCell(67, 4, $lib_condition_paiement, 0, 'L');
994
995 $posy = $pdf->GetY() + 1;
996 }
997
998 // Show payments conditions
999 if (empty($conf->global->PROPOSAL_PDF_HIDE_PAYMENTTERM) && $object->cond_reglement_code) {
1000 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1001 $pdf->SetXY($this->marge_gauche, $posy);
1002 $titre = $outputlangs->transnoentities("PaymentConditions").':';
1003 $pdf->MultiCell(43, 4, $titre, 0, 'L');
1004
1005 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1006 $pdf->SetXY($posxval, $posy);
1007 $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);
1008 $lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
1009 if ($object->deposit_percent > 0) {
1010 $lib_condition_paiement = str_replace('__DEPOSIT_PERCENT__', $object->deposit_percent, $lib_condition_paiement);
1011 }
1012 $pdf->MultiCell(67, 4, $lib_condition_paiement, 0, 'L');
1013
1014 $posy = $pdf->GetY() + 3;
1015 }
1016
1017 if (empty($conf->global->PROPOSAL_PDF_HIDE_PAYMENTMODE)) {
1018 // Show payment mode
1019 if ($object->mode_reglement_code
1020 && $object->mode_reglement_code != 'CHQ'
1021 && $object->mode_reglement_code != 'VIR') {
1022 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1023 $pdf->SetXY($this->marge_gauche, $posy);
1024 $titre = $outputlangs->transnoentities("PaymentMode").':';
1025 $pdf->MultiCell(80, 5, $titre, 0, 'L');
1026 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1027 $pdf->SetXY($posxval, $posy);
1028 $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);
1029 $pdf->MultiCell(80, 5, $lib_mode_reg, 0, 'L');
1030
1031 $posy = $pdf->GetY() + 2;
1032 }
1033
1034 // Show payment mode CHQ
1035 if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ') {
1036 // Si mode reglement non force ou si force a CHQ
1037 if (getDolGlobalInt('FACTURE_CHQ_NUMBER')) {
1038 if ($conf->global->FACTURE_CHQ_NUMBER > 0) {
1039 $account = new Account($this->db);
1040 $account->fetch(getDolGlobalInt('FACTURE_CHQ_NUMBER'));
1041
1042 $pdf->SetXY($this->marge_gauche, $posy);
1043 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1044 $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $account->proprio), 0, 'L', 0);
1045 $posy = $pdf->GetY() + 1;
1046
1047 if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) {
1048 $pdf->SetXY($this->marge_gauche, $posy);
1049 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1050 $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0);
1051 $posy = $pdf->GetY() + 2;
1052 }
1053 }
1054 if ($conf->global->FACTURE_CHQ_NUMBER == -1) {
1055 $pdf->SetXY($this->marge_gauche, $posy);
1056 $pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1057 $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $this->emetteur->name), 0, 'L', 0);
1058 $posy = $pdf->GetY() + 1;
1059
1060 if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) {
1061 $pdf->SetXY($this->marge_gauche, $posy);
1062 $pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1063 $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0);
1064 $posy = $pdf->GetY() + 2;
1065 }
1066 }
1067 }
1068 }
1069
1070 // If payment mode not forced or forced to VIR, show payment with BAN
1071 if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') {
1072 if (!empty($object->fk_account) || !empty($object->fk_bank) || getDolGlobalInt('FACTURE_RIB_NUMBER')) {
1073 $bankid = (empty($object->fk_account) ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account);
1074 if (!empty($object->fk_bank)) {
1075 $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank
1076 }
1077 $account = new Account($this->db);
1078 $account->fetch($bankid);
1079
1080 $curx = $this->marge_gauche;
1081 $cury = $posy;
1082
1083 $posy = pdf_bank($pdf, $outputlangs, $curx, $cury, $account, 0, $default_font_size);
1084
1085 $posy += 2;
1086 }
1087 }
1088 }
1089
1090 return $posy;
1091 }
1092
1093 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1094 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1106 protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis = null)
1107 {
1108 // phpcs:enable
1109 global $conf, $mysoc;
1110 $default_font_size = pdf_getPDFFontSize($outputlangs);
1111
1112 $tab2_top = $posy;
1113 $tab2_hl = 4;
1114 $pdf->SetFont('', '', $default_font_size - 1);
1115
1116 // Total table
1117 $col1x = 120;
1118 $col2x = 170;
1119 if ($this->page_largeur < 210) { // To work with US executive format
1120 $col2x -= 20;
1121 }
1122 $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
1123
1124 $useborder = 0;
1125 $index = 0;
1126
1127 // Total HT
1128 $pdf->SetFillColor(255, 255, 255);
1129 $pdf->SetXY($col1x, $tab2_top);
1130 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1);
1131
1132 $total_ht = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht);
1133 $pdf->SetXY($col2x, $tab2_top);
1134 $pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + (!empty($object->remise) ? $object->remise : 0), 0, $outputlangs), 0, 'R', 1);
1135
1136 // Show VAT by rates and total
1137 $pdf->SetFillColor(248, 248, 248);
1138
1139 $total_ttc = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
1140
1141 $this->atleastoneratenotnull = 0;
1142 if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) {
1143 $tvaisnull = ((!empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false);
1144 if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull) {
1145 // Nothing to do
1146 } else {
1147 //Local tax 1 before VAT
1148 //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1149 //{
1150 foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1151 if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1152 continue;
1153 }
1154
1155 foreach ($localtax_rate as $tvakey => $tvaval) {
1156 if ($tvakey != 0) { // On affiche pas taux 0
1157 //$this->atleastoneratenotnull++;
1158
1159 $index++;
1160 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1161
1162 $tvacompl = '';
1163 if (preg_match('/\*/', $tvakey)) {
1164 $tvakey = str_replace('*', '', $tvakey);
1165 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1166 }
1167 $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).' ';
1168 $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1169 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1170
1171 $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1172
1173 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1174 $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1);
1175 }
1176 }
1177 }
1178 //}
1179 //Local tax 2 before VAT
1180 //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1181 //{
1182 foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1183 if (in_array((string) $localtax_type, array('1', '3', '5'))) {
1184 continue;
1185 }
1186
1187 foreach ($localtax_rate as $tvakey => $tvaval) {
1188 if ($tvakey != 0) { // On affiche pas taux 0
1189 //$this->atleastoneratenotnull++;
1190
1191 $index++;
1192 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1193
1194 $tvacompl = '';
1195 if (preg_match('/\*/', $tvakey)) {
1196 $tvakey = str_replace('*', '', $tvakey);
1197 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1198 }
1199 $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' ';
1200 $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1201 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1202
1203 $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1204
1205 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1206 $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1);
1207 }
1208 }
1209 }
1210 //}
1211
1212 // VAT
1213 foreach ($this->tva_array as $tvakey => $tvaval) {
1214 if ($tvakey != 0) { // On affiche pas taux 0
1215 $this->atleastoneratenotnull++;
1216
1217 $index++;
1218 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1219
1220 $tvacompl = '';
1221 if (preg_match('/\*/', $tvakey)) {
1222 $tvakey = str_replace('*', '', $tvakey);
1223 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1224 }
1225 $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalVAT", $mysoc->country_code) : '');
1226 $totalvat .= ' ';
1227 if (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'rateonly') {
1228 $totalvat .= vatrate($tvaval['vatrate'], 1).$tvacompl;
1229 } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'codeonly') {
1230 $totalvat .= ($tvaval['vatcode'] ? $tvaval['vatcode'] : vatrate($tvaval['vatrate'], 1)).$tvacompl;
1231 } else {
1232 $totalvat .= vatrate($tvaval['vatrate'], 1).($tvaval['vatcode'] ? ' ('.$tvaval['vatcode'].')' : '').$tvacompl;
1233 }
1234 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1235
1236 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1237 $pdf->MultiCell($largcol2, $tab2_hl, price(price2num($tvaval['amount'], 'MT'), 0, $outputlangs), 0, 'R', 1);
1238 }
1239 }
1240
1241 //Local tax 1 after VAT
1242 //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1243 //{
1244 foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
1245 if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1246 continue;
1247 }
1248
1249 foreach ($localtax_rate as $tvakey => $tvaval) {
1250 if ($tvakey != 0) { // On affiche pas taux 0
1251 //$this->atleastoneratenotnull++;
1252
1253 $index++;
1254 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1255
1256 $tvacompl = '';
1257 if (preg_match('/\*/', $tvakey)) {
1258 $tvakey = str_replace('*', '', $tvakey);
1259 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1260 }
1261 $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).' ';
1262
1263 $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1264 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1265
1266 $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1267
1268 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1269 $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1);
1270 }
1271 }
1272 }
1273 //}
1274 //Local tax 2 after VAT
1275 //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1276 //{
1277 foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
1278 if (in_array((string) $localtax_type, array('2', '4', '6'))) {
1279 continue;
1280 }
1281
1282 foreach ($localtax_rate as $tvakey => $tvaval) {
1283 // retrieve global local tax
1284 if ($tvakey != 0) { // On affiche pas taux 0
1285 //$this->atleastoneratenotnull++;
1286
1287 $index++;
1288 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1289
1290 $tvacompl = '';
1291 if (preg_match('/\*/', $tvakey)) {
1292 $tvakey = str_replace('*', '', $tvakey);
1293 $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1294 }
1295 $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' ';
1296
1297 $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1298 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1299
1300 $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval);
1301
1302 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1303 $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1);
1304 }
1305 }
1306 }
1307 //}
1308
1309 // Total TTC
1310 $index++;
1311 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1312 $pdf->SetTextColor(0, 0, 60);
1313 $pdf->SetFillColor(224, 224, 224);
1314 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1);
1315
1316 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1317 $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', 1);
1318 }
1319 }
1320
1321 $pdf->SetTextColor(0, 0, 0);
1322
1323 /*
1324 $resteapayer = $object->total_ttc - $deja_regle;
1325 if (!empty($object->paye)) $resteapayer=0;
1326 */
1327
1328 if ($deja_regle > 0) {
1329 $index++;
1330
1331 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1332 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid"), 0, 'L', 0);
1333
1334 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1335 $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', 0);
1336
1337 /*
1338 if ($object->close_code == 'discount_vat')
1339 {
1340 $index++;
1341 $pdf->SetFillColor(255,255,255);
1342
1343 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1344 $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("EscompteOfferedShort"), $useborder, 'L', 1);
1345
1346 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1347 $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle, 0, $outputlangs), $useborder, 'R', 1);
1348
1349 $resteapayer=0;
1350 }
1351 */
1352
1353 $index++;
1354 $pdf->SetTextColor(0, 0, 60);
1355 $pdf->SetFillColor(224, 224, 224);
1356 $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1357 $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1);
1358
1359 $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1360 $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1);
1361
1362 $pdf->SetFont('', '', $default_font_size - 1);
1363 $pdf->SetTextColor(0, 0, 0);
1364 }
1365
1366 $index++;
1367 return ($tab2_top + ($tab2_hl * $index));
1368 }
1369
1370 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1384 protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '')
1385 {
1386 global $conf;
1387
1388 // Force to disable hidetop and hidebottom
1389 $hidebottom = 0;
1390 if ($hidetop) {
1391 $hidetop = -1;
1392 }
1393
1394 $currency = !empty($currency) ? $currency : $conf->currency;
1395 $default_font_size = pdf_getPDFFontSize($outputlangs);
1396
1397 // Amount in (at tab_top - 1)
1398 $pdf->SetTextColor(0, 0, 0);
1399 $pdf->SetFont('', '', $default_font_size - 2);
1400
1401 if (empty($hidetop)) {
1402 $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
1403 $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
1404 $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
1405
1406 //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
1407 if (!empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) {
1408 $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite - $this->marge_gauche, 5, 'F', null, explode(',', $conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR));
1409 }
1410 }
1411
1412 $pdf->SetDrawColor(128, 128, 128);
1413 $pdf->SetFont('', '', $default_font_size - 1);
1414
1415 // Output Rect
1416 $this->printRect($pdf, $this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $tab_height, $hidetop, $hidebottom); // Rect takes a length in 3rd parameter and 4th parameter
1417
1418 if (empty($hidetop)) {
1419 $pdf->line($this->marge_gauche, $tab_top + 5, $this->page_largeur - $this->marge_droite, $tab_top + 5); // line takes a position y in 2nd parameter and 4th parameter
1420
1421 $pdf->SetXY($this->posxdesc - 1, $tab_top + 1);
1422 $pdf->MultiCell(108, 2, $outputlangs->transnoentities("Designation"), '', 'L');
1423 }
1424
1425 if (!empty($conf->global->MAIN_GENERATE_PROPOSALS_WITH_PICTURE)) {
1426 $pdf->line($this->posxpicture - 1, $tab_top, $this->posxpicture - 1, $tab_top + $tab_height);
1427 if (empty($hidetop)) {
1428 //$pdf->SetXY($this->posxpicture-1, $tab_top+1);
1429 //$pdf->MultiCell($this->posxtva-$this->posxpicture-1,2, $outputlangs->transnoentities("Photo"),'','C');
1430 }
1431 }
1432
1433 if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
1434 $pdf->line($this->posxtva - 1, $tab_top, $this->posxtva - 1, $tab_top + $tab_height);
1435 if (empty($hidetop)) {
1436 // Not do -3 and +3 instead of -1 -1 to have more space for text 'Sales tax'
1437 $pdf->SetXY($this->posxtva - 3, $tab_top + 1);
1438 $pdf->MultiCell($this->posxup - $this->posxtva + 3, 2, $outputlangs->transnoentities("VAT"), '', 'C');
1439 }
1440 }
1441
1442 $pdf->line($this->posxup - 1, $tab_top, $this->posxup - 1, $tab_top + $tab_height);
1443 if (empty($hidetop)) {
1444 $pdf->SetXY($this->posxup - 1, $tab_top + 1);
1445 $pdf->MultiCell($this->posxqty - $this->posxup - 1, 2, $outputlangs->transnoentities("PriceUHT"), '', 'C');
1446 }
1447
1448 $pdf->line($this->posxqty - 1, $tab_top, $this->posxqty - 1, $tab_top + $tab_height);
1449 if (empty($hidetop)) {
1450 $pdf->SetXY($this->posxqty - 1, $tab_top + 1);
1451 $pdf->MultiCell($this->posxunit - $this->posxqty - 1, 2, $outputlangs->transnoentities("Qty"), '', 'C');
1452 }
1453
1454 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1455 $pdf->line($this->posxunit - 1, $tab_top, $this->posxunit - 1, $tab_top + $tab_height);
1456 if (empty($hidetop)) {
1457 $pdf->SetXY($this->posxunit - 1, $tab_top + 1);
1458 $pdf->MultiCell(
1459 $this->posxdiscount - $this->posxunit - 1,
1460 2,
1461 $outputlangs->transnoentities("Unit"),
1462 '',
1463 'C'
1464 );
1465 }
1466 }
1467
1468 $pdf->line($this->posxdiscount - 1, $tab_top, $this->posxdiscount - 1, $tab_top + $tab_height);
1469 if (empty($hidetop)) {
1470 if ($this->atleastonediscount) {
1471 $pdf->SetXY($this->posxdiscount - 1, $tab_top + 1);
1472 $pdf->MultiCell($this->postotalht - $this->posxdiscount + 1, 2, $outputlangs->transnoentities("ReductionShort"), '', 'C');
1473 }
1474 }
1475 if ($this->atleastonediscount) {
1476 $pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height);
1477 }
1478 if (empty($hidetop)) {
1479 $pdf->SetXY($this->postotalht - 1, $tab_top + 1);
1480 $pdf->MultiCell(30, 2, $outputlangs->transnoentities("TotalHTShort"), '', 'C');
1481 }
1482 }
1483
1484 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1495 protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null)
1496 {
1497 global $conf, $langs;
1498
1499 $ltrdirection = 'L';
1500 if ($outputlangs->trans("DIRECTION") == 'rtl') $ltrdirection = 'R';
1501
1502 // Load traductions files required by page
1503 $outputlangs->loadLangs(array("main", "propal", "companies", "bills"));
1504
1505 $default_font_size = pdf_getPDFFontSize($outputlangs);
1506
1507 pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
1508
1509 $pdf->SetTextColor(0, 0, 60);
1510 $pdf->SetFont('', 'B', $default_font_size + 3);
1511
1512 $w = 100;
1513
1514 $posy = $this->marge_haute;
1515 $posx = $this->page_largeur - $this->marge_droite - $w;
1516
1517 $pdf->SetXY($this->marge_gauche, $posy);
1518
1519 // Logo
1520 if (!getDolGlobalInt('PDF_DISABLE_MYCOMPANY_LOGO')) {
1521 if ($this->emetteur->logo) {
1522 $logodir = $conf->mycompany->dir_output;
1523 if (!empty($conf->mycompany->multidir_output[$object->entity])) {
1524 $logodir = $conf->mycompany->multidir_output[$object->entity];
1525 }
1526 if (!getDolGlobalInt('MAIN_PDF_USE_LARGE_LOGO')) {
1527 $logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
1528 } else {
1529 $logo = $logodir.'/logos/'.$this->emetteur->logo;
1530 }
1531 if (is_readable($logo)) {
1532 $height = pdf_getHeightForLogo($logo);
1533 $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
1534 } else {
1535 $pdf->SetTextColor(200, 0, 0);
1536 $pdf->SetFont('', 'B', $default_font_size - 2);
1537 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
1538 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
1539 }
1540 } else {
1541 $text = $this->emetteur->name;
1542 $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);
1543 }
1544 }
1545
1546 $pdf->SetFont('', 'B', $default_font_size + 3);
1547 $pdf->SetXY($posx, $posy);
1548 $pdf->SetTextColor(0, 0, 60);
1549 $title = $outputlangs->transnoentities("PdfCommercialProposalTitle");
1550 $title .= ' '.$outputlangs->convToOutputCharset($object->ref);
1551 if ($object->statut == $object::STATUS_DRAFT) {
1552 $pdf->SetTextColor(128, 0, 0);
1553 $title .= ' - '.$outputlangs->transnoentities("NotValidated");
1554 }
1555 $pdf->MultiCell(100, 4, $title, '', 'R');
1556
1557 $pdf->SetFont('', 'B', $default_font_size);
1558
1559 /*
1560 $posy += 5;
1561 $pdf->SetXY($posx, $posy);
1562 $pdf->SetTextColor(0, 0, 60);
1563 $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Ref")." : ".$outputlangs->convToOutputCharset($object->ref), '', 'R');
1564 */
1565
1566 $posy += 3;
1567 $pdf->SetFont('', '', $default_font_size - 2);
1568
1569 if ($object->ref_client) {
1570 $posy += 4;
1571 $pdf->SetXY($posx, $posy);
1572 $pdf->SetTextColor(0, 0, 60);
1573 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R');
1574 }
1575
1576 if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) {
1577 $object->fetch_projet();
1578 if (!empty($object->project->ref)) {
1579 $posy += 3;
1580 $pdf->SetXY($posx, $posy);
1581 $pdf->SetTextColor(0, 0, 60);
1582 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->project->title), '', 'R');
1583 }
1584 }
1585
1586 if (!empty($conf->global->PDF_SHOW_PROJECT)) {
1587 $object->fetch_projet();
1588 if (!empty($object->project->ref)) {
1589 $outputlangs->load("projects");
1590 $posy += 3;
1591 $pdf->SetXY($posx, $posy);
1592 $pdf->SetTextColor(0, 0, 60);
1593 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefProject")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R');
1594 }
1595 }
1596
1597 if (!empty($conf->global->MAIN_PDF_DATE_TEXT)) {
1598 $displaydate = "daytext";
1599 } else {
1600 $displaydate = "day";
1601 }
1602
1603 //$posy += 4;
1604 $posy = $pdf->getY();
1605 $pdf->SetXY($posx, $posy);
1606 $pdf->SetTextColor(0, 0, 60);
1607 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("DatePropal")." : ".dol_print_date($object->date, $displaydate, false, $outputlangs, true), '', 'R');
1608
1609 $posy += 4;
1610 $pdf->SetXY($posx, $posy);
1611 $pdf->SetTextColor(0, 0, 60);
1612 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("DateEndPropal")." : ".dol_print_date($object->fin_validite, $displaydate, false, $outputlangs, true), '', 'R');
1613
1614 if (empty($conf->global->MAIN_PDF_HIDE_CUSTOMER_CODE) && $object->thirdparty->code_client) {
1615 $posy += 4;
1616 $pdf->SetXY($posx, $posy);
1617 $pdf->SetTextColor(0, 0, 60);
1618 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R');
1619 }
1620
1621 // Get contact
1622 if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) {
1623 $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1624 if (count($arrayidcontact) > 0) {
1625 $usertmp = new User($this->db);
1626 $usertmp->fetch($arrayidcontact[0]);
1627 $posy += 4;
1628 $pdf->SetXY($posx, $posy);
1629 $pdf->SetTextColor(0, 0, 60);
1630 $pdf->MultiCell(100, 3, $outputlangs->trans("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
1631 }
1632 }
1633
1634 $posy += 2;
1635
1636 $top_shift = 0;
1637 // Show list of linked objects
1638 $current_y = $pdf->getY();
1639 $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size);
1640 if ($current_y < $pdf->getY()) {
1641 $top_shift = $pdf->getY() - $current_y;
1642 }
1643
1644 if ($showaddress) {
1645 // Sender properties
1646 $carac_emetteur = '';
1647 // Add internal contact of object if defined
1648 $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1649 if (count($arrayidcontact) > 0) {
1650 $object->fetch_user($arrayidcontact[0]);
1651 $labelbeforecontactname = ($outputlangs->transnoentities("FromContactName") != 'FromContactName' ? $outputlangs->transnoentities("FromContactName") : $outputlangs->transnoentities("Name"));
1652 $carac_emetteur .= ($carac_emetteur ? "\n" : '').$labelbeforecontactname." ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs));
1653 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ' (' : '';
1654 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && !empty($object->user->office_phone)) ? $object->user->office_phone : '';
1655 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ', ' : '';
1656 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT') && !empty($object->user->email)) ? $object->user->email : '';
1657 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ')' : '';
1658 $carac_emetteur .= "\n";
1659 }
1660
1661 $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
1662
1663 // Show sender
1664 $posy = 42 + $top_shift;
1665 $posx = $this->marge_gauche;
1666 if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1667 $posx = $this->page_largeur - $this->marge_droite - 80;
1668 }
1669 $hautcadre = 40;
1670
1671 // Show sender frame
1672 if (empty($conf->global->MAIN_PDF_NO_SENDER_FRAME)) {
1673 $pdf->SetTextColor(0, 0, 0);
1674 $pdf->SetFont('', '', $default_font_size - 2);
1675 $pdf->SetXY($posx, $posy - 5);
1676 $pdf->MultiCell(80, 5, $outputlangs->transnoentities("BillFrom"), 0, $ltrdirection);
1677 $pdf->SetXY($posx, $posy);
1678 $pdf->SetFillColor(230, 230, 230);
1679 $pdf->MultiCell(82, $hautcadre, "", 0, 'R', 1);
1680 $pdf->SetTextColor(0, 0, 60);
1681 }
1682
1683 // Show company name
1684 if (empty($conf->global->MAIN_PDF_HIDE_SENDER_NAME)) {
1685 $pdf->SetXY($posx + 2, $posy + 3);
1686 $pdf->SetFont('', 'B', $default_font_size);
1687 $pdf->MultiCell(80, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, $ltrdirection);
1688 $posy = $pdf->getY();
1689 }
1690
1691 // Show sender information
1692 $pdf->SetXY($posx + 2, $posy);
1693 $pdf->SetFont('', '', $default_font_size - 1);
1694 $pdf->MultiCell(80, 4, $carac_emetteur, 0, $ltrdirection);
1695
1696
1697 // If CUSTOMER contact defined, we use it
1698 $usecontact = false;
1699 $arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
1700 if (count($arrayidcontact) > 0) {
1701 $usecontact = true;
1702 $result = $object->fetch_contact($arrayidcontact[0]);
1703 }
1704
1705 // Recipient name
1706 if ($usecontact && ($object->contact->socid != $object->thirdparty->id && (!isset($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT) || !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)))) {
1707 $thirdparty = $object->contact;
1708 } else {
1709 $thirdparty = $object->thirdparty;
1710 }
1711
1712 $carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);
1713
1714 $mode = 'target';
1715 $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), $usecontact, $mode, $object);
1716
1717 // Show recipient
1718 $widthrecbox = 100;
1719 if ($this->page_largeur < 210) {
1720 $widthrecbox = 84; // To work with US executive format
1721 }
1722 $posy = 42 + $top_shift;
1723 $posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
1724 if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1725 $posx = $this->marge_gauche;
1726 }
1727
1728 // Show recipient frame
1729 if (empty($conf->global->MAIN_PDF_NO_RECIPENT_FRAME)) {
1730 $pdf->SetTextColor(0, 0, 0);
1731 $pdf->SetFont('', '', $default_font_size - 2);
1732 $pdf->SetXY($posx + 2, $posy - 5);
1733 $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo"), 0, $ltrdirection);
1734 $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
1735 }
1736
1737 // Show recipient name
1738 $pdf->SetXY($posx + 2, $posy + 3);
1739 $pdf->SetFont('', 'B', $default_font_size);
1740 $pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, $ltrdirection);
1741
1742 $posy = $pdf->getY();
1743
1744 // Show recipient information
1745 $pdf->SetFont('', '', $default_font_size - 1);
1746 $pdf->SetXY($posx + 2, $posy);
1747 $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, $ltrdirection);
1748 }
1749
1750 $pdf->SetTextColor(0, 0, 0);
1751 return $top_shift;
1752 }
1753
1754 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1764 protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
1765 {
1766 $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0);
1767 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);
1768 }
1769
1770 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1771 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1781 protected function _signature_area(&$pdf, $object, $posy, $outputlangs)
1782 {
1783 // phpcs:enable
1784 global $conf;
1785 $default_font_size = pdf_getPDFFontSize($outputlangs);
1786 $tab_top = $posy + 4;
1787 $tab_hl = 4;
1788
1789 $posx = 120;
1790 $largcol = ($this->page_largeur - $this->marge_droite - $posx);
1791 $useborder = 0;
1792 $index = 0;
1793 // Total HT
1794 $pdf->SetFillColor(255, 255, 255);
1795 $pdf->SetXY($posx, $tab_top);
1796 $pdf->SetFont('', '', $default_font_size - 2);
1797 $pdf->MultiCell($largcol, $tab_hl, $outputlangs->transnoentities("ProposalCustomerSignature"), 0, 'L', 1);
1798
1799 $pdf->SetXY($posx, $tab_top + $tab_hl);
1800 $pdf->MultiCell($largcol, $tab_hl * 3, '', 1, 'R');
1801 if (!empty($conf->global->MAIN_PDF_PROPAL_USE_ELECTRONIC_SIGNING)) {
1802 $pdf->addEmptySignatureAppearance($posx, $tab_top + $tab_hl, $largcol, $tab_hl * 3);
1803 }
1804
1805 return ($tab_hl * 7);
1806 }
1807}
Class to manage bank accounts.
printRect($pdf, $x, $y, $l, $h, $hidetop=0, $hidebottom=0)
Rect pdf.
Class to manage hooks.
Classe 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 Azur.
_tableau_info(&$pdf, $object, $posy, $outputlangs)
Show miscellaneous information (payment mode, payment term, ...)
__construct($db)
Constructor.
_pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis=null)
Show top header of page.
_signature_area(&$pdf, $object, $posy, $outputlangs)
Show area for the customer to sign.
_tableau_versements(&$pdf, $object, $posy, $outputlangs)
Show payments table.
_tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='')
Show table for lines.
write_file($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0)
Function to build pdf onto disk.
_pagefoot(&$pdf, $object, $outputlangs, $hidefreetext=0)
Show footer of page.
_tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis=null)
Show total to pay.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
if(!function_exists( 'dolEscapeXML')) convertBackOfficeMediasLinksToPublicLinks($notetoshow)
Convert links to local wrapper to medias files into a string into a public external URL readable on i...
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
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.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return 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_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
pdf_getSizeForImage($realpath)
Return dimensions to use for images onto PDF checking that width and height are not higher than maxim...
Definition pdf.lib.php:2529
pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line total excluding tax.
Definition pdf.lib.php:2284
pdf_getPDFFontSize($outputlangs)
Return font size to use for PDF generation.
Definition pdf.lib.php:289
pdf_getFormat(Translate $outputlangs=null, $mode='setup')
Return array with format properties of default PDF format.
Definition pdf.lib.php:85
pdf_writelinedesc(&$pdf, $object, $i, $outputlangs, $w, $h, $posx, $posy, $hideref=0, $hidedesc=0, $issupplierline=0)
Output line description into PDF.
Definition pdf.lib.php:1374
pdf_getHeightForLogo($logo, $url=false)
Return height to use for Logo onto PDF.
Definition pdf.lib.php:314
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:1010
pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails=0)
Return line unit price excluding tax.
Definition pdf.lib.php:1901
pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails=0)
Return line vat rate.
Definition pdf.lib.php:1839
pdf_getlineunit($object, $i, $outputlangs, $hidedetails=0, $hookmanager=false)
Return line unit.
Definition pdf.lib.php:2147
pdfGetHeightForHtmlContent(&$pdf, $htmlcontent)
Function to try to calculate height of a HTML Content.
Definition pdf.lib.php:339
pdf_pagehead(&$pdf, $outputlangs, $page_height)
Show header of page for PDF generation.
Definition pdf.lib.php:726
pdf_writeLinkedObjects(&$pdf, $object, $outputlangs, $posx, $posy, $w, $h, $align, $default_font_size)
Show linked objects for PDF generation.
Definition pdf.lib.php:1338
pdf_bank(&$pdf, $outputlangs, $curx, $cury, $account, $onlynumber=0, $default_font_size=10)
Show bank informations for PDF generation.
Definition pdf.lib.php:833
pdf_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition pdf.lib.php:266
pdf_build_address($outputlangs, $sourcecompany, $targetcompany='', $targetcontact='', $usecontact=0, $mode='source', $object=null)
Return a string with full address formated for output on documents.
Definition pdf.lib.php:435
pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails=0)
Return line remise percent.
Definition pdf.lib.php:2190
pdf_getlineqty($object, $i, $outputlangs, $hidedetails=0)
Return line quantity.
Definition pdf.lib.php:1986
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:758
pdf_getInstance($format='', $metric='mm', $pagetype='P')
Return a PDF instance object.
Definition pdf.lib.php:127
pdfBuildThirdpartyName($thirdparty, Translate $outputlangs, $includealias=0)
Returns the name of the thirdparty.
Definition pdf.lib.php:387
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:120
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:123