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

pdf_cyan::_tableau()   B

Complexity

Conditions 8

Size

Total Lines 41
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 21
nop 9
dl 0
loc 41
rs 8.4444
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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