Passed
Branch develop (01f96b)
by
unknown
30:45
created

pdf_sponge::_tableau()   B

Complexity

Conditions 8
Paths 40

Size

Total Lines 42
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

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

How to fix   Many Parameters   

Many Parameters

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

There are several approaches to avoid long parameter lists:

1
<?php
2
/* Copyright (C) 2004-2014  Laurent Destailleur     <[email protected]>
3
 * Copyright (C) 2005-2012  Regis Houssin           <[email protected]>
4
 * Copyright (C) 2008       Raphael Bertrand        <[email protected]>
5
 * Copyright (C) 2010-2014  Juanjo Menent           <[email protected]>
6
 * Copyright (C) 2012       Christophe Battarel     <[email protected]>
7
 * Copyright (C) 2012       Cédric Salvador         <[email protected]>
8
 * Copyright (C) 2012-2014  Raphaël Doursenaud      <[email protected]>
9
 * Copyright (C) 2015       Marcos García           <[email protected]>
10
 * Copyright (C) 2017       Ferran Marcet           <[email protected]>
11
 * Copyright (C) 2018       Frédéric France         <[email protected]>
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 3 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25
 * or see https://www.gnu.org/
26
 */
27
28
/**
29
 *  \file       htdocs/core/modules/facture/doc/pdf_sponge.modules.php
30
 *  \ingroup    facture
31
 *  \brief      File of class to generate customers invoices from sponge model
32
 */
33
34
require_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php';
35
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
36
require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
37
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
38
require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
39
40
41
/**
42
 *	Class to manage PDF invoice template sponge
43
 */
44
class pdf_sponge extends ModelePDFFactures
45
{
46
    /**
47
     * @var DoliDb Database handler
48
     */
49
    public $db;
50
51
	/**
52
     * @var string model name
53
     */
54
    public $name;
55
56
	/**
57
     * @var string model description (short text)
58
     */
59
    public $description;
60
61
    /**
62
     * @var int     Save the name of generated file as the main doc when generating a doc with this template
63
     */
64
    public $update_main_doc_field;
65
66
	/**
67
     * @var string document type
68
     */
69
    public $type;
70
71
	/**
72
     * @var array Minimum version of PHP required by module.
73
     * e.g.: PHP ≥ 5.5 = array(5, 5)
74
     */
75
	public $phpmin = array(5, 5);
76
77
	/**
78
     * Dolibarr version of the loaded document
79
     * @var string
80
     */
81
	public $version = 'dolibarr';
82
83
     /**
84
     * @var int page_largeur
85
     */
86
    public $page_largeur;
87
88
	/**
89
     * @var int page_hauteur
90
     */
91
    public $page_hauteur;
92
93
	/**
94
     * @var array format
95
     */
96
    public $format;
97
98
	/**
99
     * @var int marge_gauche
100
     */
101
	public $marge_gauche;
102
103
	/**
104
     * @var int marge_droite
105
     */
106
	public $marge_droite;
107
108
	/**
109
     * @var int marge_haute
110
     */
111
	public $marge_haute;
112
113
	/**
114
     * @var int marge_basse
115
     */
116
	public $marge_basse;
117
118
    /**
119
	* Issuer
120
	* @var Societe Object that emits
121
	*/
122
	public $emetteur;
123
124
	/**
125
	 * @var bool Situation invoice type
126
	 */
127
	public $situationinvoice;
128
129
130
	/**
131
	 * @var array of document table collumns
132
	 */
133
	public $cols;
134
135
136
	/**
137
	 *	Constructor
138
	 *
139
	 *  @param		DoliDB		$db      Database handler
140
	 */
141
	public function __construct($db)
142
	{
143
		global $conf, $langs, $mysoc;
144
145
		// Translations
146
		$langs->loadLangs(array("main", "bills"));
147
148
		$this->db = $db;
149
		$this->name = "sponge";
150
		$this->description = $langs->trans('PDFSpongeDescription');
151
		$this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template
152
153
		// Dimension page
154
		$this->type = 'pdf';
155
		$formatarray = pdf_getFormat();
156
		$this->page_largeur = $formatarray['width'];
157
		$this->page_hauteur = $formatarray['height'];
158
		$this->format = array($this->page_largeur, $this->page_hauteur);
159
		$this->marge_gauche = isset($conf->global->MAIN_PDF_MARGIN_LEFT) ? $conf->global->MAIN_PDF_MARGIN_LEFT : 10;
160
		$this->marge_droite = isset($conf->global->MAIN_PDF_MARGIN_RIGHT) ? $conf->global->MAIN_PDF_MARGIN_RIGHT : 10;
161
		$this->marge_haute = isset($conf->global->MAIN_PDF_MARGIN_TOP) ? $conf->global->MAIN_PDF_MARGIN_TOP : 10;
162
		$this->marge_basse = isset($conf->global->MAIN_PDF_MARGIN_BOTTOM) ? $conf->global->MAIN_PDF_MARGIN_BOTTOM : 10;
163
164
		$this->option_logo = 1; // Display logo
165
		$this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION
166
		$this->option_modereg = 1; // Display payment mode
167
		$this->option_condreg = 1; // Display payment terms
168
		$this->option_codeproduitservice = 1; // Display product-service code
169
		$this->option_multilang = 1; // Available in several languages
170
		$this->option_escompte = 1; // Displays if there has been a discount
171
		$this->option_credit_note = 1; // Support credit notes
172
		$this->option_freetext = 1; // Support add of a personalised text
173
		$this->option_draft_watermark = 1; // Support add of a watermark on drafts
174
175
		// Get source company
176
		$this->emetteur = $mysoc;
177
		if (empty($this->emetteur->country_code)) $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined
178
179
		// Define position of columns
180
		$this->posxdesc = $this->marge_gauche + 1; // used for notes ans other stuff
181
182
183
		$this->tabTitleHeight = 5; // default height
184
185
		//  Use new system for position of columns, view  $this->defineColumnField()
186
187
		$this->tva = array();
188
		$this->localtax1 = array();
189
		$this->localtax2 = array();
190
		$this->atleastoneratenotnull = 0;
191
		$this->atleastonediscount = 0;
192
		$this->situationinvoice = false;
193
	}
194
195
196
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
197
    /**
198
     *  Function to build pdf onto disk
199
     *
200
     *  @param		Object		$object				Object to generate
201
     *  @param		Translate	$outputlangs		Lang output object
202
     *  @param		string		$srctemplatepath	Full path of source filename for generator using a template file
203
     *  @param		int			$hidedetails		Do not show line details
204
     *  @param		int			$hidedesc			Do not show desc
205
     *  @param		int			$hideref			Do not show ref
206
     *  @return     int         	    			1=OK, 0=KO
207
	 */
208
	public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
209
	{
210
	    // phpcs:enable
211
	    global $user, $langs, $conf, $mysoc, $db, $hookmanager, $nblines;
212
213
	    dol_syslog("write_file outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null'));
214
215
	    if (!is_object($outputlangs)) $outputlangs = $langs;
216
	    // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
217
	    if (!empty($conf->global->MAIN_USE_FPDF)) $outputlangs->charset_output = 'ISO-8859-1';
218
219
	    // Load translation files required by the page
220
	    $outputlangs->loadLangs(array("main", "bills", "products", "dict", "companies"));
221
222
	    if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) {
223
	    	global $outputlangsbis;
224
	    	$outputlangsbis = new Translate('', $conf);
225
	    	$outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE);
226
	    	$outputlangsbis->loadLangs(array("main", "bills", "products", "dict", "companies"));
227
	    }
228
229
	    $nblines = count($object->lines);
230
231
	    $hidetop = 0;
232
	    if (!empty($conf->global->MAIN_PDF_DISABLE_COL_HEAD_TITLE)) {
233
	        $hidetop = $conf->global->MAIN_PDF_DISABLE_COL_HEAD_TITLE;
234
	    }
235
236
	    // Loop on each lines to detect if there is at least one image to show
237
	    $realpatharray = array();
238
	    $this->atleastonephoto = false;
239
	    if (!empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE))
240
	    {
241
	        $objphoto = new Product($this->db);
242
243
	        for ($i = 0; $i < $nblines; $i++)
244
	        {
245
	            if (empty($object->lines[$i]->fk_product)) continue;
246
247
	            $objphoto->fetch($object->lines[$i]->fk_product);
248
	            //var_dump($objphoto->ref);exit;
249
	            if (!empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))
250
	            {
251
	                $pdir[0] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/";
252
	                $pdir[1] = get_exdir(0, 0, 0, 0, $objphoto, 'product').dol_sanitizeFileName($objphoto->ref).'/';
253
	            }
254
	            else
255
	            {
256
	                $pdir[0] = get_exdir(0, 0, 0, 0, $objphoto, 'product').dol_sanitizeFileName($objphoto->ref).'/'; // default
257
	                $pdir[1] = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$objphoto->id."/photos/"; // alternative
258
	            }
259
260
	            $arephoto = false;
261
	            foreach ($pdir as $midir)
262
	            {
263
	                if (!$arephoto)
264
	                {
265
	                    $dir = $conf->product->dir_output.'/'.$midir;
266
267
	                    foreach ($objphoto->liste_photos($dir, 1) as $key => $obj)
268
	                    {
269
	                        if (empty($conf->global->CAT_HIGH_QUALITY_IMAGES))		// If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo
270
	                        {
271
	                            if ($obj['photo_vignette'])
272
	                            {
273
	                                $filename = $obj['photo_vignette'];
274
	                            }
275
	                            else
276
	                            {
277
	                                $filename = $obj['photo'];
278
	                            }
279
	                        }
280
	                        else
281
	                        {
282
	                            $filename = $obj['photo'];
283
	                        }
284
285
	                        $realpath = $dir.$filename;
286
	                        $arephoto = true;
287
	                        $this->atleastonephoto = true;
288
	                    }
289
	                }
290
	            }
291
292
	            if ($realpath && $arephoto) $realpatharray[$i] = $realpath;
293
	        }
294
	    }
295
296
	    //if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva;
297
298
	    if ($conf->facture->dir_output)
299
	    {
300
	        $object->fetch_thirdparty();
301
302
	        $deja_regle = $object->getSommePaiement(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0);
303
	        $amount_credit_notes_included = $object->getSumCreditNotesUsed(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0);
304
	        $amount_deposits_included = $object->getSumDepositsUsed(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0);
305
306
	        // Definition of $dir and $file
307
	        if ($object->specimen)
308
	        {
309
	            $dir = $conf->facture->dir_output;
310
	            $file = $dir."/SPECIMEN.pdf";
311
	        }
312
	        else
313
	        {
314
	            $objectref = dol_sanitizeFileName($object->ref);
315
	            $dir = $conf->facture->dir_output."/".$objectref;
316
	            $file = $dir."/".$objectref.".pdf";
317
	        }
318
	        if (!file_exists($dir))
319
	        {
320
	            if (dol_mkdir($dir) < 0)
321
	            {
322
	                $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
323
	                return 0;
324
	            }
325
	        }
326
327
	        if (file_exists($dir))
328
	        {
329
	            // Add pdfgeneration hook
330
	            if (!is_object($hookmanager))
331
	            {
332
	                include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
333
	                $hookmanager = new HookManager($this->db);
334
	            }
335
	            $hookmanager->initHooks(array('pdfgeneration'));
336
	            $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
337
	            global $action;
338
	            $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
339
340
	            // Set nblines with the new facture lines content after hook
341
	            $nblines = count($object->lines);
342
	            $nbpayments = count($object->getListOfPayments());
343
344
	            // Create pdf instance
345
	            $pdf = pdf_getInstance($this->format);
346
	            $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
347
	            $pdf->SetAutoPageBreak(1, 0);
348
349
	            $heightforinfotot = 50 + (4 * $nbpayments); // Height reserved to output the info and total part and payment part
350
	            $heightforfreetext = (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT) ? $conf->global->MAIN_PDF_FREETEXT_HEIGHT : 5); // Height reserved to output the free text on last page
351
	            $heightforfooter = $this->marge_basse + (empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS) ? 12 : 22); // Height reserved to output the footer (value include bottom margin)
352
353
	            if (class_exists('TCPDF'))
354
	            {
355
	                $pdf->setPrintHeader(false);
356
	                $pdf->setPrintFooter(false);
357
	            }
358
	            $pdf->SetFont(pdf_getPDFFont($outputlangs));
359
360
	            // Set path to the background PDF File
361
                if (!empty($conf->global->MAIN_ADD_PDF_BACKGROUND))
362
	            {
363
	            	$pagecount = $pdf->setSourceFile($conf->mycompany->multidir_output[$object->entity].'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND);
364
	                $tplidx = $pdf->importPage(1);
365
	            }
366
367
	            $pdf->Open();
368
	            $pagenb = 0;
369
	            $pdf->SetDrawColor(128, 128, 128);
370
371
	            $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
372
	            $pdf->SetSubject($outputlangs->transnoentities("PdfInvoiceTitle"));
373
	            $pdf->SetCreator("Dolibarr ".DOL_VERSION);
374
	            $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
375
	            $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfInvoiceTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
376
	            if (!empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false);
377
378
	            // Set certificate
379
	            $cert = empty($user->conf->CERTIFICATE_CRT) ? '' : $user->conf->CERTIFICATE_CRT;
380
	            // If use has no certificate, we try to take the company one
381
	            if (!$cert) {
382
	            	$cert = empty($conf->global->CERTIFICATE_CRT) ? '' : $conf->global->CERTIFICATE_CRT;
383
	            }
384
	            // If a certificate is found
385
	            if ($cert) {
386
	            	$info = array(
387
	            		'Name' => $this->emetteur->name,
388
	            		'Location' => getCountry($this->emetteur->country_code, 0),
389
	            		'Reason' => 'INVOICE',
390
	            		'ContactInfo' => $this->emetteur->email
391
	            	);
392
	            	$pdf->setSignature($cert, $cert, $this->emetteur->name, '', 2, $info);
393
	            }
394
395
	            $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
396
397
	            // Does we have at least one line with discount $this->atleastonediscount
398
	            foreach ($object->lines as $line) {
399
                    if ($line->remise_percent) {
400
	                    $this->atleastonediscount = true;
401
	                    break;
402
	                }
403
	            }
404
405
406
	            // Situation invoice handling
407
	            if ($object->situation_cycle_ref)
408
	            {
409
	                $this->situationinvoice = true;
410
	            }
411
412
	            // New page
413
	            $pdf->AddPage();
414
	            if (!empty($tplidx)) $pdf->useTemplate($tplidx);
415
	            $pagenb++;
416
417
	            $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, $outputlangsbis);
418
	            $pdf->SetFont('', '', $default_font_size - 1);
419
	            $pdf->MultiCell(0, 3, ''); // Set interline to 3
420
	            $pdf->SetTextColor(0, 0, 0);
421
422
	            $tab_top = 90 + $top_shift;
423
	            $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD) ? 42 + $top_shift : 10);
424
	            $tab_height = 130 - $top_shift;
425
	            $tab_height_newpage = 150;
426
	            if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $tab_height_newpage -= $top_shift;
427
428
                $nexY = $tab_top - 1;
429
430
	            // Incoterm
431
	            $height_incoterms = 0;
432
	            if ($conf->incoterm->enabled)
433
	            {
434
	                $desc_incoterms = $object->getIncotermsForPDF();
435
	                if ($desc_incoterms)
436
	                {
437
						$tab_top -= 2;
438
439
	                    $pdf->SetFont('', '', $default_font_size - 1);
440
	                    $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($desc_incoterms), 0, 1);
441
	                    $nexY = max($pdf->GetY(), $nexY);
442
	                    $height_incoterms = $nexY - $tab_top;
443
444
	                    // Rect takes a length in 3rd parameter
445
	                    $pdf->SetDrawColor(192, 192, 192);
446
	                    $pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_incoterms + 1);
447
448
	                    $tab_top = $nexY + 6;
449
	                    $height_incoterms += 4;
450
	                }
451
	            }
452
453
	            // Display notes
454
	            $notetoshow = empty($object->note_public) ? '' : $object->note_public;
455
	            if (!empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE))
456
	            {
457
	                // Get first sale rep
458
	                if (is_object($object->thirdparty))
459
	                {
460
	                    $salereparray = $object->thirdparty->getSalesRepresentatives($user);
461
	                    $salerepobj = new User($this->db);
462
	                    $salerepobj->fetch($salereparray[0]['id']);
463
	                    if (!empty($salerepobj->signature)) $notetoshow = dol_concatdesc($notetoshow, $salerepobj->signature);
464
	                }
465
	            }
466
467
	            // Extrafields in note
468
                $extranote = $this->getExtrafieldsInHtml($object, $outputlangs);
469
                if (!empty($extranote))
470
                {
471
                    $notetoshow = dol_concatdesc($notetoshow, $extranote);
472
                }
473
474
	            $pagenb = $pdf->getPage();
475
	            if ($notetoshow)
476
	            {
477
					$tab_top -= 2;
478
479
	                $tab_width = $this->page_largeur - $this->marge_gauche - $this->marge_droite;
480
	                $pageposbeforenote = $pagenb;
481
482
	                $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
483
	                complete_substitutions_array($substitutionarray, $outputlangs, $object);
484
	                $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
485
	                $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);
486
487
	                $pdf->startTransaction();
488
489
	                $pdf->SetFont('', '', $default_font_size - 1);
490
	                $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
491
	                // Description
492
	                $pageposafternote = $pdf->getPage();
493
	                $posyafter = $pdf->GetY();
494
495
	                if ($pageposafternote > $pageposbeforenote)
496
	                {
497
	                    $pdf->rollbackTransaction(true);
498
499
	                    // prepare pages to receive notes
500
	                    while ($pagenb < $pageposafternote) {
501
	                        $pdf->AddPage();
502
	                        $pagenb++;
503
	                        if (!empty($tplidx)) $pdf->useTemplate($tplidx);
504
	                        if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
505
	                        // $this->_pagefoot($pdf,$object,$outputlangs,1);
506
	                        $pdf->setTopMargin($tab_top_newpage);
507
	                        // The only function to edit the bottom margin of current page to set it.
508
	                        $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
509
	                    }
510
511
	                    // back to start
512
	                    $pdf->setPage($pageposbeforenote);
513
	                    $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
514
	                    $pdf->SetFont('', '', $default_font_size - 1);
515
	                    $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
516
	                    $pageposafternote = $pdf->getPage();
517
518
	                    $posyafter = $pdf->GetY();
519
520
	                    if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20)))	// There is no space left for total+free text
521
	                    {
522
	                        $pdf->AddPage('', '', true);
523
	                        $pagenb++;
524
	                        $pageposafternote++;
525
	                        $pdf->setPage($pageposafternote);
526
	                        $pdf->setTopMargin($tab_top_newpage);
527
	                        // The only function to edit the bottom margin of current page to set it.
528
	                        $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
529
	                        //$posyafter = $tab_top_newpage;
530
	                    }
531
532
533
	                    // apply note frame to previous pages
534
	                    $i = $pageposbeforenote;
535
	                    while ($i < $pageposafternote) {
536
	                        $pdf->setPage($i);
537
538
539
	                        $pdf->SetDrawColor(128, 128, 128);
540
	                        // Draw note frame
541
	                        if ($i > $pageposbeforenote) {
542
	                            $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter);
543
	                            $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1);
544
	                        }
545
	                        else {
546
	                            $height_note = $this->page_hauteur - ($tab_top + $heightforfooter);
547
	                            $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1);
548
	                        }
549
550
	                        // Add footer
551
	                        $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
552
	                        $this->_pagefoot($pdf, $object, $outputlangs, 1);
553
554
	                        $i++;
555
	                    }
556
557
	                    // apply note frame to last page
558
	                    $pdf->setPage($pageposafternote);
559
	                    if (!empty($tplidx)) $pdf->useTemplate($tplidx);
560
	                    if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
561
	                    $height_note = $posyafter - $tab_top_newpage;
562
	                    $pdf->Rect($this->marge_gauche, $tab_top_newpage - 1, $tab_width, $height_note + 1);
563
	                }
564
	                else // No pagebreak
565
	                {
566
	                    $pdf->commitTransaction();
567
	                    $posyafter = $pdf->GetY();
568
	                    $height_note = $posyafter - $tab_top;
569
	                    $pdf->Rect($this->marge_gauche, $tab_top - 1, $tab_width, $height_note + 1);
570
571
572
	                    if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + 20)))
573
	                    {
574
	                        // not enough space, need to add page
575
	                        $pdf->AddPage('', '', true);
576
	                        $pagenb++;
577
	                        $pageposafternote++;
578
	                        $pdf->setPage($pageposafternote);
579
	                        if (!empty($tplidx)) $pdf->useTemplate($tplidx);
580
	                        if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
581
582
	                        $posyafter = $tab_top_newpage;
583
	                    }
584
	                }
585
586
	                $tab_height = $tab_height - $height_note;
587
	                $tab_top = $posyafter + 6;
588
	            }
589
	            else
590
	            {
591
	                $height_note = 0;
592
	            }
593
594
	            // Use new auto column system
595
	            $this->prepareArrayColumnField($object, $outputlangs, $hidedetails, $hidedesc, $hideref);
596
597
	            // Table simulation to know the height of the title line
598
			    $pdf->startTransaction();
599
			    $this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop);
600
			    $pdf->rollbackTransaction(true);
601
602
			    $nexY = $tab_top + $this->tabTitleHeight;
603
604
	            // Loop on each lines
605
	            $pageposbeforeprintlines = $pdf->getPage();
606
	            $pagenb = $pageposbeforeprintlines;
607
	            for ($i = 0; $i < $nblines; $i++)
608
	            {
609
	                $curY = $nexY;
610
	                $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
611
	                $pdf->SetTextColor(0, 0, 0);
612
613
	                // Define size of image if we need it
614
	                $imglinesize = array();
615
	                if (!empty($realpatharray[$i])) $imglinesize = pdf_getSizeForImage($realpatharray[$i]);
616
617
	                $pdf->setTopMargin($tab_top_newpage);
618
	                $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext + $heightforinfotot); // The only function to edit the bottom margin of current page to set it.
619
	                $pageposbefore = $pdf->getPage();
620
621
	                $showpricebeforepagebreak = 1;
622
	                $posYAfterImage = 0;
623
624
	                if ($this->getColumnStatus('photo'))
625
	                {
626
    	                // We start with Photo of product line
627
    	                if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot)))	// If photo too high, we moved completely on new page
628
    	                {
629
    	                    $pdf->AddPage('', '', true);
630
    	                    if (!empty($tplidx)) $pdf->useTemplate($tplidx);
631
    	                    $pdf->setPage($pageposbefore + 1);
632
633
    	                    $curY = $tab_top_newpage;
634
635
							// Allows data in the first page if description is long enough to break in multiples pages
636
							if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE))
637
								$showpricebeforepagebreak = 1;
638
							else
639
								$showpricebeforepagebreak = 0;
640
    	                }
641
642
    	                if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height']))
643
    	                {
644
    	                    $pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi
645
    	                    // $pdf->Image does not increase value return by getY, so we save it manually
646
    	                    $posYAfterImage = $curY + $imglinesize['height'];
647
    	                }
648
	                }
649
650
	                // Description of product line
651
	                if ($this->getColumnStatus('desc'))
652
	                {
653
    	                $pdf->startTransaction();
654
655
                        $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc);
656
    	                $pageposafter = $pdf->getPage();
657
658
    	                if ($pageposafter > $pageposbefore)	// There is a pagebreak
659
    	                {
660
    	                    $pdf->rollbackTransaction(true);
661
    	                    $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
662
663
                            $this->printColDescContent($pdf, $curY, 'desc', $object, $i, $outputlangs, $hideref, $hidedesc);
664
665
    	                    $pageposafter = $pdf->getPage();
666
    	                    $posyafter = $pdf->GetY();
667
    	                    //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit;
668
    	                    if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot)))	// There is no space left for total+free text
669
    	                    {
670
    	                        if ($i == ($nblines - 1))	// No more lines, and no space left to show total, so we create a new page
671
    	                        {
672
    	                            $pdf->AddPage('', '', true);
673
    	                            if (!empty($tplidx)) $pdf->useTemplate($tplidx);
674
    	                            $pdf->setPage($pageposafter + 1);
675
    	                        }
676
    	                    }
677
    	                    else
678
    	                    {
679
    	                        // We found a page break
680
								// Allows data in the first page if description is long enough to break in multiples pages
681
								if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE))
682
									$showpricebeforepagebreak = 1;
683
								else
684
									$showpricebeforepagebreak = 0;
685
    	                    }
686
    	                }
687
    	                else	// No pagebreak
688
    	                {
689
    	                    $pdf->commitTransaction();
690
    	                }
691
	                }
692
693
                    $nexY = $pdf->GetY();
694
	                $pageposafter = $pdf->getPage();
695
	                $pdf->setPage($pageposbefore);
696
	                $pdf->setTopMargin($this->marge_haute);
697
	                $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
698
699
	                // We suppose that a too long description or photo were moved completely on next page
700
	                if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
701
	                    $pdf->setPage($pageposafter); $curY = $tab_top_newpage;
702
	                }
703
704
	                $pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par defaut
705
706
	                // VAT Rate
707
	                if ($this->getColumnStatus('vat'))
708
	                {
709
	                    $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
710
	                    $this->printStdColumnContent($pdf, $curY, 'vat', $vat_rate);
711
	                    $nexY = max($pdf->GetY(), $nexY);
712
	                }
713
714
	                // Unit price before discount
715
	                if ($this->getColumnStatus('subprice'))
716
	                {
717
	                    $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);
718
	                    $this->printStdColumnContent($pdf, $curY, 'subprice', $up_excl_tax);
719
	                    $nexY = max($pdf->GetY(), $nexY);
720
	                }
721
722
	                // Quantity
723
	                // Enough for 6 chars
724
	                if ($this->getColumnStatus('qty'))
725
	                {
726
	                    $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
727
	                    $this->printStdColumnContent($pdf, $curY, 'qty', $qty);
728
	                    $nexY = max($pdf->GetY(), $nexY);
729
	                }
730
731
	                // Situation progress
732
	                if ($this->getColumnStatus('progress'))
733
	                {
734
	                    $progress = pdf_getlineprogress($object, $i, $outputlangs, $hidedetails);
735
	                    $this->printStdColumnContent($pdf, $curY, 'progress', $progress);
736
	                    $nexY = max($pdf->GetY(), $nexY);
737
	                }
738
739
	                // Unit
740
	                if ($this->getColumnStatus('unit'))
741
	                {
742
	                    $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager);
743
	                    $this->printStdColumnContent($pdf, $curY, 'unit', $unit);
744
	                    $nexY = max($pdf->GetY(), $nexY);
745
	                }
746
747
	                // Discount on line
748
	                if ($this->getColumnStatus('discount') && $object->lines[$i]->remise_percent)
749
	                {
750
	                    $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);
751
	                    $this->printStdColumnContent($pdf, $curY, 'discount', $remise_percent);
752
	                    $nexY = max($pdf->GetY(), $nexY);
753
	                }
754
755
	                // Total HT line
756
	                if ($this->getColumnStatus('totalexcltax'))
757
	                {
758
	                    $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails);
759
	                    $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax);
760
	                    $nexY = max($pdf->GetY(), $nexY);
761
	                }
762
763
                    // Extrafields
764
	                if (!empty($object->lines[$i]->array_options)) {
765
	                    foreach ($object->lines[$i]->array_options as $extrafieldColKey => $extrafieldValue) {
766
                            if ($this->getColumnStatus($extrafieldColKey))
767
                            {
768
                                $extrafieldValue = $this->getExtrafieldContent($object->lines[$i], $extrafieldColKey);
769
                                $this->printStdColumnContent($pdf, $curY, $extrafieldColKey, $extrafieldValue);
770
                                $nexY = max($pdf->GetY(), $nexY);
771
                            }
772
                        }
773
                    }
774
775
776
	                $parameters = array(
777
	                    'object' => $object,
778
	                    'i' => $i,
779
	                    'pdf' =>& $pdf,
780
	                    'curY' =>& $curY,
781
	                    'nexY' =>& $nexY,
782
	                    'outputlangs' => $outputlangs,
783
	                    'hidedetails' => $hidedetails
784
	                );
785
	                $reshook = $hookmanager->executeHooks('printPDFline', $parameters, $this); // Note that $object may have been modified by hook
786
787
788
	                $sign = 1;
789
	                if (isset($object->type) && $object->type == 2 && !empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign = -1;
790
	                // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva
791
	                $prev_progress = $object->lines[$i]->get_prev_progress($object->id);
792
	                if ($prev_progress > 0 && !empty($object->lines[$i]->situation_percent)) // Compute progress from previous situation
793
	                {
794
	                    if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent;
795
	                    else $tvaligne = $sign * $object->lines[$i]->total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent;
796
	                } else {
797
	                    if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva;
798
	                    else $tvaligne = $sign * $object->lines[$i]->total_tva;
799
	                }
800
801
	                $localtax1ligne = $object->lines[$i]->total_localtax1;
802
	                $localtax2ligne = $object->lines[$i]->total_localtax2;
803
	                $localtax1_rate = $object->lines[$i]->localtax1_tx;
804
	                $localtax2_rate = $object->lines[$i]->localtax2_tx;
805
	                $localtax1_type = $object->lines[$i]->localtax1_type;
806
	                $localtax2_type = $object->lines[$i]->localtax2_type;
807
808
	                if ($object->remise_percent) $tvaligne -= ($tvaligne * $object->remise_percent) / 100;
809
	                if ($object->remise_percent) $localtax1ligne -= ($localtax1ligne * $object->remise_percent) / 100;
810
	                if ($object->remise_percent) $localtax2ligne -= ($localtax2ligne * $object->remise_percent) / 100;
811
812
	                $vatrate = (string) $object->lines[$i]->tva_tx;
813
814
	                // Retrieve type from database for backward compatibility with old records
815
	                if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined
816
	                    && (!empty($localtax1_rate) || !empty($localtax2_rate))) // and there is local tax
817
	                {
818
	                    $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $object->thirdparty, $mysoc);
819
	                    $localtax1_type = $localtaxtmp_array[0];
820
	                    $localtax2_type = $localtaxtmp_array[2];
821
	                }
822
823
	                // retrieve global local tax
824
                    if ($localtax1_type && $localtax1ligne != 0) {
825
                        $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne;
826
                    }
827
                    if ($localtax2_type && $localtax2ligne != 0) {
828
                        $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne;
829
                    }
830
831
                    if (($object->lines[$i]->info_bits & 0x01) == 0x01) $vatrate .= '*';
832
                    if (!isset($this->tva[$vatrate])) 				$this->tva[$vatrate] = 0;
833
                    $this->tva[$vatrate] += $tvaligne;
834
835
                    $nexY = max($nexY, $posYAfterImage);
836
837
                    // Add line
838
                    if (!empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblines - 1)) {
839
                        $pdf->setPage($pageposafter);
840
                        $pdf->SetLineStyle(array('dash'=>'1,1', 'color'=>array(80, 80, 80)));
841
                        //$pdf->SetDrawColor(190,190,200);
842
                        $pdf->line($this->marge_gauche, $nexY, $this->page_largeur - $this->marge_droite, $nexY);
843
                        $pdf->SetLineStyle(array('dash'=>0));
844
                    }
845
846
                    // Detect if some page were added automatically and output _tableau for past pages
847
                    while ($pagenb < $pageposafter) {
848
                        $pdf->setPage($pagenb);
849
                        if ($pagenb == $pageposbeforeprintlines) {
850
                            $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code, $outputlangsbis);
851
                        }
852
                        else
853
                        {
854
                        	$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code, $outputlangsbis);
855
                        }
856
                        $this->_pagefoot($pdf, $object, $outputlangs, 1);
857
                        $pagenb++;
858
                        $pdf->setPage($pagenb);
859
                        $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
860
                        if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
861
                    }
862
863
                    if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) {
864
                        if ($pagenb == $pageposafter) {
865
                        	$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code, $outputlangsbis);
866
                        }
867
                        else
868
                        {
869
                        	$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code, $outputlangsbis);
870
                        }
871
                        $this->_pagefoot($pdf, $object, $outputlangs, 1);
872
                        // New page
873
                        $pdf->AddPage();
874
                        if (!empty($tplidx)) $pdf->useTemplate($tplidx);
875
                        $pagenb++;
876
                        if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
877
                    }
878
	            }
879
880
	            // Show square
881
	            if ($pagenb == $pageposbeforeprintlines)
882
	            {
883
	            	$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, $hidetop, 0, $object->multicurrency_code, $outputlangsbis);
884
	                $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
885
	            }
886
	            else
887
	            {
888
	            	$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code, $outputlangsbis);
889
	                $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
890
	            }
891
892
	            // Display infos area
893
	            $posy = $this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs);
894
895
	            // Display total zone
896
	            $posy = $this->drawTotalTable($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs);
897
898
	            // Display payment area
899
	            if (($deja_regle || $amount_credit_notes_included || $amount_deposits_included) && empty($conf->global->INVOICE_NO_PAYMENT_DETAILS))
900
	            {
901
	                $posy = $this->drawPaymentsTable($pdf, $object, $posy, $outputlangs);
902
	            }
903
904
	            // Pagefoot
905
	            $this->_pagefoot($pdf, $object, $outputlangs);
906
	            if (method_exists($pdf, 'AliasNbPages')) $pdf->AliasNbPages();
907
908
	            $pdf->Close();
909
910
	            $pdf->Output($file, 'F');
911
912
	            // Add pdfgeneration hook
913
	            $hookmanager->initHooks(array('pdfgeneration'));
914
	            $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
915
	            global $action;
916
	            $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
917
	            if ($reshook < 0)
918
	            {
919
	                $this->error = $hookmanager->error;
920
	                $this->errors = $hookmanager->errors;
921
	            }
922
923
	            if (!empty($conf->global->MAIN_UMASK))
924
	                @chmod($file, octdec($conf->global->MAIN_UMASK));
925
926
	                $this->result = array('fullpath'=>$file);
927
928
	                return 1; // No error
929
	        }
930
	        else
931
	        {
932
	            $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
933
	            return 0;
934
	        }
935
	    }
936
	    else
937
	    {
938
	        $this->error = $langs->transnoentities("ErrorConstantNotDefined", "FAC_OUTPUTDIR");
939
	        return 0;
940
	    }
941
	}
942
943
944
	/**
945
	 *  Show payments table
946
	 *
947
     *  @param	PDF			$pdf           Object PDF
948
     *  @param  Object		$object         Object invoice
949
     *  @param  int			$posy           Position y in PDF
950
     *  @param  Translate	$outputlangs    Object langs for output
951
     *  @return int             			<0 if KO, >0 if OK
952
	 */
953
	public function drawPaymentsTable(&$pdf, $object, $posy, $outputlangs)
954
	{
955
		global $conf;
956
957
        $sign = 1;
958
        if ($object->type == 2 && !empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign = -1;
959
960
        $tab3_posx = 120;
961
		$tab3_top = $posy + 8;
962
		$tab3_width = 80;
963
		$tab3_height = 4;
964
		if ($this->page_largeur < 210) // To work with US executive format
965
		{
966
			$tab3_posx -= 20;
967
		}
968
969
		$default_font_size = pdf_getPDFFontSize($outputlangs);
970
971
		$title = $outputlangs->transnoentities("PaymentsAlreadyDone");
972
		if ($object->type == 2) $title = $outputlangs->transnoentities("PaymentsBackAlreadyDone");
973
974
		$pdf->SetFont('', '', $default_font_size - 3);
975
		$pdf->SetXY($tab3_posx, $tab3_top - 4);
976
		$pdf->MultiCell(60, 3, $title, 0, 'L', 0);
977
978
		$pdf->line($tab3_posx, $tab3_top, $tab3_posx + $tab3_width, $tab3_top);
979
980
		$pdf->SetFont('', '', $default_font_size - 4);
981
		$pdf->SetXY($tab3_posx, $tab3_top);
982
		$pdf->MultiCell(20, 3, $outputlangs->transnoentities("Payment"), 0, 'L', 0);
983
		$pdf->SetXY($tab3_posx + 21, $tab3_top);
984
		$pdf->MultiCell(20, 3, $outputlangs->transnoentities("Amount"), 0, 'L', 0);
985
		$pdf->SetXY($tab3_posx + 40, $tab3_top);
986
		$pdf->MultiCell(20, 3, $outputlangs->transnoentities("Type"), 0, 'L', 0);
987
		$pdf->SetXY($tab3_posx + 58, $tab3_top);
988
		$pdf->MultiCell(20, 3, $outputlangs->transnoentities("Num"), 0, 'L', 0);
989
990
		$pdf->line($tab3_posx, $tab3_top - 1 + $tab3_height, $tab3_posx + $tab3_width, $tab3_top - 1 + $tab3_height);
991
992
		$y = 0;
993
994
		$pdf->SetFont('', '', $default_font_size - 4);
995
996
997
		// Loop on each discount available (deposits and credit notes and excess of payment included)
998
		$sql = "SELECT re.rowid, re.amount_ht, re.multicurrency_amount_ht, re.amount_tva, re.multicurrency_amount_tva,  re.amount_ttc, re.multicurrency_amount_ttc,";
999
		$sql .= " re.description, re.fk_facture_source,";
1000
		$sql .= " f.type, f.datef";
1001
		$sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture as f";
1002
		$sql .= " WHERE re.fk_facture_source = f.rowid AND re.fk_facture = ".$object->id;
1003
		$resql = $this->db->query($sql);
1004
		if ($resql)
1005
		{
1006
			$num = $this->db->num_rows($resql);
1007
			$i = 0;
1008
			$invoice = new Facture($this->db);
1009
			while ($i < $num)
1010
			{
1011
				$y += 3;
1012
				$obj = $this->db->fetch_object($resql);
1013
1014
				if ($obj->type == 2) $text = $outputlangs->transnoentities("CreditNote");
1015
				elseif ($obj->type == 3) $text = $outputlangs->transnoentities("Deposit");
1016
				elseif ($obj->type == 0) $text = $outputlangs->transnoentities("ExcessReceived");
1017
				else $text = $outputlangs->transnoentities("UnknownType");
1018
1019
				$invoice->fetch($obj->fk_facture_source);
1020
1021
				$pdf->SetXY($tab3_posx, $tab3_top + $y);
1022
				$pdf->MultiCell(20, 3, dol_print_date($this->db->jdate($obj->datef), 'day', false, $outputlangs, true), 0, 'L', 0);
1023
				$pdf->SetXY($tab3_posx + 21, $tab3_top + $y);
1024
				$pdf->MultiCell(20, 3, price(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $obj->multicurrency_amount_ttc : $obj->amount_ttc, 0, $outputlangs), 0, 'L', 0);
1025
				$pdf->SetXY($tab3_posx + 40, $tab3_top + $y);
1026
				$pdf->MultiCell(20, 3, $text, 0, 'L', 0);
1027
				$pdf->SetXY($tab3_posx + 58, $tab3_top + $y);
1028
				$pdf->MultiCell(20, 3, $invoice->ref, 0, 'L', 0);
1029
1030
				$pdf->line($tab3_posx, $tab3_top + $y + 3, $tab3_posx + $tab3_width, $tab3_top + $y + 3);
1031
1032
				$i++;
1033
			}
1034
		}
1035
		else
1036
		{
1037
			$this->error = $this->db->lasterror();
1038
			return -1;
1039
		}
1040
1041
		// Loop on each payment
1042
		// TODO Call getListOfPaymentsgetListOfPayments instead of hard coded sql
1043
		$sql = "SELECT p.datep as date, p.fk_paiement, p.num_paiement as num, pf.amount as amount, pf.multicurrency_amount,";
1044
		$sql .= " cp.code";
1045
		$sql .= " FROM ".MAIN_DB_PREFIX."paiement_facture as pf, ".MAIN_DB_PREFIX."paiement as p";
1046
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as cp ON p.fk_paiement = cp.id";
1047
		$sql .= " WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = ".$object->id;
1048
		//$sql.= " WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = 1";
1049
		$sql .= " ORDER BY p.datep";
1050
1051
		$resql = $this->db->query($sql);
1052
		if ($resql)
1053
		{
1054
			$num = $this->db->num_rows($resql);
1055
			$i = 0;
1056
			while ($i < $num) {
1057
				$y += 3;
1058
				$row = $this->db->fetch_object($resql);
1059
1060
				$pdf->SetXY($tab3_posx, $tab3_top + $y);
1061
				$pdf->MultiCell(20, 3, dol_print_date($this->db->jdate($row->date), 'day', false, $outputlangs, true), 0, 'L', 0);
1062
				$pdf->SetXY($tab3_posx + 21, $tab3_top + $y);
1063
				$pdf->MultiCell(20, 3, price($sign * (($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $row->multicurrency_amount : $row->amount), 0, $outputlangs), 0, 'L', 0);
1064
				$pdf->SetXY($tab3_posx + 40, $tab3_top + $y);
1065
				$oper = $outputlangs->transnoentitiesnoconv("PaymentTypeShort".$row->code);
1066
1067
				$pdf->MultiCell(20, 3, $oper, 0, 'L', 0);
1068
				$pdf->SetXY($tab3_posx + 58, $tab3_top + $y);
1069
				$pdf->MultiCell(30, 3, $row->num, 0, 'L', 0);
1070
1071
				$pdf->line($tab3_posx, $tab3_top + $y + 3, $tab3_posx + $tab3_width, $tab3_top + $y + 3);
1072
1073
				$i++;
1074
			}
1075
1076
			return $tab3_top + $y + 3;
1077
		}
1078
		else
1079
		{
1080
			$this->error = $this->db->lasterror();
1081
			return -1;
1082
		}
1083
	}
1084
1085
1086
	/**
1087
	 *   Show miscellaneous information (payment mode, payment term, ...)
1088
	 *
1089
	 *   @param		tcpdf			$pdf     		Object PDF
1090
	 *   @param		Object		$object			Object to show
1091
	 *   @param		int			$posy			Y
1092
	 *   @param		Translate	$outputlangs	Langs object
1093
	 *   @return	int							Pos y
1094
	 */
1095
	protected function drawInfoTable(&$pdf, $object, $posy, $outputlangs)
1096
	{
1097
		global $conf, $mysoc;
1098
1099
		$default_font_size = pdf_getPDFFontSize($outputlangs);
1100
1101
		$pdf->SetFont('', '', $default_font_size - 1);
1102
1103
		// If France, show VAT mention if not applicable
1104
		if ($this->emetteur->country_code == 'FR' && empty($mysoc->tva_assuj))
1105
		{
1106
			$pdf->SetFont('', 'B', $default_font_size - 2);
1107
			$pdf->SetXY($this->marge_gauche, $posy);
1108
			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0);
1109
1110
			$posy = $pdf->GetY() + 4;
1111
		}
1112
1113
		$posxval = 52;
1114
1115
		// Show payments conditions
1116
		if ($object->type != 2 && ($object->cond_reglement_code || $object->cond_reglement))
1117
		{
1118
			$pdf->SetFont('', 'B', $default_font_size - 2);
1119
			$pdf->SetXY($this->marge_gauche, $posy);
1120
			$titre = $outputlangs->transnoentities("PaymentConditions").':';
1121
			$pdf->MultiCell(43, 4, $titre, 0, 'L');
1122
1123
			$pdf->SetFont('', '', $default_font_size - 2);
1124
			$pdf->SetXY($posxval, $posy);
1125
			$lib_condition_paiement = $outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code) != ('PaymentCondition'.$object->cond_reglement_code) ? $outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code) : $outputlangs->convToOutputCharset($object->cond_reglement_doc);
1126
			$lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
1127
			$pdf->MultiCell(67, 4, $lib_condition_paiement, 0, 'L');
1128
1129
			$posy = $pdf->GetY() + 3;
1130
		}
1131
1132
		if ($object->type != 2)
1133
		{
1134
			// Check a payment mode is defined
1135
			if (empty($object->mode_reglement_code)
1136
			&& empty($conf->global->FACTURE_CHQ_NUMBER)
1137
			&& empty($conf->global->FACTURE_RIB_NUMBER))
1138
			{
1139
				$this->error = $outputlangs->transnoentities("ErrorNoPaiementModeConfigured");
1140
			}
1141
			// Avoid having any valid PDF with setup that is not complete
1142
			elseif (($object->mode_reglement_code == 'CHQ' && empty($conf->global->FACTURE_CHQ_NUMBER) && empty($object->fk_account) && empty($object->fk_bank))
1143
				|| ($object->mode_reglement_code == 'VIR' && empty($conf->global->FACTURE_RIB_NUMBER) && empty($object->fk_account) && empty($object->fk_bank)))
1144
			{
1145
				$outputlangs->load("errors");
1146
1147
				$pdf->SetXY($this->marge_gauche, $posy);
1148
				$pdf->SetTextColor(200, 0, 0);
1149
				$pdf->SetFont('', 'B', $default_font_size - 2);
1150
				$this->error = $outputlangs->transnoentities("ErrorPaymentModeDefinedToWithoutSetup", $object->mode_reglement_code);
1151
				$pdf->MultiCell(80, 3, $this->error, 0, 'L', 0);
1152
				$pdf->SetTextColor(0, 0, 0);
1153
1154
				$posy = $pdf->GetY() + 1;
1155
			}
1156
1157
			// Show payment mode
1158
			if ($object->mode_reglement_code
1159
			&& $object->mode_reglement_code != 'CHQ'
1160
			&& $object->mode_reglement_code != 'VIR')
1161
			{
1162
				$pdf->SetFont('', 'B', $default_font_size - 2);
1163
				$pdf->SetXY($this->marge_gauche, $posy);
1164
				$titre = $outputlangs->transnoentities("PaymentMode").':';
1165
				$pdf->MultiCell(80, 5, $titre, 0, 'L');
1166
1167
				$pdf->SetFont('', '', $default_font_size - 2);
1168
				$pdf->SetXY($posxval, $posy);
1169
				$lib_mode_reg = $outputlangs->transnoentities("PaymentType".$object->mode_reglement_code) != ('PaymentType'.$object->mode_reglement_code) ? $outputlangs->transnoentities("PaymentType".$object->mode_reglement_code) : $outputlangs->convToOutputCharset($object->mode_reglement);
1170
				$pdf->MultiCell(80, 5, $lib_mode_reg, 0, 'L');
1171
1172
				// Show online payment link
1173
				$useonlinepayment = ((!empty($conf->paypal->enabled) || !empty($conf->stripe->enabled) || !empty($conf->paybox->enabled)) && !empty($conf->global->PDF_SHOW_LINK_TO_ONLINE_PAYMENT));
1174
				if (($object->mode_reglement_code == 'CB' || $object->mode_reglement_code == 'VAD') && $object->statut != Facture::STATUS_DRAFT && $useonlinepayment) {
1175
					require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
1176
					global $langs;
1177
1178
					$langs->loadLangs(array('payment', 'paybox'));
1179
					$servicename = $langs->transnoentities('Online');
1180
					$paiement_url = getOnlinePaymentUrl('', 'invoice', $object->ref, '', '', '');
1181
					$linktopay = $langs->trans("ToOfferALinkForOnlinePayment", $servicename).' <a href="'.$paiement_url.'">'.$outputlangs->transnoentities("ClickHere").'</a>';
1182
1183
					$pdf->writeHTMLCell(80, 10, '', '', dol_htmlentitiesbr($linktopay), 0, 1);
1184
				}
1185
1186
				$posy = $pdf->GetY() + 2;
1187
			}
1188
1189
			// Show payment mode CHQ
1190
			if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ')
1191
			{
1192
				// If payment mode unregulated or payment mode forced to CHQ
1193
				if (!empty($conf->global->FACTURE_CHQ_NUMBER))
1194
				{
1195
					$diffsizetitle = (empty($conf->global->PDF_DIFFSIZE_TITLE) ? 3 : $conf->global->PDF_DIFFSIZE_TITLE);
1196
1197
					if ($conf->global->FACTURE_CHQ_NUMBER > 0)
1198
					{
1199
						$account = new Account($this->db);
1200
						$account->fetch($conf->global->FACTURE_CHQ_NUMBER);
1201
1202
						$pdf->SetXY($this->marge_gauche, $posy);
1203
						$pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1204
						$pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $account->proprio), 0, 'L', 0);
1205
						$posy = $pdf->GetY() + 1;
1206
1207
			            if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS))
1208
			            {
1209
							$pdf->SetXY($this->marge_gauche, $posy);
1210
							$pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1211
							$pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0);
1212
							$posy = $pdf->GetY() + 2;
1213
			            }
1214
					}
1215
					if ($conf->global->FACTURE_CHQ_NUMBER == -1)
1216
					{
1217
						$pdf->SetXY($this->marge_gauche, $posy);
1218
						$pdf->SetFont('', 'B', $default_font_size - $diffsizetitle);
1219
						$pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo', $this->emetteur->name), 0, 'L', 0);
1220
						$posy = $pdf->GetY() + 1;
1221
1222
			            if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS))
1223
			            {
1224
							$pdf->SetXY($this->marge_gauche, $posy);
1225
							$pdf->SetFont('', '', $default_font_size - $diffsizetitle);
1226
							$pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0);
1227
							$posy = $pdf->GetY() + 2;
1228
			            }
1229
					}
1230
				}
1231
			}
1232
1233
			// If payment mode not forced or forced to VIR, show payment with BAN
1234
			if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR')
1235
			{
1236
				if ($object->fk_account > 0 || $object->fk_bank > 0 || !empty($conf->global->FACTURE_RIB_NUMBER)) {
1237
					$bankid = ($object->fk_account <= 0 ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account);
1238
					if ($object->fk_bank > 0) $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank
1239
					$account = new Account($this->db);
1240
					$account->fetch($bankid);
1241
1242
					$curx = $this->marge_gauche;
1243
					$cury = $posy;
1244
1245
					$posy = pdf_bank($pdf, $outputlangs, $curx, $cury, $account, 0, $default_font_size);
1246
1247
					$posy += 2;
1248
				}
1249
			}
1250
		}
1251
1252
		return $posy;
1253
	}
1254
1255
1256
	/**
1257
	 *  Show total to pay
1258
	 *
1259
	 *  @param	TCPDI			$pdf            Object PDF
1260
	 *	@param  Facture		$object         Object invoice
1261
	 *	@param  int			$deja_regle     Amount already paid (in the currency of invoice)
1262
	 *	@param	int			$posy			Position depart
1263
	 *	@param	Translate	$outputlangs	Objet langs
1264
	 *	@return int							Position pour suite
1265
	 */
1266
	protected function drawTotalTable(&$pdf, $object, $deja_regle, $posy, $outputlangs)
1267
	{
1268
		global $conf, $mysoc, $hookmanager;
1269
1270
        $sign = 1;
1271
        if ($object->type == 2 && !empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign = -1;
1272
1273
        $default_font_size = pdf_getPDFFontSize($outputlangs);
1274
1275
		$tab2_top = $posy;
1276
		$tab2_hl = 4;
1277
		$pdf->SetFont('', '', $default_font_size - 1);
1278
1279
		// Total table
1280
		$col1x = 120; $col2x = 170;
1281
		if ($this->page_largeur < 210) // To work with US executive format
1282
		{
1283
			$col2x -= 20;
1284
		}
1285
		$largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
1286
1287
		$useborder = 0;
1288
		$index = 0;
1289
1290
		$outputlangsbis = null;
1291
		if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) {
1292
			$outputlangsbis = new Translate('', $conf);
1293
			$outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE);
1294
			$outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal"));
1295
		}
1296
1297
		// Add trigger to allow to edit $object
1298
		$parameters = array(
1299
			'object' => &$object,
1300
			'outputlangs' => $outputlangs,
1301
		);
1302
		$hookmanager->executeHooks('beforePercentCalculation', $parameters, $this); // Note that $object may have been modified by hook
1303
1304
		// overall percentage of advancement
1305
		$percent = 0;
1306
		$i = 0;
1307
		foreach ($object->lines as $line)
1308
		{
1309
			$percent += $line->situation_percent;
1310
			$i++;
1311
		}
1312
1313
		if (!empty($i)) {
1314
		    $avancementGlobal = $percent / $i;
1315
		}
1316
		else {
1317
		    $avancementGlobal = 0;
1318
		}
1319
1320
		$object->fetchPreviousNextSituationInvoice();
1321
		$TPreviousIncoice = $object->tab_previous_situation_invoice;
1322
1323
		$total_a_payer = 0;
1324
		$total_a_payer_ttc = 0;
1325
		foreach ($TPreviousIncoice as &$fac) {
1326
		    $total_a_payer += $fac->total_ht;
1327
		    $total_a_payer_ttc += $fac->total_ttc;
1328
		}
1329
		$total_a_payer += $object->total_ht;
1330
		$total_a_payer_ttc += $object->total_ttc;
1331
1332
		if (!empty($avancementGlobal)) {
1333
		    $total_a_payer = $total_a_payer * 100 / $avancementGlobal;
1334
		    $total_a_payer_ttc = $total_a_payer_ttc * 100 / $avancementGlobal;
1335
		}
1336
		else {
1337
		    $total_a_payer = 0;
1338
		    $total_a_payer_ttc = 0;
1339
		}
1340
1341
		$i = 1;
1342
		if (!empty($TPreviousIncoice)) {
1343
		    $pdf->setY($tab2_top);
1344
		    $posy = $pdf->GetY();
1345
1346
		    foreach ($TPreviousIncoice as &$fac) {
1347
		        if ($posy > $this->page_hauteur - 4) {
1348
		            $this->_pagefoot($pdf, $object, $outputlangs, 1);
1349
		            $pdf->addPage();
1350
		            $pdf->setY($this->marge_haute);
1351
		            $posy = $pdf->GetY();
1352
		        }
1353
1354
		        // cumul TVA précédent
1355
		        $index++;
1356
		        $pdf->SetFillColor(255, 255, 255);
1357
		        $pdf->SetXY($col1x, $posy);
1358
		        $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("PDFSituationTitle", $fac->situation_counter).' '.$outputlangs->transnoentities("TotalHT"), 0, 'L', 1);
1359
1360
		        $pdf->SetXY($col2x, $posy);
1361
1362
		        $facSign = '';
1363
		        if ($i > 1) {
1364
		            $facSign = $fac->total_ht >= 0 ? '+' : '';
1365
		        }
1366
1367
		        $displayAmount = ' '.$facSign.' '.price($fac->total_ht, 0, $outputlangs);
1368
1369
		        $pdf->MultiCell($largcol2, $tab2_hl, $displayAmount, 0, 'R', 1);
1370
1371
		        $i++;
1372
		        $posy += $tab2_hl;
1373
1374
		        $pdf->setY($posy);
1375
		    }
1376
1377
		    // Display current total
1378
		    $pdf->SetFillColor(255, 255, 255);
1379
		    $pdf->SetXY($col1x, $posy);
1380
		    $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("PDFSituationTitle", $object->situation_counter).' '.$outputlangs->transnoentities("TotalHT"), 0, 'L', 1);
1381
1382
		    $pdf->SetXY($col2x, $posy);
1383
		    $facSign = '';
1384
		    if ($i > 1) {
1385
		        $facSign = $object->total_ht >= 0 ? '+' : ''; // management of a particular customer case
1386
		    }
1387
1388
		    if ($fac->type === facture::TYPE_CREDIT_NOTE) {
1389
		        $facSign = '-'; // les avoirs
1390
		    }
1391
1392
1393
		    $displayAmount = ' '.$facSign.' '.price($object->total_ht, 0, $outputlangs);
1394
		    $pdf->MultiCell($largcol2, $tab2_hl, $displayAmount, 0, 'R', 1);
1395
1396
		    $posy += $tab2_hl;
1397
1398
		    // Display all total
1399
		    $pdf->SetFont('', '', $default_font_size - 1);
1400
		    $pdf->SetFillColor(255, 255, 255);
1401
		    $pdf->SetXY($col1x, $posy);
1402
		    $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("SituationTotalProgress", $avancementGlobal), 0, 'L', 1);
1403
1404
		    $pdf->SetXY($col2x, $posy);
1405
		    $pdf->MultiCell($largcol2, $tab2_hl, price($total_a_payer * $avancementGlobal / 100, 0, $outputlangs), 0, 'R', 1);
1406
		    $pdf->SetFont('', '', $default_font_size - 2);
1407
1408
		    $posy += $tab2_hl;
1409
1410
		    if ($posy > $this->page_hauteur - 4) {
1411
		        $pdf->addPage();
1412
		        $pdf->setY($this->marge_haute);
1413
		        $posy = $pdf->GetY();
1414
		    }
1415
1416
		    $tab2_top = $posy;
1417
		    $index = 0;
1418
		}
1419
1420
		$tab2_top += 3;
1421
1422
		// Get Total HT
1423
		$total_ht = ($conf->multicurrency->enabled && $object->mylticurrency_tx != 1 ? $object->multicurrency_total_ht : $object->total_ht);
1424
1425
		// Total remise
1426
		$total_line_remise = 0;
1427
		foreach ($object->lines as $i => $line) {
1428
		    $total_line_remise += pdfGetLineTotalDiscountAmount($object, $i, $outputlangs, 2); // TODO: add this methode to core/lib/pdf.lib
1429
		    // Gestion remise sous forme de ligne négative
1430
		    if ($line->total_ht < 0) $total_line_remise += -$line->total_ht;
1431
		}
1432
		if ($total_line_remise > 0) {
1433
		    if (!empty($conf->global->MAIN_SHOW_AMOUNT_DISCOUNT)) {
1434
		        $pdf->SetFillColor(255, 255, 255);
1435
		        $pdf->SetXY($col1x, $tab2_top + $tab2_hl);
1436
		        $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalDiscount").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("TotalDiscount") : ''), 0, 'L', 1);
1437
		        $pdf->SetXY($col2x, $tab2_top + $tab2_hl);
1438
		        $pdf->MultiCell($largcol2, $tab2_hl, price($total_line_remise, 0, $outputlangs), 0, 'R', 1);
1439
1440
		        $index++;
1441
		    }
1442
		    // Show total NET before discount
1443
		    if (!empty($conf->global->MAIN_SHOW_AMOUNT_BEFORE_DISCOUNT)) {
1444
		        $pdf->SetFillColor(255, 255, 255);
1445
		        $pdf->SetXY($col1x, $tab2_top + 0);
1446
		        $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHTBeforeDiscount").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("TotalHTBeforeDiscount") : ''), 0, 'L', 1);
1447
                $pdf->SetXY($col2x, $tab2_top + 0);
1448
		        $pdf->MultiCell($largcol2, $tab2_hl, price($total_line_remise + $total_ht, 0, $outputlangs), 0, 'R', 1);
1449
1450
		        $index++;
1451
		    }
1452
		}
1453
1454
		// Total HT
1455
		$pdf->SetFillColor(255, 255, 255);
1456
		$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1457
		$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("TotalHT") : ''), 0, 'L', 1);
1458
1459
		$total_ht = (($conf->multicurrency->enabled && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht);
1460
		$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1461
		$pdf->MultiCell($largcol2, $tab2_hl, price($sign * ($total_ht + (!empty($object->remise) ? $object->remise : 0)), 0, $outputlangs), 0, 'R', 1);
1462
1463
		// Show VAT by rates and total
1464
		$pdf->SetFillColor(248, 248, 248);
1465
1466
		$total_ttc = ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
1467
1468
		$this->atleastoneratenotnull = 0;
1469
		if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT))
1470
		{
1471
			$tvaisnull = ((!empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false);
1472
			if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull)
1473
			{
1474
				// Nothing to do
1475
			}
1476
			else
1477
			{
1478
			    // FIXME amount of vat not supported with multicurrency
1479
1480
				//Local tax 1 before VAT
1481
				//if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1482
				//{
1483
				foreach ($this->localtax1 as $localtax_type => $localtax_rate)
1484
				{
1485
					if (in_array((string) $localtax_type, array('1', '3', '5'))) continue;
1486
1487
					foreach ($localtax_rate as $tvakey => $tvaval)
1488
					{
1489
						if ($tvakey != 0)    // On affiche pas taux 0
1490
						{
1491
							//$this->atleastoneratenotnull++;
1492
1493
							$index++;
1494
							$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1495
1496
							$tvacompl = '';
1497
							if (preg_match('/\*/', $tvakey))
1498
							{
1499
								$tvakey = str_replace('*', '', $tvakey);
1500
								$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1501
							}
1502
1503
							$totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : '');
1504
							$totalvat .= ' ';
1505
							$totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1506
							$pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1507
1508
							$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1509
							$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1510
						}
1511
					}
1512
				}
1513
	      		//}
1514
				//Local tax 2 before VAT
1515
				//if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1516
				//{
1517
				foreach ($this->localtax2 as $localtax_type => $localtax_rate)
1518
				{
1519
					if (in_array((string) $localtax_type, array('1', '3', '5'))) continue;
1520
1521
					foreach ($localtax_rate as $tvakey => $tvaval)
1522
					{
1523
						if ($tvakey != 0)    // On affiche pas taux 0
1524
						{
1525
							//$this->atleastoneratenotnull++;
1526
1527
							$index++;
1528
							$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1529
1530
							$tvacompl = '';
1531
							if (preg_match('/\*/', $tvakey))
1532
							{
1533
								$tvakey = str_replace('*', '', $tvakey);
1534
								$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1535
							}
1536
							$totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : '');
1537
							$totalvat .= ' ';
1538
							$totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1539
							$pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1540
1541
							$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1542
							$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1543
						}
1544
					}
1545
				}
1546
                //}
1547
1548
				// VAT
1549
				// Situations totals migth be wrong on huge amounts
1550
				if ($object->situation_cycle_ref && $object->situation_counter > 1) {
1551
					$sum_pdf_tva = 0;
1552
					foreach ($this->tva as $tvakey => $tvaval) {
1553
						$sum_pdf_tva += $tvaval; // sum VAT amounts to compare to object
1554
					}
1555
1556
					if ($sum_pdf_tva != $object->total_tva) { // apply coef to recover the VAT object amount (the good one)
1557
					    if (!empty($sum_pdf_tva))
1558
					    {
1559
							$coef_fix_tva = $object->total_tva / $sum_pdf_tva;
1560
					    }
1561
					    else {
1562
					        $coef_fix_tva = 1;
1563
					    }
1564
1565
1566
						foreach ($this->tva as $tvakey => $tvaval) {
1567
							$this->tva[$tvakey] = $tvaval * $coef_fix_tva;
1568
						}
1569
					}
1570
				}
1571
1572
				foreach ($this->tva as $tvakey => $tvaval)
1573
				{
1574
					if ($tvakey != 0)    // On affiche pas taux 0
1575
					{
1576
						$this->atleastoneratenotnull++;
1577
1578
						$index++;
1579
						$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1580
1581
						$tvacompl = '';
1582
						if (preg_match('/\*/', $tvakey))
1583
						{
1584
							$tvakey = str_replace('*', '', $tvakey);
1585
							$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1586
						}
1587
						$totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalVAT", $mysoc->country_code) : '');
1588
						$totalvat .= ' ';
1589
						$totalvat .= vatrate($tvakey, 1).$tvacompl;
1590
						$pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1591
1592
						$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1593
						$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1594
					}
1595
				}
1596
1597
				//Local tax 1 after VAT
1598
				//if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
1599
				//{
1600
				foreach ($this->localtax1 as $localtax_type => $localtax_rate)
1601
				{
1602
					if (in_array((string) $localtax_type, array('2', '4', '6'))) continue;
1603
1604
					foreach ($localtax_rate as $tvakey => $tvaval)
1605
					{
1606
						if ($tvakey != 0)    // On affiche pas taux 0
1607
						{
1608
							//$this->atleastoneratenotnull++;
1609
1610
							$index++;
1611
							$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1612
1613
							$tvacompl = '';
1614
							if (preg_match('/\*/', $tvakey))
1615
							{
1616
								$tvakey = str_replace('*', '', $tvakey);
1617
								$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1618
							}
1619
							$totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : '');
1620
							$totalvat .= ' ';
1621
							$totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1622
1623
							$pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1624
							$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1625
							$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1626
						}
1627
					}
1628
				}
1629
	      		//}
1630
				//Local tax 2 after VAT
1631
				//if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
1632
				//{
1633
				foreach ($this->localtax2 as $localtax_type => $localtax_rate)
1634
				{
1635
					if (in_array((string) $localtax_type, array('2', '4', '6'))) continue;
1636
1637
					foreach ($localtax_rate as $tvakey => $tvaval)
1638
					{
1639
					    // retrieve global local tax
1640
						if ($tvakey != 0)    // On affiche pas taux 0
1641
						{
1642
							//$this->atleastoneratenotnull++;
1643
1644
							$index++;
1645
							$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1646
1647
							$tvacompl = '';
1648
							if (preg_match('/\*/', $tvakey))
1649
							{
1650
								$tvakey = str_replace('*', '', $tvakey);
1651
								$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1652
							}
1653
							$totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : '');
1654
							$totalvat .= ' ';
1655
1656
							$totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
1657
							$pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1658
1659
							$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1660
							$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1661
						}
1662
					}
1663
				}
1664
1665
1666
				// Revenue stamp
1667
				if (price2num($object->revenuestamp) != 0)
1668
				{
1669
					$index++;
1670
					$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1671
					$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RevenueStamp").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("RevenueStamp", $mysoc->country_code) : ''), $useborder, 'L', 1);
1672
1673
					$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1674
					$pdf->MultiCell($largcol2, $tab2_hl, price($sign * $object->revenuestamp), $useborder, 'R', 1);
1675
				}
1676
1677
				// Total TTC
1678
				$index++;
1679
				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1680
				$pdf->SetTextColor(0, 0, 60);
1681
				$pdf->SetFillColor(224, 224, 224);
1682
				$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("TotalTTC") : ''), $useborder, 'L', 1);
1683
1684
				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1685
				$pdf->MultiCell($largcol2, $tab2_hl, price($sign * $total_ttc, 0, $outputlangs), $useborder, 'R', 1);
1686
1687
1688
1689
1690
				// Retained warranty
1691
				if ($object->displayRetainedWarranty())
1692
				{
1693
					$pdf->SetTextColor(40, 40, 40);
1694
					$pdf->SetFillColor(255, 255, 255);
1695
1696
					$retainedWarranty = $object->getRetainedWarrantyAmount();
1697
					$billedWithRetainedWarranty = $object->total_ttc - $retainedWarranty;
1698
1699
					// Billed - retained warranty
1700
					$index++;
1701
					$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1702
					$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("ToPayOn", dol_print_date($object->date_lim_reglement, 'day')), $useborder, 'L', 1);
1703
1704
					$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1705
					$pdf->MultiCell($largcol2, $tab2_hl, price($billedWithRetainedWarranty), $useborder, 'R', 1);
1706
1707
					// retained warranty
1708
					$index++;
1709
					$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1710
1711
					$retainedWarrantyToPayOn = $outputlangs->transnoentities("RetainedWarranty").' ('.$object->retained_warranty.'%)';
1712
					$retainedWarrantyToPayOn .= !empty($object->retained_warranty_date_limit) ? ' '.$outputlangs->transnoentities("toPayOn", dol_print_date($object->retained_warranty_date_limit, 'day')) : '';
1713
1714
					$pdf->MultiCell($col2x - $col1x, $tab2_hl, $retainedWarrantyToPayOn, $useborder, 'L', 1);
1715
					$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1716
					$pdf->MultiCell($largcol2, $tab2_hl, price($retainedWarranty), $useborder, 'R', 1);
1717
				}
1718
			}
1719
		}
1720
1721
		$pdf->SetTextColor(0, 0, 0);
1722
1723
		$creditnoteamount = $object->getSumCreditNotesUsed(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0); // Warning, this also include excess received
1724
		$depositsamount = $object->getSumDepositsUsed(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0);
1725
1726
		$resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT');
1727
		if (!empty($object->paye)) $resteapayer = 0;
1728
1729
		if (($deja_regle > 0 || $creditnoteamount > 0 || $depositsamount > 0) && empty($conf->global->INVOICE_NO_PAYMENT_DETAILS))
1730
		{
1731
			// Already paid + Deposits
1732
			$index++;
1733
			$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1734
			$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("Paid").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("Paid") : ''), 0, 'L', 0);
1735
			$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1736
			$pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle + $depositsamount, 0, $outputlangs), 0, 'R', 0);
1737
1738
			// Credit note
1739
			if ($creditnoteamount)
1740
			{
1741
				$labeltouse = ($outputlangs->transnoentities("CreditNotesOrExcessReceived") != "CreditNotesOrExcessReceived") ? $outputlangs->transnoentities("CreditNotesOrExcessReceived") : $outputlangs->transnoentities("CreditNotes");
1742
				$labeltouse .= (is_object($outputlangsbis) ? ' / '.($outputlangsbis->transnoentities("CreditNotesOrExcessReceived") != "CreditNotesOrExcessReceived") ? $outputlangsbis->transnoentities("CreditNotesOrExcessReceived") : $outputlangsbis->transnoentities("CreditNotes") : '');
1743
				$index++;
1744
				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1745
				$pdf->MultiCell($col2x - $col1x, $tab2_hl, $labeltouse, 0, 'L', 0);
1746
				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1747
				$pdf->MultiCell($largcol2, $tab2_hl, price($creditnoteamount, 0, $outputlangs), 0, 'R', 0);
1748
			}
1749
1750
			// Escompte
1751
			if ($object->close_code == Facture::CLOSECODE_DISCOUNTVAT)
1752
			{
1753
				$index++;
1754
				$pdf->SetFillColor(255, 255, 255);
1755
1756
				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1757
				$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("EscompteOfferedShort").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("EscompteOfferedShort") : ''), $useborder, 'L', 1);
1758
				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1759
				$pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 0, $outputlangs), $useborder, 'R', 1);
1760
1761
				$resteapayer = 0;
1762
			}
1763
1764
			$index++;
1765
			$pdf->SetTextColor(0, 0, 60);
1766
			$pdf->SetFillColor(224, 224, 224);
1767
			$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1768
			$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities("RemainderToPay") : ''), $useborder, 'L', 1);
1769
			$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1770
			$pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1);
1771
1772
			$pdf->SetFont('', '', $default_font_size - 1);
1773
			$pdf->SetTextColor(0, 0, 0);
1774
		}
1775
1776
		$index++;
1777
		return ($tab2_top + ($tab2_hl * $index));
1778
	}
1779
1780
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1781
	/**
1782
	 *  Return list of active generation modules
1783
	 *
1784
	 *  @param	DoliDB	$db     			Database handler
1785
	 *  @param  integer	$maxfilenamelength  Max length of value to show
1786
	 *  @return	array						List of templates
1787
	 */
1788
	public static function liste_modeles($db, $maxfilenamelength = 0)
1789
	{
1790
		// phpcs:enable
1791
		return parent::liste_modeles($db, $maxfilenamelength); // TODO: Change the autogenerated stub
1792
	}
1793
1794
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1795
	/**
1796
	 *   Show table for lines
1797
	 *
1798
	 *   @param		tcpdf			$pdf     		Object PDF
1799
	 *   @param		string		$tab_top		Top position of table
1800
	 *   @param		string		$tab_height		Height of table (rectangle)
1801
	 *   @param		int			$nexY			Y (not used)
1802
	 *   @param		Translate	$outputlangs	Langs object
1803
	 *   @param		int			$hidetop		1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title
1804
	 *   @param		int			$hidebottom		Hide bottom bar of array
1805
	 *   @param		string		$currency		Currency code
1806
	 *   @param		Translate	$outputlangsbis	Langs object bis
1807
	 *   @return	void
1808
	 */
1809
	protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '', $outputlangsbis = null)
1810
	{
1811
		global $conf;
1812
1813
		// Force to disable hidetop and hidebottom
1814
		$hidebottom = 0;
1815
		if ($hidetop) $hidetop = -1;
1816
1817
		$currency = !empty($currency) ? $currency : $conf->currency;
1818
		$default_font_size = pdf_getPDFFontSize($outputlangs);
1819
1820
		// Amount in (at tab_top - 1)
1821
		$pdf->SetTextColor(0, 0, 0);
1822
		$pdf->SetFont('', '', $default_font_size - 2);
1823
1824
		if (empty($hidetop))
1825
		{
1826
			$titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
1827
			if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {
1828
				$titre .= ' - '.$outputlangsbis->transnoentities("AmountInCurrency", $outputlangsbis->transnoentitiesnoconv("Currency".$currency));
1829
			}
1830
1831
			$pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
1832
			$pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
1833
1834
			//$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
1835
			if (!empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) {
1836
				$pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite - $this->marge_gauche, $this->tabTitleHeight, 'F', null, explode(',', $conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR));
1837
			}
1838
		}
1839
1840
		$pdf->SetDrawColor(128, 128, 128);
1841
		$pdf->SetFont('', '', $default_font_size - 1);
1842
1843
		// Output Rect
1844
		$this->printRect($pdf, $this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $tab_height, $hidetop, $hidebottom); // Rect takes a length in 3rd parameter and 4th parameter
1845
1846
1847
		$this->pdfTabTitles($pdf, $tab_top, $tab_height, $outputlangs, $hidetop);
1848
1849
		if (empty($hidetop)) {
1850
		    $pdf->line($this->marge_gauche, $tab_top + $this->tabTitleHeight, $this->page_largeur - $this->marge_droite, $tab_top + $this->tabTitleHeight); // line takes a position y in 2nd parameter and 4th parameter
1851
		}
1852
	}
1853
1854
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1855
	/**
1856
	 *  Show top header of page.
1857
	 *
1858
	 *  @param	Tcpdf			$pdf     		Object PDF
1859
	 *  @param  Object		$object     	Object to show
1860
	 *  @param  int	    	$showaddress    0=no, 1=yes
1861
	 *  @param  Translate	$outputlangs	Object lang for output
1862
	 *  @param  Translate	$outputlangsbis	Object lang for output bis
1863
	 *  @return	void
1864
	 */
1865
	protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null)
1866
	{
1867
		global $conf, $langs;
1868
1869
		// Load traductions files required by page
1870
		$outputlangs->loadLangs(array("main", "bills", "propal", "companies"));
1871
1872
		$default_font_size = pdf_getPDFFontSize($outputlangs);
1873
1874
		pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
1875
1876
		// Show Draft Watermark
1877
		if ($object->statut == Facture::STATUS_DRAFT && (!empty($conf->global->FACTURE_DRAFT_WATERMARK)))
1878
        {
1879
		      pdf_watermark($pdf, $outputlangs, $this->page_hauteur, $this->page_largeur, 'mm', $conf->global->FACTURE_DRAFT_WATERMARK);
1880
        }
1881
1882
		$pdf->SetTextColor(0, 0, 60);
1883
		$pdf->SetFont('', 'B', $default_font_size + 3);
1884
1885
		$w = 110;
1886
1887
		$posy = $this->marge_haute;
1888
        $posx = $this->page_largeur - $this->marge_droite - $w;
1889
1890
		$pdf->SetXY($this->marge_gauche, $posy);
1891
1892
		// Logo
1893
		if (empty($conf->global->PDF_DISABLE_MYCOMPANY_LOGO))
1894
		{
1895
			if ($this->emetteur->logo)
1896
			{
1897
				$logodir = $conf->mycompany->dir_output;
1898
				if (!empty($conf->mycompany->multidir_output[$object->entity])) $logodir = $conf->mycompany->multidir_output[$object->entity];
1899
				if (empty($conf->global->MAIN_PDF_USE_LARGE_LOGO))
1900
				{
1901
					$logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
1902
				}
1903
				else {
1904
					$logo = $logodir.'/logos/'.$this->emetteur->logo;
1905
				}
1906
				if (is_readable($logo))
1907
				{
1908
				    $height = pdf_getHeightForLogo($logo);
1909
					$pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
1910
				}
1911
				else
1912
				{
1913
					$pdf->SetTextColor(200, 0, 0);
1914
					$pdf->SetFont('', 'B', $default_font_size - 2);
1915
					$pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
1916
					$pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
1917
				}
1918
			}
1919
			else
1920
			{
1921
				$text = $this->emetteur->name;
1922
				$pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
1923
			}
1924
		}
1925
1926
		$pdf->SetFont('', 'B', $default_font_size + 3);
1927
		$pdf->SetXY($posx, $posy);
1928
		$pdf->SetTextColor(0, 0, 60);
1929
		$title = $outputlangs->transnoentities("PdfInvoiceTitle");
1930
		if ($object->type == 1) $title = $outputlangs->transnoentities("InvoiceReplacement");
1931
		if ($object->type == 2) $title = $outputlangs->transnoentities("InvoiceAvoir");
1932
		if ($object->type == 3) $title = $outputlangs->transnoentities("InvoiceDeposit");
1933
		if ($object->type == 4) $title = $outputlangs->transnoentities("InvoiceProForma");
1934
		if ($this->situationinvoice) $title = $outputlangs->transnoentities("InvoiceSituation");
1935
		if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {
1936
			$title .= ' - ';
1937
			if ($object->type == 0) {
1938
				if ($this->situationinvoice) $title .= $outputlangsbis->transnoentities("InvoiceSituation");
1939
				$title .= $outputlangsbis->transnoentities("PdfInvoiceTitle");
1940
			}
1941
			elseif ($object->type == 1) $title .= $outputlangsbis->transnoentities("InvoiceReplacement");
1942
			elseif ($object->type == 2) $title .= $outputlangsbis->transnoentities("InvoiceAvoir");
1943
			elseif ($object->type == 3) $title .= $outputlangsbis->transnoentities("InvoiceDeposit");
1944
			elseif ($object->type == 4) $title .= $outputlangsbis->transnoentities("InvoiceProForma");
1945
		}
1946
		$pdf->MultiCell($w, 3, $title, '', 'R');
1947
1948
		$pdf->SetFont('', 'B', $default_font_size);
1949
1950
		$posy += 5;
1951
		$pdf->SetXY($posx, $posy);
1952
		$pdf->SetTextColor(0, 0, 60);
1953
		$textref = $outputlangs->transnoentities("Ref")." : ".$outputlangs->convToOutputCharset($object->ref);
1954
		if ($object->statut == Facture::STATUS_DRAFT)
1955
		{
1956
			$pdf->SetTextColor(128, 0, 0);
1957
			$textref .= ' - '.$outputlangs->transnoentities("NotValidated");
1958
		}
1959
		$pdf->MultiCell($w, 4, $textref, '', 'R');
1960
1961
		$posy += 1;
1962
		$pdf->SetFont('', '', $default_font_size - 2);
1963
1964
		if ($object->ref_client)
1965
		{
1966
			$posy += 4;
1967
			$pdf->SetXY($posx, $posy);
1968
			$pdf->SetTextColor(0, 0, 60);
1969
			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_client), '', 'R');
1970
		}
1971
1972
		if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE))
1973
		{
1974
			$object->fetch_projet();
1975
			if (!empty($object->project->ref))
1976
			{
1977
				$posy += 3;
1978
				$pdf->SetXY($posx, $posy);
1979
				$pdf->SetTextColor(0, 0, 60);
1980
				$pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->projet->title), '', 'R');
1981
			}
1982
		}
1983
1984
		if (!empty($conf->global->PDF_SHOW_PROJECT))
1985
		{
1986
			$object->fetch_projet();
1987
			if (!empty($object->project->ref))
1988
			{
1989
				$posy += 3;
1990
				$pdf->SetXY($posx, $posy);
1991
				$pdf->SetTextColor(0, 0, 60);
1992
				$pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefProject")." : ".(empty($object->project->ref) ? '' : $object->projet->ref), '', 'R');
1993
			}
1994
		}
1995
1996
		$objectidnext = $object->getIdReplacingInvoice('validated');
1997
		if ($object->type == 0 && $objectidnext)
1998
		{
1999
			$objectreplacing = new Facture($this->db);
2000
			$objectreplacing->fetch($objectidnext);
2001
2002
			$posy += 3;
2003
			$pdf->SetXY($posx, $posy);
2004
			$pdf->SetTextColor(0, 0, 60);
2005
			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("ReplacementByInvoice").' : '.$outputlangs->convToOutputCharset($objectreplacing->ref), '', 'R');
2006
		}
2007
		if ($object->type == 1)
2008
		{
2009
			$objectreplaced = new Facture($this->db);
2010
			$objectreplaced->fetch($object->fk_facture_source);
2011
2012
			$posy += 4;
2013
			$pdf->SetXY($posx, $posy);
2014
			$pdf->SetTextColor(0, 0, 60);
2015
			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("ReplacementInvoice").' : '.$outputlangs->convToOutputCharset($objectreplaced->ref), '', 'R');
2016
		}
2017
		if ($object->type == 2 && !empty($object->fk_facture_source))
2018
		{
2019
			$objectreplaced = new Facture($this->db);
2020
			$objectreplaced->fetch($object->fk_facture_source);
2021
2022
			$posy += 3;
2023
			$pdf->SetXY($posx, $posy);
2024
			$pdf->SetTextColor(0, 0, 60);
2025
			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("CorrectionInvoice").' : '.$outputlangs->convToOutputCharset($objectreplaced->ref), '', 'R');
2026
		}
2027
2028
		$posy += 4;
2029
		$pdf->SetXY($posx, $posy);
2030
		$pdf->SetTextColor(0, 0, 60);
2031
		$pdf->MultiCell($w, 3, $outputlangs->transnoentities("DateInvoice")." : ".dol_print_date($object->date, "day", false, $outputlangs), '', 'R');
2032
2033
		if (!empty($conf->global->INVOICE_POINTOFTAX_DATE))
2034
		{
2035
			$posy += 4;
2036
			$pdf->SetXY($posx, $posy);
2037
			$pdf->SetTextColor(0, 0, 60);
2038
			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("DatePointOfTax")." : ".dol_print_date($object->date_pointoftax, "day", false, $outputlangs), '', 'R');
2039
		}
2040
2041
		if ($object->type != 2)
2042
		{
2043
			$posy += 3;
2044
			$pdf->SetXY($posx, $posy);
2045
			$pdf->SetTextColor(0, 0, 60);
2046
			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("DateDue")." : ".dol_print_date($object->date_lim_reglement, "day", false, $outputlangs, true), '', 'R');
2047
		}
2048
2049
		if ($object->thirdparty->code_client)
2050
		{
2051
			$posy += 3;
2052
			$pdf->SetXY($posx, $posy);
2053
			$pdf->SetTextColor(0, 0, 60);
2054
			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R');
2055
		}
2056
2057
		// Get contact
2058
		if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP))
2059
		{
2060
		    $arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
2061
		    if (count($arrayidcontact) > 0)
2062
		    {
2063
		        $usertmp = new User($this->db);
2064
		        $usertmp->fetch($arrayidcontact[0]);
2065
                $posy += 4;
2066
                $pdf->SetXY($posx, $posy);
2067
		        $pdf->SetTextColor(0, 0, 60);
2068
		        $pdf->MultiCell($w, 3, $langs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
2069
		    }
2070
		}
2071
2072
		$posy += 1;
2073
2074
		$top_shift = 0;
2075
		// Show list of linked objects
2076
		$current_y = $pdf->getY();
2077
		$posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size);
2078
		if ($current_y < $pdf->getY())
2079
		{
2080
			$top_shift = $pdf->getY() - $current_y;
2081
		}
2082
2083
		if ($showaddress)
2084
		{
2085
			// Sender properties
2086
			$carac_emetteur = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
2087
2088
			// Show sender
2089
			$posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42;
2090
			$posy += $top_shift;
2091
			$posx = $this->marge_gauche;
2092
			if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx = $this->page_largeur - $this->marge_droite - 80;
2093
2094
			$hautcadre = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 38 : 40;
2095
			$widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 82;
2096
2097
2098
			// Show sender frame
2099
			$pdf->SetTextColor(0, 0, 0);
2100
			$pdf->SetFont('', '', $default_font_size - 2);
2101
			$pdf->SetXY($posx, $posy - 5);
2102
			$pdf->MultiCell(66, 5, $outputlangs->transnoentities("BillFrom").":", 0, 'L');
2103
			$pdf->SetXY($posx, $posy);
2104
			$pdf->SetFillColor(230, 230, 230);
2105
			$pdf->MultiCell($widthrecbox, $hautcadre, "", 0, 'R', 1);
2106
			$pdf->SetTextColor(0, 0, 60);
2107
2108
			// Show sender name
2109
			$pdf->SetXY($posx + 2, $posy + 3);
2110
			$pdf->SetFont('', 'B', $default_font_size);
2111
			$pdf->MultiCell($widthrecbox - 2, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, 'L');
2112
			$posy = $pdf->getY();
2113
2114
			// Show sender information
2115
			$pdf->SetXY($posx + 2, $posy);
2116
			$pdf->SetFont('', '', $default_font_size - 1);
2117
			$pdf->MultiCell($widthrecbox - 2, 4, $carac_emetteur, 0, 'L');
2118
2119
			// If BILLING contact defined on invoice, we use it
2120
			$usecontact = false;
2121
			$arrayidcontact = $object->getIdContact('external', 'BILLING');
2122
			if (count($arrayidcontact) > 0)
2123
			{
2124
				$usecontact = true;
2125
				$result = $object->fetch_contact($arrayidcontact[0]);
2126
			}
2127
2128
			//Recipient name
2129
			// On peut utiliser le nom de la societe du contact
2130
			if ($usecontact && !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) {
2131
				$thirdparty = $object->contact;
2132
			} else {
2133
				$thirdparty = $object->thirdparty;
2134
			}
2135
2136
			$carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);
2137
2138
			$carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), $usecontact, 'target', $object);
2139
2140
			// Show recipient
2141
			$widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100;
2142
			if ($this->page_largeur < 210) $widthrecbox = 84; // To work with US executive format
2143
			$posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42;
2144
			$posy += $top_shift;
2145
			$posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
2146
			if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx = $this->marge_gauche;
2147
2148
			// Show recipient frame
2149
			$pdf->SetTextColor(0, 0, 0);
2150
			$pdf->SetFont('', '', $default_font_size - 2);
2151
			$pdf->SetXY($posx + 2, $posy - 5);
2152
			$pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo").":", 0, 'L');
2153
			$pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
2154
2155
			// Show recipient name
2156
			$pdf->SetXY($posx + 2, $posy + 3);
2157
			$pdf->SetFont('', 'B', $default_font_size);
2158
			$pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, 'L');
2159
2160
			$posy = $pdf->getY();
2161
2162
			// Show recipient information
2163
			$pdf->SetFont('', '', $default_font_size - 1);
2164
			$pdf->SetXY($posx + 2, $posy);
2165
			$pdf->MultiCell($widthrecbox, 4, $carac_client, 0, 'L');
2166
		}
2167
2168
		$pdf->SetTextColor(0, 0, 0);
2169
		return $top_shift;
2170
	}
2171
2172
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
2173
	/**
2174
	 *   	Show footer of page. Need this->emetteur object
2175
     *
2176
	 *   	@param	PDF			$pdf     			PDF
2177
	 * 		@param	Object		$object				Object to show
2178
	 *      @param	Translate	$outputlangs		Object lang for output
2179
	 *      @param	int			$hidefreetext		1=Hide free text
2180
	 *      @return	int								Return height of bottom margin including footer text
2181
	 */
2182
	protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
2183
	{
2184
		global $conf;
2185
		$showdetails = $conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS;
2186
		return pdf_pagefoot($pdf, $outputlangs, 'INVOICE_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext);
2187
	}
2188
2189
	/**
2190
	 *  Define Array Column Field
2191
	 *
2192
	 *  @param	object			$object    		common object
2193
	 *  @param	Translate		$outputlangs    langs
2194
     *  @param	int			   $hidedetails		Do not show line details
2195
     *  @param	int			   $hidedesc		Do not show desc
2196
     *  @param	int			   $hideref			Do not show ref
2197
     *  @return	null
2198
     */
2199
    public function defineColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
2200
    {
2201
	    global $conf, $hookmanager;
2202
2203
	    // Default field style for content
2204
	    $this->defaultContentsFieldsStyle = array(
2205
	        'align' => 'R', // R,C,L
2206
	        'padding' => array(1, 0.5, 1, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2207
	    );
2208
2209
	    // Default field style for content
2210
	    $this->defaultTitlesFieldsStyle = array(
2211
	        'align' => 'C', // R,C,L
2212
	        'padding' => array(0.5, 0, 0.5, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2213
	    );
2214
2215
	    /*
2216
	     * For exemple
2217
	    $this->cols['theColKey'] = array(
2218
	        'rank' => $rank, // int : use for ordering columns
2219
	        'width' => 20, // the column width in mm
2220
	        'title' => array(
2221
	            'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
2222
	            'label' => ' ', // the final label : used fore final generated text
2223
	            'align' => 'L', // text alignement :  R,C,L
2224
	            'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2225
	        ),
2226
	        'content' => array(
2227
	            'align' => 'L', // text alignement :  R,C,L
2228
	            'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2229
	        ),
2230
	    );
2231
	    */
2232
2233
	    $rank = 0; // do not use negative rank
2234
	    $this->cols['desc'] = array(
2235
	        'rank' => $rank,
2236
	        'width' => false, // only for desc
2237
	        'status' => true,
2238
	        'title' => array(
2239
	            'textkey' => 'Designation', // use lang key is usefull in somme case with module
2240
	            'align' => 'L',
2241
	            // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
2242
	            // 'label' => ' ', // the final label
2243
	            'padding' => array(0.5, 0.5, 0.5, 0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2244
	        ),
2245
	        'content' => array(
2246
	            'align' => 'L',
2247
                'padding' => array(1, 0.5, 1, 1.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2248
	        ),
2249
	    );
2250
2251
	    // PHOTO
2252
        $rank = $rank + 10;
2253
        $this->cols['photo'] = array(
2254
            'rank' => $rank,
2255
            'width' => (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH) ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH), // in mm
2256
            'status' => false,
2257
            'title' => array(
2258
                'textkey' => 'Photo',
2259
                'label' => ' '
2260
            ),
2261
            'content' => array(
2262
                'padding' => array(0, 0, 0, 0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
2263
            ),
2264
            'border-left' => false, // remove left line separator
2265
        );
2266
2267
	    if (!empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE) && !empty($this->atleastonephoto))
2268
	    {
2269
	        $this->cols['photo']['status'] = true;
2270
	    }
2271
2272
2273
	    $rank = $rank + 10;
2274
	    $this->cols['vat'] = array(
2275
	        'rank' => $rank,
2276
	        'status' => false,
2277
	        'width' => 16, // in mm
2278
	        'title' => array(
2279
	            'textkey' => 'VAT'
2280
	        ),
2281
	        'border-left' => true, // add left line separator
2282
	    );
2283
2284
	    if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN))
2285
	    {
2286
	        $this->cols['vat']['status'] = true;
2287
	    }
2288
2289
	    $rank = $rank + 10;
2290
	    $this->cols['subprice'] = array(
2291
	        'rank' => $rank,
2292
	        'width' => 19, // in mm
2293
	        'status' => true,
2294
	        'title' => array(
2295
	            'textkey' => 'PriceUHT'
2296
	        ),
2297
	        'border-left' => true, // add left line separator
2298
	    );
2299
2300
	    $rank = $rank + 10;
2301
	    $this->cols['qty'] = array(
2302
	        'rank' => $rank,
2303
	        'width' => 16, // in mm
2304
	        'status' => true,
2305
	        'title' => array(
2306
	            'textkey' => 'Qty'
2307
	        ),
2308
	        'border-left' => true, // add left line separator
2309
	    );
2310
2311
	    $rank = $rank + 10;
2312
	    $this->cols['progress'] = array(
2313
	        'rank' => $rank,
2314
	        'width' => 19, // in mm
2315
	        'status' => false,
2316
	        'title' => array(
2317
	            'textkey' => 'Progress'
2318
	        ),
2319
	        'border-left' => true, // add left line separator
2320
	    );
2321
2322
	    if ($this->situationinvoice)
2323
	    {
2324
	        $this->cols['progress']['status'] = true;
2325
	    }
2326
2327
	    $rank = $rank + 10;
2328
	    $this->cols['unit'] = array(
2329
	        'rank' => $rank,
2330
	        'width' => 11, // in mm
2331
	        'status' => false,
2332
	        'title' => array(
2333
	            'textkey' => 'Unit'
2334
	        ),
2335
	        'border-left' => true, // add left line separator
2336
	    );
2337
	    if ($conf->global->PRODUCT_USE_UNITS) {
2338
	        $this->cols['unit']['status'] = true;
2339
	    }
2340
2341
	    $rank = $rank + 10;
2342
	    $this->cols['discount'] = array(
2343
	        'rank' => $rank,
2344
	        'width' => 13, // in mm
2345
	        'status' => false,
2346
	        'title' => array(
2347
	            'textkey' => 'ReductionShort'
2348
	        ),
2349
	        'border-left' => true, // add left line separator
2350
	    );
2351
	    if ($this->atleastonediscount) {
2352
	        $this->cols['discount']['status'] = true;
2353
	    }
2354
2355
	    $rank = $rank + 1000; // add a big offset to be sure is the last col because default extrafield rank is 100
2356
	    $this->cols['totalexcltax'] = array(
2357
	        'rank' => $rank,
2358
	        'width' => 26, // in mm
2359
	        'status' => true,
2360
	        'title' => array(
2361
	            'textkey' => 'TotalHT'
2362
	        ),
2363
	        'border-left' => true, // add left line separator
2364
	    );
2365
2366
	    // Add extrafields cols
2367
        if (!empty($object->lines)) {
2368
            $line = reset($object->lines);
2369
            $this->defineColumnExtrafield($line, $outputlangs, $hidedetails);
2370
        }
2371
2372
	    $parameters = array(
2373
	        'object' => $object,
2374
	        'outputlangs' => $outputlangs,
2375
	        'hidedetails' => $hidedetails,
2376
	        'hidedesc' => $hidedesc,
2377
	        'hideref' => $hideref
2378
	    );
2379
2380
	    $reshook = $hookmanager->executeHooks('defineColumnField', $parameters, $this); // Note that $object may have been modified by hook
2381
	    if ($reshook < 0)
2382
	    {
2383
	        setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2384
	    }
2385
	    elseif (empty($reshook))
2386
	    {
2387
	        $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys
2388
	    }
2389
	    else
2390
	    {
2391
	        $this->cols = $hookmanager->resArray;
2392
	    }
2393
	}
2394
}
2395