Passed
Push — master ( 1007d6...492b54 )
by Alxarafe
26:10
created

dolibarr/htdocs/core/lib/pdf.lib.php (1 issue)

1
<?php
2
/* Copyright (C) 2006-2017	Laurent Destailleur 	<[email protected]>
3
 * Copyright (C) 2006		Rodolphe Quiedeville	<[email protected]>
4
 * Copyright (C) 2007		Patrick Raguin      	<[email protected]>
5
 * Copyright (C) 2010-2012	Regis Houssin       	<[email protected]>
6
 * Copyright (C) 2010-2017	Juanjo Menent       	<[email protected]>
7
 * Copyright (C) 2012		Christophe Battarel		<[email protected]>
8
 * Copyright (C) 2012       Cédric Salvador         <[email protected]>
9
 * Copyright (C) 2012-2015  Raphaël Doursenaud      <[email protected]>
10
 * Copyright (C) 2014		Cedric GROSS			<[email protected]>
11
 * Copyright (C) 2014		Teddy Andreotti			<[email protected]>
12
 * Copyright (C) 2015-2016  Marcos García           <[email protected]>
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 3 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26
 * or see http://www.gnu.org/
27
 */
28
29
/**
30
 *	\file       htdocs/core/lib/pdf.lib.php
31
 *	\brief      Set of functions used for PDF generation
32
 *	\ingroup    core
33
 */
34
35
36
/**
37
 *	Return array with format properties of default PDF format
38
 *
39
 *	@param		Translate	$outputlangs		Output lang to use to autodetect output format if setup not done
40
 *  @return     array							Array('width'=>w,'height'=>h,'unit'=>u);
41
 */
42
function pdf_getFormat(Translate $outputlangs = null)
43
{
44
	global $conf,$db;
45
46
	// Default value if setup was not done and/or entry into c_paper_format not defined
47
	$width=210; $height=297; $unit='mm';
48
49
	if (empty($conf->global->MAIN_PDF_FORMAT))
50
	{
51
		include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
52
		$pdfformat=dol_getDefaultFormat($outputlangs);
53
	}
54
	else $pdfformat=$conf->global->MAIN_PDF_FORMAT;
55
56
	$sql="SELECT code, label, width, height, unit FROM ".MAIN_DB_PREFIX."c_paper_format";
57
	$sql.=" WHERE code = '".$pdfformat."'";
58
	$resql=$db->query($sql);
59
	if ($resql)
60
	{
61
		$obj=$db->fetch_object($resql);
62
		if ($obj)
63
		{
64
			$width=(int) $obj->width;
65
			$height=(int) $obj->height;
66
			$unit=$obj->unit;
67
		}
68
	}
69
70
	//print "pdfformat=".$pdfformat." width=".$width." height=".$height." unit=".$unit;
71
	return array('width'=>$width,'height'=>$height,'unit'=>$unit);
72
}
73
74
/**
75
 *      Return a PDF instance object. We create a FPDI instance that instantiate TCPDF.
76
 *
77
 *      @param	string		$format         Array(width,height). Keep empty to use default setup.
78
 *      @param	string		$metric         Unit of format ('mm')
79
 *      @param  string		$pagetype       'P' or 'l'
80
 *      @return TCPDF						PDF object
81
 */
82
function pdf_getInstance($format='',$metric='mm',$pagetype='P')
83
{
84
	global $conf;
85
86
	// Define constant for TCPDF
87
	if (! defined('K_TCPDF_EXTERNAL_CONFIG'))
88
	{
89
		define('K_TCPDF_EXTERNAL_CONFIG',1);	// this avoid using tcpdf_config file
90
		define('K_PATH_CACHE', DOL_DATA_ROOT.'/admin/temp/');
91
		define('K_PATH_URL_CACHE', DOL_DATA_ROOT.'/admin/temp/');
92
		dol_mkdir(K_PATH_CACHE);
93
		define('K_BLANK_IMAGE', '_blank.png');
94
		define('PDF_PAGE_FORMAT', 'A4');
95
		define('PDF_PAGE_ORIENTATION', 'P');
96
		define('PDF_CREATOR', 'TCPDF');
97
		define('PDF_AUTHOR', 'TCPDF');
98
		define('PDF_HEADER_TITLE', 'TCPDF Example');
99
		define('PDF_HEADER_STRING', "by Dolibarr ERP CRM");
100
		define('PDF_UNIT', 'mm');
101
		define('PDF_MARGIN_HEADER', 5);
102
		define('PDF_MARGIN_FOOTER', 10);
103
		define('PDF_MARGIN_TOP', 27);
104
		define('PDF_MARGIN_BOTTOM', 25);
105
		define('PDF_MARGIN_LEFT', 15);
106
		define('PDF_MARGIN_RIGHT', 15);
107
		define('PDF_FONT_NAME_MAIN', 'helvetica');
108
		define('PDF_FONT_SIZE_MAIN', 10);
109
		define('PDF_FONT_NAME_DATA', 'helvetica');
110
		define('PDF_FONT_SIZE_DATA', 8);
111
		define('PDF_FONT_MONOSPACED', 'courier');
112
		define('PDF_IMAGE_SCALE_RATIO', 1.25);
113
		define('HEAD_MAGNIFICATION', 1.1);
114
		define('K_CELL_HEIGHT_RATIO', 1.25);
115
		define('K_TITLE_MAGNIFICATION', 1.3);
116
		define('K_SMALL_RATIO', 2/3);
117
		define('K_THAI_TOPCHARS', true);
118
		define('K_TCPDF_CALLS_IN_HTML', true);
119
		define('K_TCPDF_THROW_EXCEPTION_ERROR', false);
120
	}
121
122
	// Load TCPDF
123
	require_once TCPDF_PATH.'tcpdf.php';
124
125
	// We need to instantiate tcpdi object (instead of tcpdf) to use merging features. But we can disable it (this will break all merge features).
126
	if (empty($conf->global->MAIN_DISABLE_TCPDI)) require_once TCPDI_PATH.'tcpdi.php';
127
128
	//$arrayformat=pdf_getFormat();
129
	//$format=array($arrayformat['width'],$arrayformat['height']);
130
	//$metric=$arrayformat['unit'];
131
132
	$pdfa=false;											// PDF-1.3
133
	if (! empty($conf->global->PDF_USE_1A)) $pdfa=true;		// PDF1/A
134
135
	if (class_exists('TCPDI')) $pdf = new TCPDI($pagetype,$metric,$format,true,'UTF-8',false,$pdfa);
136
	else $pdf = new TCPDF($pagetype,$metric,$format,true,'UTF-8',false,$pdfa);
137
138
	// Protection and encryption of pdf
139
	if (! empty($conf->global->PDF_SECURITY_ENCRYPTION))
140
	{
141
		/* Permission supported by TCPDF
142
		- print : Print the document;
143
		- modify : Modify the contents of the document by operations other than those controlled by 'fill-forms', 'extract' and 'assemble';
144
		- copy : Copy or otherwise extract text and graphics from the document;
145
		- annot-forms : Add or modify text annotations, fill in interactive form fields, and, if 'modify' is also set, create or modify interactive form fields (including signature fields);
146
		- fill-forms : Fill in existing interactive form fields (including signature fields), even if 'annot-forms' is not specified;
147
		- extract : Extract text and graphics (in support of accessibility to users with disabilities or for other purposes);
148
		- assemble : Assemble the document (insert, rotate, or delete pages and create bookmarks or thumbnail images), even if 'modify' is not set;
149
		- print-high : Print the document to a representation from which a faithful digital copy of the PDF content could be generated. When this is not set, printing is limited to a low-level representation of the appearance, possibly of degraded quality.
150
		- owner : (inverted logic - only for public-key) when set permits change of encryption and enables all other permissions.
151
		*/
152
153
		// For TCPDF, we specify permission we want to block
154
		$pdfrights = (! empty($conf->global->PDF_SECURITY_ENCRYPTION_RIGHTS)?json_decode($conf->global->PDF_SECURITY_ENCRYPTION_RIGHTS, true):array('modify','copy')); // Json format in llx_const
155
156
		// Password for the end user
157
		$pdfuserpass = (! empty($conf->global->PDF_SECURITY_ENCRYPTION_USERPASS)?$conf->global->PDF_SECURITY_ENCRYPTION_USERPASS:'');
158
159
		// Password of the owner, created randomly if not defined
160
		$pdfownerpass = (! empty($conf->global->PDF_SECURITY_ENCRYPTION_OWNERPASS)?$conf->global->PDF_SECURITY_ENCRYPTION_OWNERPASS:null);
161
162
		// For encryption strength: 0 = RC4 40 bit; 1 = RC4 128 bit; 2 = AES 128 bit; 3 = AES 256 bit
163
		$encstrength = (! empty($conf->global->PDF_SECURITY_ENCRYPTION_STRENGTH)?$conf->global->PDF_SECURITY_ENCRYPTION_STRENGTH:0);
164
165
		// Array of recipients containing public-key certificates ('c') and permissions ('p').
166
		// For example: array(array('c' => 'file://../examples/data/cert/tcpdf.crt', 'p' => array('print')))
167
		$pubkeys = (! empty($conf->global->PDF_SECURITY_ENCRYPTION_PUBKEYS)?json_decode($conf->global->PDF_SECURITY_ENCRYPTION_PUBKEYS, true):null); // Json format in llx_const
168
169
		$pdf->SetProtection($pdfrights,$pdfuserpass,$pdfownerpass,$encstrength,$pubkeys);
170
	}
171
172
	return $pdf;
173
}
174
175
/**
176
 * Return if pdf file is protected/encrypted
177
 *
178
 * @param	TCPDF		$pdf			PDF initialized object
179
 * @param   string		$pathoffile		Path of file
180
 * @return  boolean     			    True or false
181
 */
182
function pdf_getEncryption(&$pdf, $pathoffile)
183
{
184
	$isencrypted = false;
185
186
	$pdfparser = $pdf->_getPdfParser($pathoffile);
187
	$data = $pdfparser->getParsedData();
188
	if (isset($data[0]['trailer'][1]['/Encrypt'])) {
189
		$isencrypted = true;
190
	}
191
192
	return $isencrypted;
193
}
194
195
/**
196
 *      Return font name to use for PDF generation
197
 *
198
 *      @param	Translate	$outputlangs    Output langs object
199
 *      @return string          			Name of font to use
200
 */
201
function pdf_getPDFFont($outputlangs)
202
{
203
	global $conf;
204
205
	if (! empty($conf->global->MAIN_PDF_FORCE_FONT)) return $conf->global->MAIN_PDF_FORCE_FONT;
206
207
	$font='Helvetica'; // By default, for FPDI, or ISO language on TCPDF
208
	if (class_exists('TCPDF'))  // If TCPDF on, we can use an UTF8 one like DejaVuSans if required (slower)
209
	{
210
		if ($outputlangs->trans('FONTFORPDF')!='FONTFORPDF')
211
		{
212
			$font=$outputlangs->trans('FONTFORPDF');
213
		}
214
	}
215
	return $font;
216
}
217
218
/**
219
 *      Return font size to use for PDF generation
220
 *
221
 *      @param	Translate	$outputlangs     Output langs object
222
 *      @return int				             Size of font to use
223
 */
224
function pdf_getPDFFontSize($outputlangs)
225
{
226
	$size=10;                   // By default, for FPDI or ISO language on TCPDF
227
	if (class_exists('TCPDF'))  // If TCPDF on, we can use an UTF8 one like DejaVuSans if required (slower)
228
	{
229
		if ($outputlangs->trans('FONTSIZEFORPDF')!='FONTSIZEFORPDF')
230
		{
231
			$size = (int) $outputlangs->trans('FONTSIZEFORPDF');
232
		}
233
	}
234
	return $size;
235
}
236
237
238
/**
239
 * Return height to use for Logo onto PDF
240
 *
241
 * @param	string		$logo		Full path to logo file to use
242
 * @param	bool		$url		Image with url (true or false)
243
 * @return	number
244
 */
245
function pdf_getHeightForLogo($logo, $url = false)
246
{
247
	global $conf;
248
	$height=(empty($conf->global->MAIN_DOCUMENTS_LOGO_HEIGHT)?22:$conf->global->MAIN_DOCUMENTS_LOGO_HEIGHT);
249
	$maxwidth=130;
250
	include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
251
	$tmp=dol_getImageSize($logo, $url);
252
	if ($tmp['height'])
253
	{
254
		$width=round($height*$tmp['width']/$tmp['height']);
255
		if ($width > $maxwidth) $height=$height*$maxwidth/$width;
256
	}
257
	//print $tmp['width'].' '.$tmp['height'].' '.$width; exit;
258
	return $height;
259
}
260
261
/**
262
 * Function to try to calculate height of a HTML Content
263
 *
264
 * @param 	TCPDF     $pdf				PDF initialized object
265
 * @param 	string    $htmlcontent		HTML Contect
266
 * @return 	int							Height
267
 * @see getStringHeight
268
 */
269
function pdfGetHeightForHtmlContent(&$pdf, $htmlcontent)
270
{
271
    // store current object
272
    $pdf->startTransaction();
273
    // store starting values
274
    $start_y = $pdf->GetY();
275
    //var_dump($start_y);
276
    $start_page = $pdf->getPage();
277
    // call printing functions with content
278
    $pdf->writeHTMLCell(0, 0, 0, $start_y, $htmlcontent, 0, 1, false, true, 'J',true);
279
    // get the new Y
280
    $end_y = $pdf->GetY();
281
    $end_page = $pdf->getPage();
282
    // calculate height
283
    $height = 0;
284
    if ($end_page == $start_page) {
285
        $height = $end_y - $start_y;
286
    }
287
    else
288
    {
289
        for ($page=$start_page; $page <= $end_page; ++$page) {
290
        	$pdf->setPage($page);
291
        	$tmpm=$pdf->getMargins();
292
        	$tMargin = $tmpm['top'];
293
        	if ($page == $start_page) {
294
        		// first page
295
        		$height = $pdf->getPageHeight() - $start_y - $pdf->getBreakMargin();
296
        	} elseif ($page == $end_page) {
297
        		// last page
298
        		$height = $end_y - $tMargin;
299
        	} else {
300
        		$height = $pdf->getPageHeight() - $tMargin - $pdf->getBreakMargin();
301
        	}
302
        }
303
	}
304
	// restore previous object
305
	$pdf = $pdf->rollbackTransaction();
306
307
    return $height;
308
}
309
310
311
/**
312
 * Returns the name of the thirdparty
313
 *
314
 * @param   Societe|Contact     $thirdparty     Contact or thirdparty
315
 * @param   Translate           $outputlangs    Output language
316
 * @param   int                 $includealias   1=Include alias name after name
317
 * @return  string                              String with name of thirdparty (+ alias if requested)
318
 */
319
function pdfBuildThirdpartyName($thirdparty, Translate $outputlangs, $includealias=0)
320
{
321
    global $conf;
322
323
	// Recipient name
324
	$socname = '';
325
326
	if ($thirdparty instanceof Societe) {
327
		$socname .= $thirdparty->name;
328
		if (($includealias || ! empty($conf->global->PDF_INCLUDE_ALIAS_IN_THIRDPARTY_NAME)) && !empty($thirdparty->name_alias)) {
329
		    $socname .= "\n".$thirdparty->name_alias;
330
		}
331
	} elseif ($thirdparty instanceof Contact) {
332
		$socname = $thirdparty->socname;
333
	} else {
334
		throw new InvalidArgumentException('Parameter 1 $thirdparty is not a Societe nor Contact');
335
	}
336
337
	return $outputlangs->convToOutputCharset($socname);
338
}
339
340
341
/**
342
 *   	Return a string with full address formated for output on documents
343
 *
344
 * 		@param	Translate	$outputlangs		Output langs object
345
 *   	@param  Societe		$sourcecompany		Source company object
346
 *   	@param  Societe		$targetcompany		Target company object
347
 *      @param  Contact		$targetcontact		Target contact object
348
 * 		@param	int			$usecontact			Use contact instead of company
349
 * 		@param	int			$mode				Address type ('source', 'target', 'targetwithdetails', 'targetwithdetails_xxx': target but include also phone/fax/email/url)
350
 *      @param  Object      $object             Object we want to build document for
351
 * 		@return	string							String with full address
352
 */
353
function pdf_build_address($outputlangs,$sourcecompany,$targetcompany='',$targetcontact='',$usecontact=0,$mode='source',$object=null)
354
{
355
	global $conf, $hookmanager;
356
357
	if ($mode == 'source' && ! is_object($sourcecompany)) return -1;
358
	if ($mode == 'target' && ! is_object($targetcompany)) return -1;
359
360
	if (! empty($sourcecompany->state_id) && empty($sourcecompany->departement)) $sourcecompany->departement=getState($sourcecompany->state_id); //TODO deprecated
0 ignored issues
show
Deprecated Code introduced by
The property Societe::$departement has been deprecated: Use state instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

360
	if (! empty($sourcecompany->state_id) && empty(/** @scrutinizer ignore-deprecated */ $sourcecompany->departement)) $sourcecompany->departement=getState($sourcecompany->state_id); //TODO deprecated

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
361
	if (! empty($sourcecompany->state_id) && empty($sourcecompany->state))       $sourcecompany->state=getState($sourcecompany->state_id);
362
	if (! empty($sourcecompany->state_id) && !isset($sourcecompany->departement_id))   $sourcecompany->departement_id=getState($sourcecompany->state_id,'2');
363
	if (! empty($targetcompany->state_id) && empty($targetcompany->departement)) $targetcompany->departement=getState($targetcompany->state_id); //TODO deprecated
364
	if (! empty($targetcompany->state_id) && empty($targetcompany->state))       $targetcompany->state=getState($targetcompany->state_id);
365
	if (! empty($targetcompany->state_id) && !isset($targetcompany->departement_id))   $targetcompany->departement_id=getState($targetcompany->state_id,'2');
366
367
	$reshook=0;
368
	$stringaddress = '';
369
	if (is_object($hookmanager))
370
	{
371
		$parameters = array('sourcecompany'=>&$sourcecompany,'targetcompany'=>&$targetcompany,'targetcontact'=>$targetcontact,'outputlangs'=>$outputlangs,'mode'=>$mode,'usecontact'=>$usecontact);
372
		$action='';
373
		$reshook = $hookmanager->executeHooks('pdf_build_address',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
374
		$stringaddress.=$hookmanager->resPrint;
375
	}
376
	if (empty($reshook))
377
	{
378
    	if ($mode == 'source')
379
    	{
380
    		$withCountry = 0;
381
    		if (!empty($sourcecompany->country_code) && ($targetcompany->country_code != $sourcecompany->country_code)) $withCountry = 1;
382
383
    		$stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->convToOutputCharset(dol_format_address($sourcecompany, $withCountry, "\n", $outputlangs))."\n";
384
385
    		if (empty($conf->global->MAIN_PDF_DISABLESOURCEDETAILS))
386
    		{
387
    			// Phone
388
    			if ($sourcecompany->phone) $stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("PhoneShort").": ".$outputlangs->convToOutputCharset($sourcecompany->phone);
389
    			// Fax
390
    			if ($sourcecompany->fax) $stringaddress .= ($stringaddress ? ($sourcecompany->phone ? " - " : "\n") : '' ).$outputlangs->transnoentities("Fax").": ".$outputlangs->convToOutputCharset($sourcecompany->fax);
391
    			// EMail
392
    			if ($sourcecompany->email) $stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("Email").": ".$outputlangs->convToOutputCharset($sourcecompany->email);
393
    			// Web
394
    			if ($sourcecompany->url) $stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("Web").": ".$outputlangs->convToOutputCharset($sourcecompany->url);
395
    		}
396
    		// Intra VAT
397
    		if (! empty($conf->global->MAIN_TVAINTRA_IN_SOURCE_ADDRESS))
398
    		{
399
    			if ($sourcecompany->tva_intra) $stringaddress.=($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("VATIntraShort").': '.$outputlangs->convToOutputCharset($sourcecompany->tva_intra);
400
    		}
401
    		// Professionnal Ids
402
    		if (! empty($conf->global->MAIN_PROFID1_IN_SOURCE_ADDRESS) && ! empty($sourcecompany->idprof1))
403
    		{
404
    			$tmp=$outputlangs->transcountrynoentities("ProfId1",$sourcecompany->country_code);
405
    			if (preg_match('/\((.+)\)/',$tmp,$reg)) $tmp=$reg[1];
406
    			$stringaddress.=($stringaddress ? "\n" : '' ).$tmp.': '.$outputlangs->convToOutputCharset($sourcecompany->idprof1);
407
    		}
408
    		if (! empty($conf->global->MAIN_PROFID2_IN_SOURCE_ADDRESS) && ! empty($sourcecompany->idprof2))
409
    		{
410
    			$tmp=$outputlangs->transcountrynoentities("ProfId2",$sourcecompany->country_code);
411
    			if (preg_match('/\((.+)\)/',$tmp,$reg)) $tmp=$reg[1];
412
    			$stringaddress.=($stringaddress ? "\n" : '' ).$tmp.': '.$outputlangs->convToOutputCharset($sourcecompany->idprof2);
413
    		}
414
    		if (! empty($conf->global->MAIN_PROFID3_IN_SOURCE_ADDRESS) && ! empty($sourcecompany->idprof3))
415
    		{
416
    			$tmp=$outputlangs->transcountrynoentities("ProfId3",$sourcecompany->country_code);
417
    			if (preg_match('/\((.+)\)/',$tmp,$reg)) $tmp=$reg[1];
418
    			$stringaddress.=($stringaddress ? "\n" : '' ).$tmp.': '.$outputlangs->convToOutputCharset($sourcecompany->idprof3);
419
    		}
420
    		if (! empty($conf->global->MAIN_PROFID4_IN_SOURCE_ADDRESS) && ! empty($sourcecompany->idprof4))
421
    		{
422
    			$tmp=$outputlangs->transcountrynoentities("ProfId4",$sourcecompany->country_code);
423
    			if (preg_match('/\((.+)\)/',$tmp,$reg)) $tmp=$reg[1];
424
    			$stringaddress.=($stringaddress ? "\n" : '' ).$tmp.': '.$outputlangs->convToOutputCharset($sourcecompany->idprof4);
425
    		}
426
    		if (! empty($conf->global->MAIN_PROFID5_IN_SOURCE_ADDRESS) && ! empty($sourcecompany->idprof5))
427
    		{
428
    			$tmp=$outputlangs->transcountrynoentities("ProfId5",$sourcecompany->country_code);
429
    			if (preg_match('/\((.+)\)/',$tmp,$reg)) $tmp=$reg[1];
430
    			$stringaddress.=($stringaddress ? "\n" : '' ).$tmp.': '.$outputlangs->convToOutputCharset($sourcecompany->idprof5);
431
    		}
432
    		if (! empty($conf->global->MAIN_PROFID6_IN_SOURCE_ADDRESS) && ! empty($sourcecompany->idprof6))
433
    		{
434
    			$tmp=$outputlangs->transcountrynoentities("ProfId6",$sourcecompany->country_code);
435
    			if (preg_match('/\((.+)\)/',$tmp,$reg)) $tmp=$reg[1];
436
    			$stringaddress.=($stringaddress ? "\n" : '' ).$tmp.': '.$outputlangs->convToOutputCharset($sourcecompany->idprof6);
437
    		}
438
    	}
439
440
    	if ($mode == 'target' || preg_match('/targetwithdetails/',$mode))
441
    	{
442
    		if ($usecontact)
443
    		{
444
    			$stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->convToOutputCharset($targetcontact->getFullName($outputlangs,1));
445
446
    			if (!empty($targetcontact->address)) {
447
    				$stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->convToOutputCharset(dol_format_address($targetcontact));
448
    			} else {
449
    				$companytouseforaddress = $targetcompany;
450
451
					// Contact on a thirdparty that is a different thirdparty than the thirdparty of object
452
					if ($targetcontact->socid > 0 && $targetcontact->socid != $targetcompany->id)
453
					{
454
						$targetcontact->fetch_thirdparty();
455
						$companytouseforaddress = $targetcontact->thirdparty;
456
					}
457
458
					$stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->convToOutputCharset(dol_format_address($companytouseforaddress));
459
				}
460
    			// Country
461
    			if (!empty($targetcontact->country_code) && $targetcontact->country_code != $sourcecompany->country_code) {
462
    				$stringaddress.= ($stringaddress ? "\n" : '' ).$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$targetcontact->country_code));
463
    			}
464
    			else if (empty($targetcontact->country_code) && !empty($targetcompany->country_code) && ($targetcompany->country_code != $sourcecompany->country_code)) {
465
    				$stringaddress.= ($stringaddress ? "\n" : '' ).$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$targetcompany->country_code));
466
    			}
467
468
    			if (! empty($conf->global->MAIN_PDF_ADDALSOTARGETDETAILS) || preg_match('/targetwithdetails/',$mode))
469
    			{
470
    				// Phone
471
    			    if (! empty($conf->global->MAIN_PDF_ADDALSOTARGETDETAILS) || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_phone/',$mode))
472
    			    {
473
        				if (! empty($targetcontact->phone_pro) || ! empty($targetcontact->phone_mobile)) $stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("Phone").": ";
474
        				if (! empty($targetcontact->phone_pro)) $stringaddress .= $outputlangs->convToOutputCharset($targetcontact->phone_pro);
475
        				if (! empty($targetcontact->phone_pro) && ! empty($targetcontact->phone_mobile)) $stringaddress .= " / ";
476
        				if (! empty($targetcontact->phone_mobile)) $stringaddress .= $outputlangs->convToOutputCharset($targetcontact->phone_mobile);
477
    			    }
478
    				// Fax
479
    			    if (! empty($conf->global->MAIN_PDF_ADDALSOTARGETDETAILS) || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_fax/',$mode))
480
    			    {
481
                        if ($targetcontact->fax) $stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("Fax").": ".$outputlangs->convToOutputCharset($targetcontact->fax);
482
    			    }
483
    				// EMail
484
    			    if (! empty($conf->global->MAIN_PDF_ADDALSOTARGETDETAILS) || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_email/',$mode))
485
    			    {
486
                        if ($targetcontact->email) $stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("Email").": ".$outputlangs->convToOutputCharset($targetcontact->email);
487
    			    }
488
    				// Web
489
    			    if (! empty($conf->global->MAIN_PDF_ADDALSOTARGETDETAILS) || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_url/',$mode))
490
    			    {
491
                        if ($targetcontact->url) $stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("Web").": ".$outputlangs->convToOutputCharset($targetcontact->url);
492
    			    }
493
    			}
494
    		}
495
    		else
496
    		{
497
    			$stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->convToOutputCharset(dol_format_address($targetcompany));
498
    			// Country
499
    			if (!empty($targetcompany->country_code) && $targetcompany->country_code != $sourcecompany->country_code) $stringaddress.=($stringaddress ? "\n" : '' ).$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$targetcompany->country_code));
500
501
    			if (! empty($conf->global->MAIN_PDF_ADDALSOTARGETDETAILS) || preg_match('/targetwithdetails/',$mode))
502
    			{
503
    				// Phone
504
    			    if (! empty($conf->global->MAIN_PDF_ADDALSOTARGETDETAILS) || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_phone/',$mode))
505
    			    {
506
    			    	if (! empty($targetcompany->phone) || ! empty($targetcompany->phone_mobile)) $stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("Phone").": ";
507
	    				if (! empty($targetcompany->phone)) $stringaddress .= $outputlangs->convToOutputCharset($targetcompany->phone);
508
    					if (! empty($targetcompany->phone) && ! empty($targetcompany->phone_mobile)) $stringaddress .= " / ";
509
    					if (! empty($targetcompany->phone_mobile)) $stringaddress .= $outputlangs->convToOutputCharset($targetcompany->phone_mobile);
510
    			    }
511
    				// Fax
512
    			    if (! empty($conf->global->MAIN_PDF_ADDALSOTARGETDETAILS) || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_fax/',$mode))
513
    			    {
514
    			    	if ($targetcompany->fax) $stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("Fax").": ".$outputlangs->convToOutputCharset($targetcompany->fax);
515
    			    }
516
    				// EMail
517
    			    if (! empty($conf->global->MAIN_PDF_ADDALSOTARGETDETAILS) || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_email/',$mode))
518
    			    {
519
    			    	if ($targetcompany->email) $stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("Email").": ".$outputlangs->convToOutputCharset($targetcompany->email);
520
    			    }
521
    				// Web
522
    			    if (! empty($conf->global->MAIN_PDF_ADDALSOTARGETDETAILS) || $mode == 'targetwithdetails' || preg_match('/targetwithdetails_url/',$mode))
523
    			    {
524
    			    	if ($targetcompany->url) $stringaddress .= ($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("Web").": ".$outputlangs->convToOutputCharset($targetcompany->url);
525
    			    }
526
    			}
527
    		}
528
529
    		// Intra VAT
530
    		if (empty($conf->global->MAIN_TVAINTRA_NOT_IN_ADDRESS))
531
    		{
532
    			if ($targetcompany->tva_intra) $stringaddress.=($stringaddress ? "\n" : '' ).$outputlangs->transnoentities("VATIntraShort").': '.$outputlangs->convToOutputCharset($targetcompany->tva_intra);
533
    		}
534
535
    		// Professionnal Ids
536
    		if (! empty($conf->global->MAIN_PROFID1_IN_ADDRESS) && ! empty($targetcompany->idprof1))
537
    		{
538
    			$tmp=$outputlangs->transcountrynoentities("ProfId1",$targetcompany->country_code);
539
    			if (preg_match('/\((.+)\)/',$tmp,$reg)) $tmp=$reg[1];
540
    			$stringaddress.=($stringaddress ? "\n" : '' ).$tmp.': '.$outputlangs->convToOutputCharset($targetcompany->idprof1);
541
    		}
542
    		if (! empty($conf->global->MAIN_PROFID2_IN_ADDRESS) && ! empty($targetcompany->idprof2))
543
    		{
544
    			$tmp=$outputlangs->transcountrynoentities("ProfId2",$targetcompany->country_code);
545
    			if (preg_match('/\((.+)\)/',$tmp,$reg)) $tmp=$reg[1];
546
    			$stringaddress.=($stringaddress ? "\n" : '' ).$tmp.': '.$outputlangs->convToOutputCharset($targetcompany->idprof2);
547
    		}
548
    		if (! empty($conf->global->MAIN_PROFID3_IN_ADDRESS) && ! empty($targetcompany->idprof3))
549
    		{
550
    			$tmp=$outputlangs->transcountrynoentities("ProfId3",$targetcompany->country_code);
551
    			if (preg_match('/\((.+)\)/',$tmp,$reg)) $tmp=$reg[1];
552
    			$stringaddress.=($stringaddress ? "\n" : '' ).$tmp.': '.$outputlangs->convToOutputCharset($targetcompany->idprof3);
553
    		}
554
    		if (! empty($conf->global->MAIN_PROFID4_IN_ADDRESS) && ! empty($targetcompany->idprof4))
555
    		{
556
    			$tmp=$outputlangs->transcountrynoentities("ProfId4",$targetcompany->country_code);
557
    			if (preg_match('/\((.+)\)/',$tmp,$reg)) $tmp=$reg[1];
558
    			$stringaddress.=($stringaddress ? "\n" : '' ).$tmp.': '.$outputlangs->convToOutputCharset($targetcompany->idprof4);
559
    		}
560
    		if (! empty($conf->global->MAIN_PROFID5_IN_ADDRESS) && ! empty($targetcompany->idprof5))
561
    		{
562
    		    $tmp=$outputlangs->transcountrynoentities("ProfId5",$targetcompany->country_code);
563
    		    if (preg_match('/\((.+)\)/',$tmp,$reg)) $tmp=$reg[1];
564
    		    $stringaddress.=($stringaddress ? "\n" : '' ).$tmp.': '.$outputlangs->convToOutputCharset($targetcompany->idprof5);
565
    		}
566
    		if (! empty($conf->global->MAIN_PROFID6_IN_ADDRESS) && ! empty($targetcompany->idprof6))
567
    		{
568
    		    $tmp=$outputlangs->transcountrynoentities("ProfId6",$targetcompany->country_code);
569
    		    if (preg_match('/\((.+)\)/',$tmp,$reg)) $tmp=$reg[1];
570
    		    $stringaddress.=($stringaddress ? "\n" : '' ).$tmp.': '.$outputlangs->convToOutputCharset($targetcompany->idprof6);
571
    		}
572
573
    		// Public note
574
    		if (! empty($conf->global->MAIN_PUBLIC_NOTE_IN_ADDRESS))
575
    		{
576
    		    if ($mode == 'source' && ! empty($sourcecompany->note_public))
577
        		{
578
        		    $stringaddress.=($stringaddress ? "\n" : '' ).dol_string_nohtmltag($sourcecompany->note_public);
579
        		}
580
        		if (($mode == 'target' || preg_match('/targetwithdetails/',$mode)) && ! empty($targetcompany->note_public))
581
        		{
582
        		    $stringaddress.=($stringaddress ? "\n" : '' ).dol_string_nohtmltag($targetcompany->note_public);
583
        		}
584
    		}
585
    	}
586
	}
587
588
	return $stringaddress;
589
}
590
591
592
/**
593
 *   	Show header of page for PDF generation
594
 *
595
 *   	@param      TCPDF			$pdf     		Object PDF
596
 *      @param      Translate	$outputlangs	Object lang for output
597
 * 		@param		int			$page_height	Height of page
598
 *      @return	void
599
 */
600
function pdf_pagehead(&$pdf,$outputlangs,$page_height)
601
{
602
	global $conf;
603
604
	// Add a background image on document
605
	if (! empty($conf->global->MAIN_USE_BACKGROUND_ON_PDF))		// Warning, this option make TCPDF generation being crazy and some content disappeared behind the image
606
	{
607
		$pdf->SetAutoPageBreak(0,0);	// Disable auto pagebreak before adding image
608
		$pdf->Image($conf->mycompany->dir_output.'/logos/'.$conf->global->MAIN_USE_BACKGROUND_ON_PDF, (isset($conf->global->MAIN_USE_BACKGROUND_ON_PDF_X)?$conf->global->MAIN_USE_BACKGROUND_ON_PDF_X:0), (isset($conf->global->MAIN_USE_BACKGROUND_ON_PDF_Y)?$conf->global->MAIN_USE_BACKGROUND_ON_PDF_Y:0), 0, $page_height);
609
		$pdf->SetAutoPageBreak(1,0);	// Restore pagebreak
610
	}
611
}
612
613
614
/**
615
 *	Return array of possible substitutions for PDF content (without external module substitutions).
616
 *
617
 *	@param	Translate	$outputlangs	Output language
618
 *	@param	array       $exclude        Array of family keys we want to exclude. For example array('mycompany', 'object', 'date', 'user', ...)
619
 *	@param	Object      $object         Object
620
 *	@param	int         $onlykey       1=Do not calculate some heavy values of keys (performance enhancement when we need only the keys), 2=Values are truncated and html sanitized (to use for help tooltip)
621
 *	@return	array						Array of substitutions
622
 */
623
function pdf_getSubstitutionArray($outputlangs, $exclude=null, $object=null, $onlykey=0)
624
{
625
    $substitutionarray = getCommonSubstitutionArray($outputlangs, $onlykey, $exclude, $object);
626
    $substitutionarray['__FROM_NAME__']='__FROM_NAME__';
627
    $substitutionarray['__FROM_EMAIL__']='__FROM_EMAIL__';
628
    return $substitutionarray;
629
}
630
631
632
/**
633
 *      Add a draft watermark on PDF files
634
 *
635
 *      @param	TCPDF      	$pdf            Object PDF
636
 *      @param  Translate	$outputlangs	Object lang
637
 *      @param  int		    $h		        Height of PDF
638
 *      @param  int		    $w		        Width of PDF
639
 *      @param  string	    $unit           Unit of height (mm, pt, ...)
640
 *      @param  string		$text           Text to show
641
 *      @return	void
642
 */
643
function pdf_watermark(&$pdf, $outputlangs, $h, $w, $unit, $text)
644
{
645
	global $langs, $mysoc, $user;
646
647
	// Print Draft Watermark
648
	if ($unit=='pt') $k=1;
649
	elseif ($unit=='mm') $k=72/25.4;
650
	elseif ($unit=='cm') $k=72/2.54;
651
	elseif ($unit=='in') $k=72;
652
653
	// Make substitution
654
	$substitutionarray=pdf_getSubstitutionArray($outputlangs, null, null);
655
	complete_substitutions_array($substitutionarray, $outputlangs, null);
656
	$text=make_substitutions($text, $substitutionarray, $outputlangs);
657
	$text=$outputlangs->convToOutputCharset($text);
658
659
	$savx=$pdf->getX(); $savy=$pdf->getY();
660
661
	$watermark_angle=atan($h/$w)/2;
662
	$watermark_x_pos=0;
663
	$watermark_y_pos=$h/3;
664
	$watermark_x=$w/2;
665
	$watermark_y=$h/3;
666
	$pdf->SetFont('','B',40);
667
	$pdf->SetTextColor(255,192,203);
668
	//rotate
669
	$pdf->_out(sprintf('q %.5F %.5F %.5F %.5F %.2F %.2F cm 1 0 0 1 %.2F %.2F cm',cos($watermark_angle),sin($watermark_angle),-sin($watermark_angle),cos($watermark_angle),$watermark_x*$k,($h-$watermark_y)*$k,-$watermark_x*$k,-($h-$watermark_y)*$k));
670
	//print watermark
671
	$pdf->SetXY($watermark_x_pos,$watermark_y_pos);
672
	$pdf->Cell($w-20,25,$outputlangs->convToOutputCharset($text),"",2,"C",0);
673
	//antirotate
674
	$pdf->_out('Q');
675
676
	$pdf->SetXY($savx,$savy);
677
}
678
679
680
/**
681
 *  Show bank informations for PDF generation
682
 *
683
 *  @param	TCPDF			$pdf            		Object PDF
684
 *  @param  Translate	$outputlangs     		Object lang
685
 *  @param  int			$curx            		X
686
 *  @param  int			$cury            		Y
687
 *  @param  Account		$account         		Bank account object
688
 *  @param  int			$onlynumber      		Output only number (bank+desk+key+number according to country, but without name of bank and domiciliation)
689
 *  @param	int			$default_font_size		Default font size
690
 *  @return	float                               The Y PDF position
691
 */
692
function pdf_bank(&$pdf,$outputlangs,$curx,$cury,$account,$onlynumber=0,$default_font_size=10)
693
{
694
	global $mysoc, $conf;
695
696
	require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbank.class.php';
697
698
	$diffsizetitle=(empty($conf->global->PDF_DIFFSIZE_TITLE)?3:$conf->global->PDF_DIFFSIZE_TITLE);
699
	$diffsizecontent=(empty($conf->global->PDF_DIFFSIZE_CONTENT)?4:$conf->global->PDF_DIFFSIZE_CONTENT);
700
	$pdf->SetXY($curx, $cury);
701
702
	if (empty($onlynumber))
703
	{
704
		$pdf->SetFont('','B',$default_font_size - $diffsizetitle);
705
		$pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByTransferOnThisBankAccount').':', 0, 'L', 0);
706
		$cury+=4;
707
	}
708
709
	$outputlangs->load("banks");
710
711
	// Use correct name of bank id according to country
712
	$bickey="BICNumber";
713
	if ($account->getCountryCode() == 'IN') $bickey="SWIFT";
714
715
	// Get format of bank account according to its country
716
	$usedetailedbban=$account->useDetailedBBAN();
717
718
	//$onlynumber=0; $usedetailedbban=1; // For tests
719
	if ($usedetailedbban)
720
	{
721
		$savcurx=$curx;
722
723
		if (empty($onlynumber))
724
		{
725
			$pdf->SetFont('','',$default_font_size - $diffsizecontent);
726
			$pdf->SetXY($curx, $cury);
727
			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("Bank").': ' . $outputlangs->convToOutputCharset($account->bank), 0, 'L', 0);
728
			$cury+=3;
729
		}
730
731
		if (empty($conf->global->PDF_BANK_HIDE_NUMBER_SHOW_ONLY_BICIBAN))    // Note that some countries still need bank number, BIC/IBAN not enougth for them
732
		{
733
		    // Note:
734
		    // bank = code_banque (FR), sort code (GB, IR. Example: 12-34-56)
735
		    // desk = code guichet (FR), used only when $usedetailedbban = 1
736
		    // number = account number
737
		    // key = check control key used only when $usedetailedbban = 1
738
    		if (empty($onlynumber)) $pdf->line($curx+1, $cury+1, $curx+1, $cury+6);
739
740
741
			foreach ($account->getFieldsToShow() as $val)
742
			{
743
				$pdf->SetXY($curx, $cury+4);
744
				$pdf->SetFont('','',$default_font_size - 3);
745
746
				if ($val == 'BankCode') {
747
					// Bank code
748
					$tmplength = 18;
749
					$content = $account->code_banque;
750
				} elseif ($val == 'DeskCode') {
751
					// Desk
752
					$tmplength = 18;
753
					$content = $account->code_guichet;
754
				} elseif ($val == 'BankAccountNumber') {
755
					// Number
756
					$tmplength = 24;
757
					$content = $account->number;
758
				} elseif ($val == 'BankAccountNumberKey') {
759
					// Key
760
					$tmplength = 15;
761
					$content = $account->cle_rib;
762
				}elseif ($val == 'IBAN' || $val == 'BIC') {
763
					// Key
764
					$tmplength = 0;
765
					$content = '';
766
				} else {
767
					dol_print_error($account->db, 'Unexpected value for getFieldsToShow: '.$val);
768
					break;
769
				}
770
771
				$pdf->MultiCell($tmplength, 3, $outputlangs->convToOutputCharset($content), 0, 'C', 0);
772
				$pdf->SetXY($curx, $cury + 1);
773
				$curx += $tmplength;
774
				$pdf->SetFont('', 'B', $default_font_size - $diffsizecontent);
775
				$pdf->MultiCell($tmplength, 3, $outputlangs->transnoentities($val), 0, 'C', 0);
776
				if (empty($onlynumber)) {
777
					$pdf->line($curx, $cury + 1, $curx, $cury + 7);
778
				}
779
    		}
780
781
    		$curx=$savcurx;
782
    		$cury+=8;
783
		}
784
	}
785
	else
786
	{
787
		$pdf->SetFont('','B',$default_font_size - $diffsizecontent);
788
		$pdf->SetXY($curx, $cury);
789
		$pdf->MultiCell(100, 3, $outputlangs->transnoentities("Bank").': ' . $outputlangs->convToOutputCharset($account->bank), 0, 'L', 0);
790
		$cury+=3;
791
792
		$pdf->SetFont('','B',$default_font_size - $diffsizecontent);
793
		$pdf->SetXY($curx, $cury);
794
		$pdf->MultiCell(100, 3, $outputlangs->transnoentities("BankAccountNumber").': ' . $outputlangs->convToOutputCharset($account->number), 0, 'L', 0);
795
		$cury+=3;
796
797
		if ($diffsizecontent <= 2) $cury+=1;
798
	}
799
800
	$pdf->SetFont('','',$default_font_size - $diffsizecontent);
801
802
	if (empty($onlynumber) && ! empty($account->domiciliation))
803
	{
804
		$pdf->SetXY($curx, $cury);
805
		$val=$outputlangs->transnoentities("Residence").': ' . $outputlangs->convToOutputCharset($account->domiciliation);
806
		$pdf->MultiCell(100, 3, $val, 0, 'L', 0);
807
		//$nboflines=dol_nboflines_bis($val,120);
808
		//$cury+=($nboflines*3)+2;
809
		$tmpy=$pdf->getStringHeight(100, $val);
810
		$cury+=$tmpy;
811
	}
812
813
	if (! empty($account->proprio))
814
	{
815
		$pdf->SetXY($curx, $cury);
816
		$val=$outputlangs->transnoentities("BankAccountOwner").': ' . $outputlangs->convToOutputCharset($account->proprio);
817
		$pdf->MultiCell(100, 3, $val, 0, 'L', 0);
818
		$tmpy=$pdf->getStringHeight(100, $val);
819
		$cury+=$tmpy;
820
		$cur+=1;
821
	}
822
823
	else if (! $usedetailedbban) $cury+=1;
824
825
	// Use correct name of bank id according to country
826
	$ibankey = FormBank::getIBANLabel($account);
827
828
	if (! empty($account->iban))
829
	{
830
		//Remove whitespaces to ensure we are dealing with the format we expect
831
		$ibanDisplay_temp = str_replace(' ', '', $outputlangs->convToOutputCharset($account->iban));
832
		$ibanDisplay = "";
833
834
		$nbIbanDisplay_temp = dol_strlen($ibanDisplay_temp);
835
		for ($i = 0; $i < $nbIbanDisplay_temp; $i++)
836
		{
837
			$ibanDisplay .= $ibanDisplay_temp[$i];
838
			if($i%4 == 3 && $i > 0)	$ibanDisplay .= " ";
839
		}
840
841
		$pdf->SetFont('','B',$default_font_size - 3);
842
		$pdf->SetXY($curx, $cury);
843
		$pdf->MultiCell(100, 3, $outputlangs->transnoentities($ibankey).': ' . $ibanDisplay, 0, 'L', 0);
844
		$cury+=3;
845
	}
846
847
	if (! empty($account->bic))
848
	{
849
		$pdf->SetFont('','B',$default_font_size - 3);
850
		$pdf->SetXY($curx, $cury);
851
		$pdf->MultiCell(100, 3, $outputlangs->transnoentities($bickey).': ' . $outputlangs->convToOutputCharset($account->bic), 0, 'L', 0);
852
	}
853
854
	return $pdf->getY();
855
}
856
857
/**
858
 *  Show footer of page for PDF generation
859
 *
860
 *	@param	TCPDF			$pdf     		The PDF factory
861
 *  @param  Translate	$outputlangs	Object lang for output
862
 * 	@param	string		$paramfreetext	Constant name of free text
863
 * 	@param	Societe		$fromcompany	Object company
864
 * 	@param	int			$marge_basse	Margin bottom we use for the autobreak
865
 * 	@param	int			$marge_gauche	Margin left (no more used)
866
 * 	@param	int			$page_hauteur	Page height (no more used)
867
 * 	@param	Object		$object			Object shown in PDF
868
 * 	@param	int			$showdetails	Show company adress details into footer (0=Nothing, 1=Show address, 2=Show managers, 3=Both)
869
 *  @param	int			$hidefreetext	1=Hide free text, 0=Show free text
870
 * 	@return	int							Return height of bottom margin including footer text
871
 */
872
function pdf_pagefoot(&$pdf,$outputlangs,$paramfreetext,$fromcompany,$marge_basse,$marge_gauche,$page_hauteur,$object,$showdetails=0,$hidefreetext=0)
873
{
874
	global $conf,$user,$mysoc;
875
876
	$outputlangs->load("dict");
877
	$line='';
878
879
	$dims=$pdf->getPageDimensions();
880
881
	// Line of free text
882
	if (empty($hidefreetext) && ! empty($conf->global->$paramfreetext))
883
	{
884
		$substitutionarray=pdf_getSubstitutionArray($outputlangs, null, $object);
885
		// More substitution keys
886
		$substitutionarray['__FROM_NAME__']=$fromcompany->name;
887
		$substitutionarray['__FROM_EMAIL__']=$fromcompany->email;
888
		complete_substitutions_array($substitutionarray, $outputlangs, $object);
889
		$newfreetext=make_substitutions($conf->global->$paramfreetext, $substitutionarray, $outputlangs);
890
891
		// Make a change into HTML code to allow to include images from medias directory.
892
		// <img alt="" src="/dolibarr_dev/htdocs/viewimage.php?modulepart=medias&amp;entity=1&amp;file=image/ldestailleur_166x166.jpg" style="height:166px; width:166px" />
893
		// become
894
		// <img alt="" src="'.DOL_DATA_ROOT.'/medias/image/ldestailleur_166x166.jpg" style="height:166px; width:166px" />
895
		$newfreetext=preg_replace('/(<img.*src=")[^\"]*viewimage\.php[^\"]*modulepart=medias[^\"]*file=([^\"]*)("[^\/]*\/>)/', '\1'.DOL_DATA_ROOT.'/medias/\2\3', $newfreetext);
896
897
		$line.=$outputlangs->convToOutputCharset($newfreetext);
898
	}
899
900
	// First line of company infos
901
	$line1=""; $line2=""; $line3=""; $line4="";
902
903
		if ($showdetails == 1 || $showdetails == 3)
904
	{
905
		// Company name
906
		if ($fromcompany->name)
907
		{
908
			$line1.=($line1?" - ":"").$outputlangs->transnoentities("RegisteredOffice").": ".$fromcompany->name;
909
		}
910
		// Address
911
		if ($fromcompany->address)
912
		{
913
			$line1.=($line1?" - ":"").str_replace("\n", ", ", $fromcompany->address);
914
		}
915
		// Zip code
916
		if ($fromcompany->zip)
917
		{
918
			$line1.=($line1?" - ":"").$fromcompany->zip;
919
		}
920
		// Town
921
		if ($fromcompany->town)
922
		{
923
			$line1.=($line1?" ":"").$fromcompany->town;
924
		}
925
		// Phone
926
		if ($fromcompany->phone)
927
		{
928
			$line2.=($line2?" - ":"").$outputlangs->transnoentities("Phone").": ".$fromcompany->phone;
929
		}
930
		// Fax
931
		if ($fromcompany->fax)
932
		{
933
			$line2.=($line2?" - ":"").$outputlangs->transnoentities("Fax").": ".$fromcompany->fax;
934
		}
935
936
		// URL
937
		if ($fromcompany->url)
938
		{
939
			$line2.=($line2?" - ":"").$fromcompany->url;
940
		}
941
		// Email
942
		if ($fromcompany->email)
943
		{
944
			$line2.=($line2?" - ":"").$fromcompany->email;
945
		}
946
	}
947
	if ($showdetails == 2 || $showdetails == 3 || ($fromcompany->country_code == 'DE'))
948
	{
949
		// Managers
950
		if ($fromcompany->managers)
951
		{
952
			$line2.=($line2?" - ":"").$fromcompany->managers;
953
		}
954
	}
955
956
	// Line 3 of company infos
957
	// Juridical status
958
	if ($fromcompany->forme_juridique_code)
959
	{
960
		$line3.=($line3?" - ":"").$outputlangs->convToOutputCharset(getFormeJuridiqueLabel($fromcompany->forme_juridique_code));
961
	}
962
	// Capital
963
	if ($fromcompany->capital)
964
	{
965
		$tmpamounttoshow = price2num($fromcompany->capital); // This field is a free string
966
		if (is_numeric($tmpamounttoshow) && $tmpamounttoshow > 0) $line3.=($line3?" - ":"").$outputlangs->transnoentities("CapitalOf",price($tmpamounttoshow, 0, $outputlangs, 0, 0, 0, $conf->currency));
967
		else $line3.=($line3?" - ":"").$outputlangs->transnoentities("CapitalOf",$tmpamounttoshow,$outputlangs);
968
	}
969
	// Prof Id 1
970
	if ($fromcompany->idprof1 && ($fromcompany->country_code != 'FR' || ! $fromcompany->idprof2))
971
	{
972
		$field=$outputlangs->transcountrynoentities("ProfId1",$fromcompany->country_code);
973
		if (preg_match('/\((.*)\)/i',$field,$reg)) $field=$reg[1];
974
		$line3.=($line3?" - ":"").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof1);
975
	}
976
	// Prof Id 2
977
	if ($fromcompany->idprof2)
978
	{
979
		$field=$outputlangs->transcountrynoentities("ProfId2",$fromcompany->country_code);
980
		if (preg_match('/\((.*)\)/i',$field,$reg)) $field=$reg[1];
981
		$line3.=($line3?" - ":"").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof2);
982
	}
983
984
	// Line 4 of company infos
985
	// Prof Id 3
986
	if ($fromcompany->idprof3)
987
	{
988
		$field=$outputlangs->transcountrynoentities("ProfId3",$fromcompany->country_code);
989
		if (preg_match('/\((.*)\)/i',$field,$reg)) $field=$reg[1];
990
		$line4.=($line4?" - ":"").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof3);
991
	}
992
	// Prof Id 4
993
	if ($fromcompany->idprof4)
994
	{
995
		$field=$outputlangs->transcountrynoentities("ProfId4",$fromcompany->country_code);
996
		if (preg_match('/\((.*)\)/i',$field,$reg)) $field=$reg[1];
997
		$line4.=($line4?" - ":"").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof4);
998
	}
999
	// Prof Id 5
1000
	if ($fromcompany->idprof5)
1001
	{
1002
		$field=$outputlangs->transcountrynoentities("ProfId5",$fromcompany->country_code);
1003
		if (preg_match('/\((.*)\)/i',$field,$reg)) $field=$reg[1];
1004
		$line4.=($line4?" - ":"").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof5);
1005
	}
1006
	// Prof Id 6
1007
	if ($fromcompany->idprof6)
1008
	{
1009
		$field=$outputlangs->transcountrynoentities("ProfId6",$fromcompany->country_code);
1010
		if (preg_match('/\((.*)\)/i',$field,$reg)) $field=$reg[1];
1011
		$line4.=($line4?" - ":"").$field.": ".$outputlangs->convToOutputCharset($fromcompany->idprof6);
1012
	}
1013
	// IntraCommunautary VAT
1014
	if ($fromcompany->tva_intra != '')
1015
	{
1016
		$line4.=($line4?" - ":"").$outputlangs->transnoentities("VATIntraShort").": ".$outputlangs->convToOutputCharset($fromcompany->tva_intra);
1017
	}
1018
1019
	$pdf->SetFont('','',7);
1020
	$pdf->SetDrawColor(224,224,224);
1021
1022
	// The start of the bottom of this page footer is positioned according to # of lines
1023
	$freetextheight=0;
1024
	if ($line)	// Free text
1025
	{
1026
		//$line="sample text<br>\nfd<strong>sf</strong>sdf<br>\nghfghg<br>";
1027
	    if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT))
1028
		{
1029
			$width=20000; $align='L';	// By default, ask a manual break: We use a large value 20000, to not have automatic wrap. This make user understand, he need to add CR on its text.
1030
    		if (! empty($conf->global->MAIN_USE_AUTOWRAP_ON_FREETEXT)) {
1031
    			$width=200; $align='C';
1032
    		}
1033
		    $freetextheight=$pdf->getStringHeight($width,$line);
1034
		}
1035
		else
1036
		{
1037
            $freetextheight=pdfGetHeightForHtmlContent($pdf,dol_htmlentitiesbr($line, 1, 'UTF-8', 0));      // New method (works for HTML content)
1038
            //print '<br>'.$freetextheight;exit;
1039
		}
1040
	}
1041
1042
	$marginwithfooter=$marge_basse + $freetextheight + (! empty($line1)?3:0) + (! empty($line2)?3:0) + (! empty($line3)?3:0) + (! empty($line4)?3:0);
1043
	$posy=$marginwithfooter+0;
1044
1045
	if ($line)	// Free text
1046
	{
1047
		$pdf->SetXY($dims['lm'],-$posy);
1048
		if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT))   // by default
1049
		{
1050
            $pdf->MultiCell(0, 3, $line, 0, $align, 0);
1051
		}
1052
		else
1053
		{
1054
            $pdf->writeHTMLCell($pdf->page_largeur - $pdf->margin_left - $pdf->margin_right, $freetextheight, $dims['lm'], $dims['hk']-$marginwithfooter, dol_htmlentitiesbr($line, 1, 'UTF-8', 0));
1055
		}
1056
		$posy-=$freetextheight;
1057
	}
1058
1059
	$pdf->SetY(-$posy);
1060
	$pdf->line($dims['lm'], $dims['hk']-$posy, $dims['wk']-$dims['rm'], $dims['hk']-$posy);
1061
	$posy--;
1062
1063
	if (! empty($line1))
1064
	{
1065
		$pdf->SetFont('','B',7);
1066
		$pdf->SetXY($dims['lm'],-$posy);
1067
		$pdf->MultiCell($dims['wk']-$dims['rm']-$dims['lm'], 2, $line1, 0, 'C', 0);
1068
		$posy-=3;
1069
		$pdf->SetFont('','',7);
1070
	}
1071
1072
	if (! empty($line2))
1073
	{
1074
		$pdf->SetFont('','B',7);
1075
		$pdf->SetXY($dims['lm'],-$posy);
1076
		$pdf->MultiCell($dims['wk']-$dims['rm']-$dims['lm'], 2, $line2, 0, 'C', 0);
1077
		$posy-=3;
1078
		$pdf->SetFont('','',7);
1079
	}
1080
1081
	if (! empty($line3))
1082
	{
1083
		$pdf->SetXY($dims['lm'],-$posy);
1084
		$pdf->MultiCell($dims['wk']-$dims['rm']-$dims['lm'], 2, $line3, 0, 'C', 0);
1085
	}
1086
1087
	if (! empty($line4))
1088
	{
1089
		$posy-=3;
1090
		$pdf->SetXY($dims['lm'],-$posy);
1091
		$pdf->MultiCell($dims['wk']-$dims['rm']-$dims['lm'], 2, $line4, 0, 'C', 0);
1092
	}
1093
1094
	// Show page nb only on iso languages (so default Helvetica font)
1095
	if (strtolower(pdf_getPDFFont($outputlangs)) == 'helvetica')
1096
	{
1097
		$pdf->SetXY($dims['wk']-$dims['rm']-15, -$posy);
1098
		//print 'xxx'.$pdf->PageNo().'-'.$pdf->getAliasNbPages().'-'.$pdf->getAliasNumPage();exit;
1099
		$pdf->MultiCell(15, 2, $pdf->PageNo().'/'.$pdf->getAliasNbPages(), 0, 'R', 0);
1100
	}
1101
1102
	return $marginwithfooter;
1103
}
1104
1105
/**
1106
 *	Show linked objects for PDF generation
1107
 *
1108
 *	@param	TCPDF			$pdf				Object PDF
1109
 *	@param	object		$object				Object
1110
 *	@param  Translate	$outputlangs		Object lang
1111
 *	@param  int			$posx				X
1112
 *	@param  int			$posy				Y
1113
 *	@param	float		$w					Width of cells. If 0, they extend up to the right margin of the page.
1114
 *	@param	float		$h					Cell minimum height. The cell extends automatically if needed.
1115
 *	@param	int			$align				Align
1116
 *	@param	string		$default_font_size	Font size
1117
 *	@return	float                           The Y PDF position
1118
 */
1119
function pdf_writeLinkedObjects(&$pdf,$object,$outputlangs,$posx,$posy,$w,$h,$align,$default_font_size)
1120
{
1121
	$linkedobjects = pdf_getLinkedObjects($object,$outputlangs);
1122
	if (! empty($linkedobjects))
1123
	{
1124
		foreach($linkedobjects as $linkedobject)
1125
		{
1126
		    $reftoshow = $linkedobject["ref_title"].' : '.$linkedobject["ref_value"];
1127
		    if (! empty($linkedobject["date_value"]))
1128
		    {
1129
		        $reftoshow .= ' / '.$linkedobject["date_value"];
1130
		    }
1131
1132
			$posy+=3;
1133
			$pdf->SetXY($posx,$posy);
1134
			$pdf->SetFont('','', $default_font_size - 2);
1135
			$pdf->MultiCell($w, $h, $reftoshow, '', $align);
1136
		}
1137
	}
1138
1139
	return $pdf->getY();
1140
}
1141
1142
/**
1143
 *	Output line description into PDF
1144
 *
1145
 *  @param  TCPDF				$pdf               PDF object
1146
 *	@param	Object			$object				Object
1147
 *	@param	int				$i					Current line number
1148
 *  @param  Translate		$outputlangs		Object lang for output
1149
 *  @param  int				$w					Width
1150
 *  @param  int				$h					Height
1151
 *  @param  int				$posx				Pos x
1152
 *  @param  int				$posy				Pos y
1153
 *  @param  int				$hideref       		Hide reference
1154
 *  @param  int				$hidedesc           Hide description
1155
 * 	@param	int				$issupplierline		Is it a line for a supplier object ?
1156
 * 	@return	string
1157
 */
1158
function pdf_writelinedesc(&$pdf,$object,$i,$outputlangs,$w,$h,$posx,$posy,$hideref=0,$hidedesc=0,$issupplierline=0)
1159
{
1160
	global $db, $conf, $langs, $hookmanager;
1161
1162
	$reshook=0;
1163
	$result='';
1164
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1165
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1166
	{
1167
		$special_code = $object->lines[$i]->special_code;
1168
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1169
		$parameters = array('pdf'=>$pdf,'i'=>$i,'outputlangs'=>$outputlangs,'w'=>$w,'h'=>$h,'posx'=>$posx,'posy'=>$posy,'hideref'=>$hideref,'hidedesc'=>$hidedesc,'issupplierline'=>$issupplierline,'special_code'=>$special_code);
1170
		$action='';
1171
		$reshook=$hookmanager->executeHooks('pdf_writelinedesc',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1172
1173
		if (!empty($hookmanager->resPrint)) $result.=$hookmanager->resPrint;
1174
	}
1175
	if (empty($reshook))
1176
	{
1177
		$labelproductservice=pdf_getlinedesc($object,$i,$outputlangs,$hideref,$hidedesc,$issupplierline);
1178
		// Description
1179
		$pdf->writeHTMLCell($w, $h, $posx, $posy, $outputlangs->convToOutputCharset($labelproductservice), 0, 1, false, true, 'J',true);
1180
		$result.=$labelproductservice;
1181
	}
1182
	return $result;
1183
}
1184
1185
/**
1186
 *  Return line description translated in outputlangs and encoded into htmlentities and with <br>
1187
 *
1188
 *  @param  Object		$object              Object
1189
 *  @param  int			$i                   Current line number (0 = first line, 1 = second line, ...)
1190
 *  @param  Translate	$outputlangs         Object langs for output
1191
 *  @param  int			$hideref             Hide reference
1192
 *  @param  int			$hidedesc            Hide description
1193
 *  @param  int			$issupplierline      Is it a line for a supplier object ?
1194
 *  @return string       				     String with line
1195
 */
1196
function pdf_getlinedesc($object,$i,$outputlangs,$hideref=0,$hidedesc=0,$issupplierline=0)
1197
{
1198
	global $db, $conf, $langs;
1199
1200
	$idprod=(! empty($object->lines[$i]->fk_product)?$object->lines[$i]->fk_product:false);
1201
	$label=(! empty($object->lines[$i]->label)?$object->lines[$i]->label:(! empty($object->lines[$i]->product_label)?$object->lines[$i]->product_label:''));
1202
	$desc=(! empty($object->lines[$i]->desc)?$object->lines[$i]->desc:(! empty($object->lines[$i]->description)?$object->lines[$i]->description:''));
1203
	$ref_supplier=(! empty($object->lines[$i]->ref_supplier)?$object->lines[$i]->ref_supplier:(! empty($object->lines[$i]->ref_fourn)?$object->lines[$i]->ref_fourn:''));    // TODO Not yet saved for supplier invoices, only supplier orders
1204
	$note=(! empty($object->lines[$i]->note)?$object->lines[$i]->note:'');
1205
	$dbatch=(! empty($object->lines[$i]->detail_batch)?$object->lines[$i]->detail_batch:false);
1206
1207
	if ($issupplierline)
1208
	{
1209
		include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
1210
		$prodser = new ProductFournisseur($db);
1211
	}
1212
	else
1213
	{
1214
		include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1215
		$prodser = new Product($db);
1216
	}
1217
1218
	if ($idprod)
1219
	{
1220
		$prodser->fetch($idprod);
1221
		// If a predefined product and multilang and on other lang, we renamed label with label translated
1222
		if (! empty($conf->global->MAIN_MULTILANGS) && ($outputlangs->defaultlang != $langs->defaultlang))
1223
		{
1224
			$translatealsoifmodified=(! empty($conf->global->MAIN_MULTILANG_TRANSLATE_EVEN_IF_MODIFIED));	// By default if value was modified manually, we keep it (no translation because we don't have it)
1225
1226
			// TODO Instead of making a compare to see if param was modified, check that content contains reference translation. If yes, add the added part to the new translation
1227
			// ($textwasmodified is replaced with $textwasmodifiedorcompleted and we add completion).
1228
1229
			// Set label
1230
			// If we want another language, and if label is same than default language (we did force it to a specific value), we can use translation.
1231
			//var_dump($outputlangs->defaultlang.' - '.$langs->defaultlang.' - '.$label.' - '.$prodser->label);exit;
1232
			$textwasmodified=($label == $prodser->label);
1233
			if (! empty($prodser->multilangs[$outputlangs->defaultlang]["label"]) && ($textwasmodified || $translatealsoifmodified))     $label=$prodser->multilangs[$outputlangs->defaultlang]["label"];
1234
1235
			// Set desc
1236
			// Manage HTML entities description test because $prodser->description is store with htmlentities but $desc no
1237
			$textwasmodified=false;
1238
			if (!empty($desc) && dol_textishtml($desc) && !empty($prodser->description) && dol_textishtml($prodser->description)) {
1239
				$textwasmodified=(strpos(dol_html_entity_decode($desc,ENT_QUOTES | ENT_HTML401),dol_html_entity_decode($prodser->description,ENT_QUOTES | ENT_HTML401))!==false);
1240
			} else {
1241
				$textwasmodified=($desc == $prodser->description);
1242
			}
1243
			if (! empty($prodser->multilangs[$outputlangs->defaultlang]["description"]) && ($textwasmodified || $translatealsoifmodified))  $desc=$prodser->multilangs[$outputlangs->defaultlang]["description"];
1244
1245
			// Set note
1246
			$textwasmodified=($note == $prodser->note);
1247
			if (! empty($prodser->multilangs[$outputlangs->defaultlang]["note"]) && ($textwasmodified || $translatealsoifmodified))  $note=$prodser->multilangs[$outputlangs->defaultlang]["note"];
1248
		}
1249
	}
1250
1251
	// Description short of product line
1252
	$libelleproduitservice=$label;
1253
1254
	// Description long of product line
1255
	if (! empty($desc) && ($desc != $label))
1256
	{
1257
		if ($libelleproduitservice && empty($hidedesc))
1258
		{
1259
			$libelleproduitservice.='__N__';
1260
		}
1261
1262
		if ($desc == '(CREDIT_NOTE)' && $object->lines[$i]->fk_remise_except)
1263
		{
1264
			$discount=new DiscountAbsolute($db);
1265
			$discount->fetch($object->lines[$i]->fk_remise_except);
1266
			$sourceref=!empty($discount->discount_type)?$discount->ref_invoive_supplier_source:$discount->ref_facture_source;
1267
			$libelleproduitservice=$outputlangs->transnoentitiesnoconv("DiscountFromCreditNote",$sourceref);
1268
		}
1269
		elseif ($desc == '(DEPOSIT)' && $object->lines[$i]->fk_remise_except)
1270
		{
1271
			$discount=new DiscountAbsolute($db);
1272
			$discount->fetch($object->lines[$i]->fk_remise_except);
1273
			$sourceref=!empty($discount->discount_type)?$discount->ref_invoive_supplier_source:$discount->ref_facture_source;
1274
			$libelleproduitservice=$outputlangs->transnoentitiesnoconv("DiscountFromDeposit",$sourceref);
1275
			// Add date of deposit
1276
			if (! empty($conf->global->INVOICE_ADD_DEPOSIT_DATE)) echo ' ('.dol_print_date($discount->datec,'day','',$outputlangs).')';
1277
		}
1278
		if ($desc == '(EXCESS RECEIVED)' && $object->lines[$i]->fk_remise_except)
1279
		{
1280
			$discount=new DiscountAbsolute($db);
1281
			$discount->fetch($object->lines[$i]->fk_remise_except);
1282
			$libelleproduitservice=$outputlangs->transnoentitiesnoconv("DiscountFromExcessReceived",$discount->ref_facture_source);
1283
		}
1284
		elseif ($desc == '(EXCESS PAID)' && $object->lines[$i]->fk_remise_except)
1285
		{
1286
			$discount=new DiscountAbsolute($db);
1287
			$discount->fetch($object->lines[$i]->fk_remise_except);
1288
			$libelleproduitservice=$outputlangs->transnoentitiesnoconv("DiscountFromExcessPaid",$discount->ref_invoice_supplier_source);
1289
		}
1290
		else
1291
		{
1292
			if ($idprod)
1293
			{
1294
				if (empty($hidedesc))
1295
				{
1296
					if (!empty($conf->global->MAIN_DOCUMENTS_DESCRIPTION_FIRST))
1297
					{
1298
						$libelleproduitservice=$desc."\n".$libelleproduitservice;
1299
					}
1300
					else
1301
					{
1302
						$libelleproduitservice.=$desc;
1303
					}
1304
				}
1305
			}
1306
			else
1307
			{
1308
				$libelleproduitservice.=$desc;
1309
			}
1310
		}
1311
	}
1312
1313
	// We add ref of product (and supplier ref if defined)
1314
	$prefix_prodserv = "";
1315
	$ref_prodserv = "";
1316
	if (! empty($conf->global->PRODUCT_ADD_TYPE_IN_DOCUMENTS))   // In standard mode, we do not show this
1317
	{
1318
		if ($prodser->isService())
1319
		{
1320
			$prefix_prodserv = $outputlangs->transnoentitiesnoconv("Service")." ";
1321
		}
1322
		else
1323
		{
1324
			$prefix_prodserv = $outputlangs->transnoentitiesnoconv("Product")." ";
1325
		}
1326
	}
1327
1328
	if (empty($hideref))
1329
	{
1330
		if ($issupplierline)
1331
		{
1332
			if ($conf->global->PDF_HIDE_PRODUCT_REF_IN_SUPPLIER_LINES == 1)
1333
				$ref_prodserv = $ref_supplier;
1334
			elseif ($conf->global->PDF_HIDE_PRODUCT_REF_IN_SUPPLIER_LINES == 2)
1335
				$ref_prodserv = $ref_supplier. ' ('.$outputlangs->transnoentitiesnoconv("InternalRef").' '.$prodser->ref.')';
1336
			else	// Common case
1337
			{
1338
				$ref_prodserv = $prodser->ref; // Show local ref
1339
				if ($ref_supplier) $ref_prodserv.= ($prodser->ref?' (':'').$outputlangs->transnoentitiesnoconv("SupplierRef").' '.$ref_supplier.($prodser->ref?')':'');
1340
			}
1341
		}
1342
		else
1343
		{
1344
			$ref_prodserv = $prodser->ref; // Show local ref only
1345
		}
1346
1347
		if (! empty($libelleproduitservice) && ! empty($ref_prodserv)) $ref_prodserv .= " - ";
1348
	}
1349
1350
	if(!empty($ref_prodserv) && !empty($conf->global->ADD_HTML_FORMATING_INTO_DESC_DOC)){ $ref_prodserv = '<b>'.$ref_prodserv.'</b>'; }
1351
	$libelleproduitservice=$prefix_prodserv.$ref_prodserv.$libelleproduitservice;
1352
1353
	// Add an additional description for the category products
1354
	if (! empty($conf->global->CATEGORY_ADD_DESC_INTO_DOC) && $idprod && ! empty($conf->categorie->enabled))
1355
	{
1356
		include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1357
		$categstatic=new Categorie($db);
1358
		// recovering the list of all the categories linked to product
1359
		$tblcateg=$categstatic->containing($idprod, Categorie::TYPE_PRODUCT);
1360
		foreach ($tblcateg as $cate)
1361
		{
1362
			// Adding the descriptions if they are filled
1363
			$desccateg=$cate->add_description;
1364
			if ($desccateg)
1365
				$libelleproduitservice.='__N__'.$desccateg;
1366
		}
1367
	}
1368
1369
	if (! empty($object->lines[$i]->date_start) || ! empty($object->lines[$i]->date_end))
1370
	{
1371
		$format='day';
1372
		// Show duration if exists
1373
		if ($object->lines[$i]->date_start && $object->lines[$i]->date_end)
1374
		{
1375
			$period='('.$outputlangs->transnoentitiesnoconv('DateFromTo',dol_print_date($object->lines[$i]->date_start, $format, false, $outputlangs),dol_print_date($object->lines[$i]->date_end, $format, false, $outputlangs)).')';
1376
		}
1377
		if ($object->lines[$i]->date_start && ! $object->lines[$i]->date_end)
1378
		{
1379
			$period='('.$outputlangs->transnoentitiesnoconv('DateFrom',dol_print_date($object->lines[$i]->date_start, $format, false, $outputlangs)).')';
1380
		}
1381
		if (! $object->lines[$i]->date_start && $object->lines[$i]->date_end)
1382
		{
1383
			$period='('.$outputlangs->transnoentitiesnoconv('DateUntil',dol_print_date($object->lines[$i]->date_end, $format, false, $outputlangs)).')';
1384
		}
1385
		//print '>'.$outputlangs->charset_output.','.$period;
1386
		if(!empty($conf->global->ADD_HTML_FORMATING_INTO_DESC_DOC)){
1387
		    $libelleproduitservice.= '<b style="color:#333666;" ><em>'."__N__</b> ".$period.'</em>';
1388
		}else{
1389
		$libelleproduitservice.="__N__".$period;
1390
		}
1391
		//print $libelleproduitservice;
1392
	}
1393
1394
	if ($dbatch)
1395
	{
1396
		$format='day';
1397
		foreach ($dbatch as $detail)
1398
		{
1399
			$dte=array();
1400
			if ($detail->eatby) $dte[]=$outputlangs->transnoentitiesnoconv('printEatby',dol_print_date($detail->eatby, $format, false, $outputlangs));
1401
			if ($detail->sellby) $dte[]=$outputlangs->transnoentitiesnoconv('printSellby',dol_print_date($detail->sellby, $format, false, $outputlangs));
1402
			if ($detail->batch) $dte[]=$outputlangs->transnoentitiesnoconv('printBatch',$detail->batch);
1403
			$dte[]=$outputlangs->transnoentitiesnoconv('printQty',$detail->qty);
1404
			$libelleproduitservice.= "__N__  ".implode(" - ", $dte);
1405
		}
1406
	}
1407
1408
	// Now we convert \n into br
1409
	if (dol_textishtml($libelleproduitservice)) $libelleproduitservice=preg_replace('/__N__/','<br>',$libelleproduitservice);
1410
	else $libelleproduitservice=preg_replace('/__N__/',"\n",$libelleproduitservice);
1411
	$libelleproduitservice=dol_htmlentitiesbr($libelleproduitservice,1);
1412
1413
	return $libelleproduitservice;
1414
}
1415
1416
/**
1417
 *	Return line num
1418
 *
1419
 *	@param	Object		$object				Object
1420
 *	@param	int			$i					Current line number
1421
 *  @param  Translate	$outputlangs		Object langs for output
1422
 *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
1423
 * 	@return	string
1424
 */
1425
function pdf_getlinenum($object,$i,$outputlangs,$hidedetails=0)
1426
{
1427
	global $hookmanager;
1428
1429
	$reshook=0;
1430
	$result='';
1431
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1432
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1433
	{
1434
		$special_code = $object->lines[$i]->special_code;
1435
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1436
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
1437
		$action='';
1438
		$reshook = $hookmanager->executeHooks('pdf_getlinenum',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1439
		$result.=$hookmanager->resPrint;
1440
	}
1441
	if (empty($reshook))
1442
	{
1443
		$result.=dol_htmlentitiesbr($object->lines[$i]->num);
1444
	}
1445
	return $result;
1446
}
1447
1448
1449
/**
1450
 *	Return line product ref
1451
 *
1452
 *	@param	Object		$object				Object
1453
 *	@param	int			$i					Current line number
1454
 *  @param  Translate	$outputlangs		Object langs for output
1455
 *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
1456
 * 	@return	string
1457
 */
1458
function pdf_getlineref($object,$i,$outputlangs,$hidedetails=0)
1459
{
1460
	global $hookmanager;
1461
1462
	$reshook=0;
1463
	$result='';
1464
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1465
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1466
	{
1467
		$special_code = $object->lines[$i]->special_code;
1468
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1469
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
1470
		$action='';
1471
		$reshook = $hookmanager->executeHooks('pdf_getlineref',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1472
		$result.=$hookmanager->resPrint;
1473
	}
1474
	if (empty($reshook))
1475
	{
1476
		$result.=dol_htmlentitiesbr($object->lines[$i]->product_ref);
1477
	}
1478
	return $result;
1479
}
1480
1481
/**
1482
 *	Return line ref_supplier
1483
 *
1484
 *	@param	Object		$object				Object
1485
 *	@param	int			$i					Current line number
1486
 *  @param  Translate	$outputlangs		Object langs for output
1487
 *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
1488
 * 	@return	string
1489
 */
1490
function pdf_getlineref_supplier($object,$i,$outputlangs,$hidedetails=0)
1491
{
1492
	global $hookmanager;
1493
1494
	$reshook=0;
1495
	$result='';
1496
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1497
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1498
	{
1499
		$special_code = $object->lines[$i]->special_code;
1500
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1501
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
1502
		$action='';
1503
		$reshook = $hookmanager->executeHooks('pdf_getlineref_supplier',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1504
		$result.=$hookmanager->resPrint;
1505
	}
1506
	if (empty($reshook))
1507
	{
1508
		$result.=dol_htmlentitiesbr($object->lines[$i]->ref_supplier);
1509
	}
1510
	return $result;
1511
}
1512
1513
/**
1514
 *	Return line vat rate
1515
 *
1516
 *	@param	Object		$object				Object
1517
 *	@param	int			$i					Current line number
1518
 *  @param  Translate	$outputlangs		Object langs for output
1519
 *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
1520
 * 	@return	string
1521
 */
1522
function pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails=0)
1523
{
1524
	global $conf, $hookmanager, $mysoc;
1525
1526
	$result='';
1527
	$reshook=0;
1528
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1529
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduce this test in the pdf_xxx function if you don't want your hook to run
1530
	{
1531
		$special_code = $object->lines[$i]->special_code;
1532
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1533
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
1534
		$action='';
1535
		$reshook = $hookmanager->executeHooks('pdf_getlinevatrate',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1536
1537
		if (!empty($hookmanager->resPrint)) $result.=$hookmanager->resPrint;
1538
	}
1539
	if (empty($reshook))
1540
	{
1541
		if (empty($hidedetails) || $hidedetails > 1)
1542
		{
1543
			$tmpresult='';
1544
1545
			$tmpresult.=vatrate($object->lines[$i]->tva_tx, 0, $object->lines[$i]->info_bits, -1);
1546
			if (empty($conf->global->MAIN_PDF_MAIN_HIDE_SECOND_TAX))
1547
			{
1548
				if ($object->lines[$i]->total_localtax1 != 0)
1549
				{
1550
					if (preg_replace('/[\s0%]/','',$tmpresult)) $tmpresult.='/';
1551
					else $tmpresult='';
1552
					$tmpresult.=vatrate(abs($object->lines[$i]->localtax1_tx), 0);
1553
				}
1554
			}
1555
			if (empty($conf->global->MAIN_PDF_MAIN_HIDE_THIRD_TAX))
1556
			{
1557
				if ($object->lines[$i]->total_localtax2 != 0)
1558
				{
1559
					if (preg_replace('/[\s0%]/','',$tmpresult)) $tmpresult.='/';
1560
					else $tmpresult='';
1561
					$tmpresult.=vatrate(abs($object->lines[$i]->localtax2_tx), 0);
1562
				}
1563
			}
1564
			$tmpresult.= '%';
1565
1566
			$result.=$tmpresult;
1567
		}
1568
	}
1569
	return $result;
1570
}
1571
1572
/**
1573
 *	Return line unit price excluding tax
1574
 *
1575
 *	@param	Object		$object				Object
1576
 *	@param	int			$i					Current line number
1577
 *  @param  Translate	$outputlangs		Object langs for output
1578
 *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
1579
 * 	@return	string
1580
 */
1581
function pdf_getlineupexcltax($object,$i,$outputlangs,$hidedetails=0)
1582
{
1583
	global $conf, $hookmanager;
1584
1585
	$sign=1;
1586
	if (isset($object->type) && $object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1;
1587
1588
	$result='';
1589
	$reshook=0;
1590
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1591
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1592
	{
1593
		$special_code = $object->lines[$i]->special_code;
1594
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1595
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
1596
		$action='';
1597
		$reshook = $hookmanager->executeHooks('pdf_getlineupexcltax',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1598
1599
		if (!empty($hookmanager->resPrint)) $result.=$hookmanager->resPrint;
1600
	}
1601
	if (empty($reshook))
1602
	{
1603
		if (empty($hidedetails) || $hidedetails > 1)
1604
		{
1605
			$subprice = ($conf->multicurrency->enabled && $object->multicurrency_tx != 1 ? $object->lines[$i]->multicurrency_subprice : $object->lines[$i]->subprice);
1606
			$result.=price($sign * $subprice, 0, $outputlangs);
1607
		}
1608
	}
1609
	return $result;
1610
}
1611
1612
/**
1613
 *	Return line unit price including tax
1614
 *
1615
 *	@param	Object		$object				Object
1616
 *	@param	int			$i					Current line number
1617
 *  @param  Translate	$outputlangs		Object langs for output
1618
 *  @param	int			$hidedetails		Hide value (0 = no,	1 = yes, 2 = just special lines)
1619
 *  @return	string
1620
 */
1621
function pdf_getlineupwithtax($object,$i,$outputlangs,$hidedetails=0)
1622
{
1623
	global $hookmanager,$conf;
1624
1625
	$sign=1;
1626
	if (isset($object->type) && $object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1;
1627
1628
	$result='';
1629
	$reshook=0;
1630
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1631
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1632
	{
1633
		$special_code = $object->lines[$i]->special_code;
1634
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1635
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
1636
		$action='';
1637
		$reshook = $hookmanager->executeHooks('pdf_getlineupwithtax',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1638
1639
		if (!empty($hookmanager->resPrint)) $result.=$hookmanager->resPrint;
1640
	}
1641
	if (empty($reshook))
1642
	{
1643
		if (empty($hidedetails) || $hidedetails > 1) $result.=price($sign * (($object->lines[$i]->subprice) + ($object->lines[$i]->subprice)*($object->lines[$i]->tva_tx)/100), 0, $outputlangs);
1644
	}
1645
	return $result;
1646
}
1647
1648
/**
1649
 *	Return line quantity
1650
 *
1651
 *	@param	Object		$object				Object
1652
 *	@param	int			$i					Current line number
1653
 *  @param  Translate	$outputlangs		Object langs for output
1654
 *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
1655
 *  @return	string
1656
 */
1657
function pdf_getlineqty($object,$i,$outputlangs,$hidedetails=0)
1658
{
1659
	global $hookmanager;
1660
1661
	$result='';
1662
	$reshook=0;
1663
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1664
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1665
	{
1666
		$special_code = $object->lines[$i]->special_code;
1667
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1668
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
1669
		$action='';
1670
		$reshook = $hookmanager->executeHooks('pdf_getlineqty',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1671
1672
		if(!empty($hookmanager->resPrint)) $result=$hookmanager->resPrint;
1673
	}
1674
    if (empty($reshook))
1675
	{
1676
	   if ($object->lines[$i]->special_code == 3) return '';
1677
	   if (empty($hidedetails) || $hidedetails > 1) $result.=$object->lines[$i]->qty;
1678
	}
1679
	return $result;
1680
}
1681
1682
/**
1683
 *	Return line quantity asked
1684
 *
1685
 *	@param	Object		$object				Object
1686
 *	@param	int			$i					Current line number
1687
 *  @param  Translate	$outputlangs		Object langs for output
1688
 *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
1689
 * 	@return	string
1690
 */
1691
function pdf_getlineqty_asked($object,$i,$outputlangs,$hidedetails=0)
1692
{
1693
	global $hookmanager;
1694
1695
	$reshook=0;
1696
	$result='';
1697
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1698
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1699
	{
1700
		$special_code = $object->lines[$i]->special_code;
1701
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1702
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
1703
		$action='';
1704
		$reshook = $hookmanager->executeHooks('pdf_getlineqty_asked',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1705
1706
		if (!empty($hookmanager->resPrint)) $result.=$hookmanager->resPrint;
1707
	}
1708
	if (empty($reshook))
1709
	{
1710
        if ($object->lines[$i]->special_code == 3) return '';
1711
        if (empty($hidedetails) || $hidedetails > 1) $result.=$object->lines[$i]->qty_asked;
1712
	}
1713
	return $result;
1714
}
1715
1716
/**
1717
 *	Return line quantity shipped
1718
 *
1719
 *	@param	Object		$object				Object
1720
 *	@param	int			$i					Current line number
1721
 *  @param  Translate	$outputlangs		Object langs for output
1722
 *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
1723
 * 	@return	string
1724
 */
1725
function pdf_getlineqty_shipped($object,$i,$outputlangs,$hidedetails=0)
1726
{
1727
	global $hookmanager;
1728
1729
	$reshook=0;
1730
	$result='';
1731
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1732
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1733
	{
1734
		$special_code = $object->lines[$i]->special_code;
1735
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1736
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
1737
		$action='';
1738
		$reshook = $hookmanager->executeHooks('pdf_getlineqty_shipped',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1739
1740
		if(!empty($hookmanager->resPrint)) $result.=$hookmanager->resPrint;
1741
	}
1742
	if (empty($reshook))
1743
	{
1744
        if ($object->lines[$i]->special_code == 3) return '';
1745
	    if (empty($hidedetails) || $hidedetails > 1) $result.=$object->lines[$i]->qty_shipped;
1746
	}
1747
	return $result;
1748
}
1749
1750
/**
1751
 *	Return line keep to ship quantity
1752
 *
1753
 *	@param	Object		$object				Object
1754
 *	@param	int			$i					Current line number
1755
 *  @param  Translate	$outputlangs		Object langs for output
1756
 *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
1757
 * 	@return	string
1758
 */
1759
function pdf_getlineqty_keeptoship($object,$i,$outputlangs,$hidedetails=0)
1760
{
1761
	global $hookmanager;
1762
1763
	$reshook=0;
1764
    $result='';
1765
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1766
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1767
	{
1768
		$special_code = $object->lines[$i]->special_code;
1769
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1770
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
1771
		$action='';
1772
		$reshook = $hookmanager->executeHooks('pdf_getlineqty_keeptoship',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1773
1774
		if(!empty($hookmanager->resPrint)) $result.=$hookmanager->resPrint;
1775
	}
1776
	if (empty($reshook))
1777
	{
1778
        if ($object->lines[$i]->special_code == 3) return '';
1779
		if (empty($hidedetails) || $hidedetails > 1) $result.=($object->lines[$i]->qty_asked - $object->lines[$i]->qty_shipped);
1780
	}
1781
	return $result;
1782
}
1783
1784
/**
1785
 *	Return line unit
1786
 *
1787
 *	@param	Object		$object				Object
1788
 *	@param	int			$i					Current line number
1789
 *  @param  Translate	$outputlangs		Object langs for output
1790
 *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
1791
 *  @param	HookManager	$hookmanager		Hook manager instance
1792
 *  @return	string							Value for unit cell
1793
 */
1794
function pdf_getlineunit($object, $i, $outputlangs, $hidedetails = 0, $hookmanager = false)
1795
{
1796
	global $langs;
1797
1798
	$reshook=0;
1799
    $result='';
1800
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1801
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1802
	{
1803
		$special_code = $object->lines[$i]->special_code;
1804
		if (!empty($object->lines[$i]->fk_parent_line)) {
1805
			$special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1806
		}
1807
		$parameters = array(
1808
			'i' => $i,
1809
			'outputlangs' => $outputlangs,
1810
			'hidedetails' => $hidedetails,
1811
			'special_code' => $special_code
1812
		);
1813
		$action = '';
1814
		$reshook = $hookmanager->executeHooks('pdf_getlineunit', $parameters, $object, $action);    // Note that $action and $object may have been modified by some hooks
1815
1816
		if(!empty($hookmanager->resPrint)) $result.=$hookmanager->resPrint;
1817
	}
1818
	if (empty($reshook))
1819
	{
1820
        if ($object->lines[$i]->special_code == 3) return '';
1821
	    if (empty($hidedetails) || $hidedetails > 1) $result.=$langs->transnoentitiesnoconv($object->lines[$i]->getLabelOfUnit('short'));
1822
	}
1823
	return $result;
1824
}
1825
1826
1827
/**
1828
 *	Return line remise percent
1829
 *
1830
 *	@param	Object		$object				Object
1831
 *	@param	int			$i					Current line number
1832
 *  @param  Translate	$outputlangs		Object langs for output
1833
 *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
1834
 * 	@return	string
1835
 */
1836
function pdf_getlineremisepercent($object,$i,$outputlangs,$hidedetails=0)
1837
{
1838
	global $hookmanager;
1839
1840
	include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
1841
1842
	$reshook=0;
1843
	$result='';
1844
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1845
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1846
	{
1847
		$special_code = $object->lines[$i]->special_code;
1848
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1849
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
1850
		$action='';
1851
		$reshook = $hookmanager->executeHooks('pdf_getlineremisepercent',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1852
1853
		if(!empty($hookmanager->resPrint)) $result.=$hookmanager->resPrint;
1854
	}
1855
	if (empty($reshook))
1856
	{
1857
        if ($object->lines[$i]->special_code == 3) return '';
1858
	    if (empty($hidedetails) || $hidedetails > 1) $result.=dol_print_reduction($object->lines[$i]->remise_percent,$outputlangs);
1859
	}
1860
	return $result;
1861
}
1862
1863
/**
1864
 * Return line percent
1865
 *
1866
 * @param Object $object Object
1867
 * @param int $i Current line number
1868
 * @param Translate $outputlangs Object langs for output
1869
 * @param int $hidedetails Hide details (0=no, 1=yes, 2=just special lines)
1870
 * @param HookManager $hookmanager Hook manager instance
1871
 * @return string
1872
 */
1873
function pdf_getlineprogress($object, $i, $outputlangs, $hidedetails = 0, $hookmanager = null)
1874
{
1875
	if (empty($hookmanager)) global $hookmanager;
1876
	global $conf;
1877
1878
	$reshook=0;
1879
    $result='';
1880
    //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1881
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1882
	{
1883
		$special_code = $object->lines[$i]->special_code;
1884
		if (!empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1885
		$parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code);
1886
		$action = '';
1887
		$reshook = $hookmanager->executeHooks('pdf_getlineprogress', $parameters, $object, $action);    // Note that $action and $object may have been modified by some hooks
1888
1889
		if(!empty($hookmanager->resPrint)) return $hookmanager->resPrint;
1890
	}
1891
	if (empty($reshook))
1892
	{
1893
        	if ($object->lines[$i]->special_code == 3) return '';
1894
		if (empty($hidedetails) || $hidedetails > 1)
1895
		{
1896
			if ($conf->global->SITUATION_DISPLAY_DIFF_ON_PDF)
1897
			{
1898
				$prev_progress = 0;
1899
				if (method_exists($object, 'get_prev_progress'))
1900
				{
1901
			 		$prev_progress = $object->lines[$i]->get_prev_progress($object->id);
1902
				}
1903
			 	$result = ($object->lines[$i]->situation_percent - $prev_progress) . '%';
1904
			}
1905
			else
1906
				$result = $object->lines[$i]->situation_percent . '%';
1907
	  	}
1908
	}
1909
	return $result;
1910
}
1911
1912
/**
1913
 *	Return line total excluding tax
1914
 *
1915
 *	@param	Object		$object				Object
1916
 *	@param	int			$i					Current line number
1917
 *  @param  Translate	$outputlangs		Object langs for output
1918
 *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
1919
 * 	@return	string							Return total of line excl tax
1920
 */
1921
function pdf_getlinetotalexcltax($object,$i,$outputlangs,$hidedetails=0)
1922
{
1923
	global $conf, $hookmanager;
1924
1925
	$sign=1;
1926
	if (isset($object->type) && $object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1;
1927
1928
	$reshook=0;
1929
	$result='';
1930
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1931
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1932
	{
1933
		$special_code = $object->lines[$i]->special_code;
1934
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1935
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code, 'sign'=>$sign);
1936
		$action='';
1937
		$reshook = $hookmanager->executeHooks('pdf_getlinetotalexcltax',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1938
1939
		if(!empty($hookmanager->resPrint)) $result.=$hookmanager->resPrint;
1940
	}
1941
    if (empty($reshook))
1942
    {
1943
	    if ($object->lines[$i]->special_code == 3)
1944
    	{
1945
    		return $outputlangs->transnoentities("Option");
1946
    	}
1947
        if (empty($hidedetails) || $hidedetails > 1)
1948
        {
1949
        	$total_ht = ($conf->multicurrency->enabled && $object->multicurrency_tx != 1 ? $object->lines[$i]->multicurrency_total_ht : $object->lines[$i]->total_ht);
1950
        	if ($object->lines[$i]->situation_percent > 0)
1951
        	{
1952
        		$prev_progress = 0;
1953
        		$progress = 1;
1954
        		if (method_exists($object->lines[$i], 'get_prev_progress'))
1955
        		{
1956
					$prev_progress = $object->lines[$i]->get_prev_progress($object->id);
1957
					$progress = ($object->lines[$i]->situation_percent - $prev_progress) / 100;
1958
        		}
1959
				$result.=price($sign * ($total_ht/($object->lines[$i]->situation_percent/100)) * $progress, 0, $outputlangs);
1960
        	}
1961
        	else
1962
			$result.=price($sign * $total_ht, 0, $outputlangs);
1963
	}
1964
    }
1965
	return $result;
1966
}
1967
1968
/**
1969
 *	Return line total including tax
1970
 *
1971
 *	@param	Object		$object				Object
1972
 *	@param	int			$i					Current line number
1973
 *  @param 	Translate	$outputlangs		Object langs for output
1974
 *  @param	int			$hidedetails		Hide value (0 = no, 1 = yes, 2 = just special lines)
1975
 *  @return	string							Return total of line incl tax
1976
 */
1977
function pdf_getlinetotalwithtax($object,$i,$outputlangs,$hidedetails=0)
1978
{
1979
	global $hookmanager,$conf;
1980
1981
	$sign=1;
1982
	if (isset($object->type) && $object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1;
1983
1984
	$reshook=0;
1985
	$result='';
1986
	//if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line) ) )
1987
	if (is_object($hookmanager))   // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don't want your hook to run
1988
	{
1989
		$special_code = $object->lines[$i]->special_code;
1990
		if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
1991
		$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
1992
		$action='';
1993
		$reshook = $hookmanager->executeHooks('pdf_getlinetotalwithtax',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
1994
1995
		if(!empty($hookmanager->resPrint)) $result.=$hookmanager->resPrint;
1996
	}
1997
	if (empty($reshook))
1998
	{
1999
		if ($object->lines[$i]->special_code == 3)
2000
    	{
2001
    		$result.=$outputlangs->transnoentities("Option");
2002
    	}
2003
		elseif (empty($hidedetails) || $hidedetails > 1) $result.=price($sign * ($object->lines[$i]->total_ht) + ($object->lines[$i]->total_ht)*($object->lines[$i]->tva_tx)/100, 0, $outputlangs);
2004
	}
2005
	return $result;
2006
}
2007
2008
/**
2009
 *	Return total quantity of products and/or services
2010
 *
2011
 *	@param	Object		$object				Object
2012
 *	@param	string		$type				Type
2013
 *  @param  Translate	$outputlangs		Object langs for output
2014
 * 	@return	integer
2015
 *  @deprecated Not used by Dolibarr core, so will be removed.
2016
 */
2017
function pdf_getTotalQty($object,$type,$outputlangs)
2018
{
2019
	global $hookmanager;
2020
2021
	$total=0;
2022
	$nblignes=count($object->lines);
2023
2024
	// Loop on each lines
2025
	for ($i = 0 ; $i < $nblignes ; $i++)
2026
	{
2027
		if ($object->lines[$i]->special_code != 3)
2028
		{
2029
			if ($type=='all')
2030
			{
2031
				$total += $object->lines[$i]->qty;
2032
			}
2033
			else if ($type==9 && is_object($hookmanager) && (($object->lines[$i]->product_type == 9 && ! empty($object->lines[$i]->special_code)) || ! empty($object->lines[$i]->fk_parent_line)))
2034
			{
2035
				$special_code = $object->lines[$i]->special_code;
2036
				if (! empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);
2037
				$parameters = array('i'=>$i,'outputlangs'=>$outputlangs,'hidedetails'=>$hidedetails,'special_code'=>$special_code);
2038
				$action='';
2039
				$reshook = $hookmanager->executeHooks('pdf_getTotalQty',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
2040
				return $hookmanager->resPrint;
2041
			}
2042
			else if ($type==0 && $object->lines[$i]->product_type == 0)
2043
			{
2044
				$total += $object->lines[$i]->qty;
2045
			}
2046
			else if ($type==1 && $object->lines[$i]->product_type == 1)
2047
			{
2048
				$total += $object->lines[$i]->qty;
2049
			}
2050
		}
2051
	}
2052
2053
	return $total;
2054
}
2055
2056
/**
2057
 * 	Return linked objects to use for document generation.
2058
 *  Warning: To save space, this function returns only one link per link type (all links are concated on same record string). This function is used by pdf_writeLinkedObjects
2059
 *
2060
 * 	@param	object		$object			Object
2061
 * 	@param	Translate	$outputlangs	Object lang for output
2062
 * 	@return	array                       Linked objects
2063
 */
2064
function pdf_getLinkedObjects($object,$outputlangs)
2065
{
2066
	global $hookmanager;
2067
2068
	$linkedobjects=array();
2069
2070
	$object->fetchObjectLinked();
2071
2072
	foreach($object->linkedObjects as $objecttype => $objects)
2073
	{
2074
	    if ($objecttype == 'facture')
2075
	    {
2076
	       // For invoice, we don't want to have a reference line on document. Image we are using recuring invoice, we will have a line longer than document width.
2077
	    }
2078
	    elseif ($objecttype == 'propal' || $objecttype == 'supplier_proposal')
2079
		{
2080
			$outputlangs->load('propal');
2081
2082
			foreach($objects as $elementobject)
2083
			{
2084
				$linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefProposal");
2085
				$linkedobjects[$objecttype]['ref_value'] = $outputlangs->transnoentities($elementobject->ref);
2086
				$linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("DatePropal");
2087
				$linkedobjects[$objecttype]['date_value'] = dol_print_date($elementobject->date,'day','',$outputlangs);
2088
			}
2089
		}
2090
		else if ($objecttype == 'commande' || $objecttype == 'supplier_order')
2091
		{
2092
			$outputlangs->load('orders');
2093
			foreach($objects as $elementobject)
2094
			{
2095
				$linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefOrder");
2096
				$linkedobjects[$objecttype]['ref_value'] = $outputlangs->transnoentities($elementobject->ref) . ($elementobject->ref_client ? ' ('.$elementobject->ref_client.')' : '') . ($elementobject->ref_supplier ? ' ('.$elementobject->ref_supplier.')' : '');
2097
				$linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("OrderDate");
2098
				$linkedobjects[$objecttype]['date_value'] = dol_print_date($elementobject->date,'day','',$outputlangs);
2099
			}
2100
		}
2101
		else if ($objecttype == 'contrat')
2102
		{
2103
			$outputlangs->load('contracts');
2104
			foreach($objects as $elementobject)
2105
			{
2106
				$linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefContract");
2107
				$linkedobjects[$objecttype]['ref_value'] = $outputlangs->transnoentities($elementobject->ref);
2108
				$linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("DateContract");
2109
				$linkedobjects[$objecttype]['date_value'] = dol_print_date($elementobject->date_contrat,'day','',$outputlangs);
2110
			}
2111
		}
2112
		else if ($objecttype == 'shipping')
2113
		{
2114
			$outputlangs->loadLangs(array("orders", "sendings"));
2115
2116
			foreach($objects as $x => $elementobject)
2117
			{
2118
			    $order=null;
2119
			    // We concat this record info into fields xxx_value. title is overwrote.
2120
			    if (empty($object->linkedObjects['commande']) && $object->element != 'commande')	// There is not already a link to order and object is not the order, so we show also info with order
2121
			    {
2122
			        $elementobject->fetchObjectLinked();
2123
			        if (! empty($elementobject->linkedObjects['commande'])) $order = reset($elementobject->linkedObjects['commande']);
2124
			    }
2125
			    if (! is_object($order))
2126
			    {
2127
			        $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefSending");
2128
			        if (! empty($linkedobjects[$objecttype]['ref_value'])) $linkedobjects[$objecttype]['ref_value'].=' / ';
2129
			        $linkedobjects[$objecttype]['ref_value'].= $outputlangs->transnoentities($elementobject->ref);
2130
			        //$linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("DateShipment");
2131
			        //if (! empty($linkedobjects[$objecttype]['date_value'])) $linkedobjects[$objecttype]['date_value'].=' / ';
2132
			        //$linkedobjects[$objecttype]['date_value'].= dol_print_date($elementobject->date_delivery,'day','',$outputlangs);
2133
			    }
2134
			    else
2135
			    {
2136
			        $linkedobjects[$objecttype]['ref_title'] = $outputlangs->transnoentities("RefOrder") . ' / ' . $outputlangs->transnoentities("RefSending");
2137
			        if (empty($linkedobjects[$objecttype]['ref_value'])) $linkedobjects[$objecttype]['ref_value'] = $outputlangs->convToOutputCharset($order->ref) . ($order->ref_client ? ' ('.$order->ref_client.')' : '');
2138
			        $linkedobjects[$objecttype]['ref_value'].= ' / ' . $outputlangs->transnoentities($elementobject->ref);
2139
			        //$linkedobjects[$objecttype]['date_title'] = $outputlangs->transnoentities("OrderDate") . ($elementobject->date_delivery ? ' / ' . $outputlangs->transnoentities("DateShipment") : '');
2140
			        //if (empty($linkedobjects[$objecttype]['date_value'])) $linkedobjects[$objecttype]['date_value'] = dol_print_date($order->date,'day','',$outputlangs);
2141
			        //$linkedobjects[$objecttype]['date_value'].= ($elementobject->date_delivery ? ' / ' . dol_print_date($elementobject->date_delivery,'day','',$outputlangs) : '');
2142
			    }
2143
			}
2144
		}
2145
	}
2146
2147
	// For add external linked objects
2148
	if (is_object($hookmanager))
2149
	{
2150
		$parameters = array('linkedobjects' => $linkedobjects, 'outputlangs'=>$outputlangs);
2151
		$action='';
2152
		$hookmanager->executeHooks('pdf_getLinkedObjects',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
2153
		if (! empty($hookmanager->resArray)) $linkedobjects = $hookmanager->resArray;
2154
	}
2155
2156
	return $linkedobjects;
2157
}
2158
2159
/**
2160
 * Return dimensions to use for images onto PDF checking that width and height are not higher than
2161
 * maximum (16x32 by default).
2162
 *
2163
 * @param	string		$realpath		Full path to photo file to use
2164
 * @return	array						Height and width to use to output image (in pdf user unit, so mm)
2165
 */
2166
function pdf_getSizeForImage($realpath)
2167
{
2168
	global $conf;
2169
2170
	$maxwidth=(empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH)?20:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH);
2171
	$maxheight=(empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_HEIGHT)?32:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_HEIGHT);
2172
	include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
2173
	$tmp=dol_getImageSize($realpath);
2174
	if ($tmp['height'])
2175
	{
2176
		$width=(int) round($maxheight*$tmp['width']/$tmp['height']);	// I try to use maxheight
2177
		if ($width > $maxwidth)	// Pb with maxheight, so i use maxwidth
2178
		{
2179
			$width=$maxwidth;
2180
			$height=(int) round($maxwidth*$tmp['height']/$tmp['width']);
2181
		}
2182
		else	// No pb with maxheight
2183
		{
2184
			$height=$maxheight;
2185
		}
2186
	}
2187
	return array('width'=>$width,'height'=>$height);
2188
}
2189