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