Passed
Branch develop (944e2a)
by
unknown
27:19
created

pdf_cyan::drawSignatureArea()   A

Complexity

Conditions 2

Size

Total Lines 24
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

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