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