1<?php
2/* Copyright (C) 2004-2014 Laurent Destailleur   <eldy@users.sourceforge.net>
3 * Copyright (C) 2005-2011 Regis Houssin         <regis.houssin@inodbox.com>
4 * Copyright (C) 2007      Franky Van Liedekerke <franky.van.liedekerke@telenet.be>
5 * Copyright (C) 2010-2014 Juanjo Menent         <jmenent@2byte.es>
6 * Copyright (C) 2015      Marcos García         <marcosgdf@gmail.com>
7 * Copyright (C) 2017      Ferran Marcet         <fmarcet@2byte.es>
8 * Copyright (C) 2018      Frédéric France       <frederic.france@netlogic.fr>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 * or see https://www.gnu.org/
23 */
24
25/**
26 *	\file       htdocs/core/modules/supplier_order/doc/pdf_muscadet.modules.php
27 *	\ingroup    fournisseur
28 *	\brief      File of class to generate suppliers orders from muscadet model
29 */
30
31require_once DOL_DOCUMENT_ROOT.'/core/modules/supplier_order/modules_commandefournisseur.php';
32require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
33require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
34require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
35require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
36require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
37
38
39/**
40 *	Class to generate the supplier orders with the muscadet model
41 */
42class pdf_muscadet extends ModelePDFSuppliersOrders
43{
44	/**
45	 * @var DoliDb Database handler
46	 */
47	public $db;
48
49	/**
50	 * @var string model name
51	 */
52	public $name;
53
54	/**
55	 * @var string model description (short text)
56	 */
57	public $description;
58
59	/**
60	 * @var int 	Save the name of generated file as the main doc when generating a doc with this template
61	 */
62	public $update_main_doc_field;
63
64	/**
65	 * @var string document type
66	 */
67	public $type;
68
69	/**
70	 * @var array Minimum version of PHP required by module.
71	 * e.g.: PHP ≥ 5.6 = array(5, 6)
72	 */
73	public $phpmin = array(5, 6);
74
75	/**
76	 * Dolibarr version of the loaded document
77	 * @var string
78	 */
79	public $version = 'dolibarr';
80
81	/**
82	 * @var int page_largeur
83	 */
84	public $page_largeur;
85
86	/**
87	 * @var int page_hauteur
88	 */
89	public $page_hauteur;
90
91	/**
92	 * @var array format
93	 */
94	public $format;
95
96	/**
97	 * @var int marge_gauche
98	 */
99	public $marge_gauche;
100
101	/**
102	 * @var int marge_droite
103	 */
104	public $marge_droite;
105
106	/**
107	 * @var int marge_haute
108	 */
109	public $marge_haute;
110
111	/**
112	 * @var int marge_basse
113	 */
114	public $marge_basse;
115
116	/**
117	 * Issuer
118	 * @var Societe object that emits
119	 */
120	public $emetteur;
121
122
123	/**
124	 *	Constructor
125	 *
126	 *  @param	DoliDB		$db      	Database handler
127	 */
128	public function __construct($db)
129	{
130		global $conf, $langs, $mysoc;
131
132		// Load translation files required by the page
133		$langs->loadLangs(array("main", "bills"));
134
135		$this->db = $db;
136		$this->name = "muscadet";
137		$this->description = $langs->trans('SuppliersCommandModelMuscadet');
138		$this->update_main_doc_field = 1;		// Save the name of generated file as the main doc when generating a doc with this template
139
140		// Page size for A4 format
141		$this->type = 'pdf';
142		$formatarray = pdf_getFormat();
143		$this->page_largeur = $formatarray['width'];
144		$this->page_hauteur = $formatarray['height'];
145		$this->format = array($this->page_largeur, $this->page_hauteur);
146		$this->marge_gauche = isset($conf->global->MAIN_PDF_MARGIN_LEFT) ? $conf->global->MAIN_PDF_MARGIN_LEFT : 10;
147		$this->marge_droite = isset($conf->global->MAIN_PDF_MARGIN_RIGHT) ? $conf->global->MAIN_PDF_MARGIN_RIGHT : 10;
148		$this->marge_haute = isset($conf->global->MAIN_PDF_MARGIN_TOP) ? $conf->global->MAIN_PDF_MARGIN_TOP : 10;
149		$this->marge_basse = isset($conf->global->MAIN_PDF_MARGIN_BOTTOM) ? $conf->global->MAIN_PDF_MARGIN_BOTTOM : 10;
150
151		$this->option_logo = 1; // Display logo
152		$this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION
153		$this->option_modereg = 1; // Display payment mode
154		$this->option_condreg = 1; // Display payment terms
155		$this->option_codeproduitservice = 1; // Display product-service code
156		$this->option_multilang = 1; // Available in several languages
157		$this->option_escompte = 0; // Displays if there has been a discount
158		$this->option_credit_note = 0; // Support credit notes
159		$this->option_freetext = 1; // Support add of a personalised text
160		$this->option_draft_watermark = 1; // Support add of a watermark on drafts
161
162		// Get source company
163		$this->emetteur = $mysoc;
164		if (empty($this->emetteur->country_code)) {
165			$this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined
166		}
167
168		// Define position of columns
169		$this->posxdesc = $this->marge_gauche + 1;
170		$this->posxdiscount = 162;
171		$this->postotalht = 174;
172
173		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
174			$this->posxtva = 95;
175			$this->posxup = 114;
176			$this->posxqty = 132;
177			$this->posxunit = 147;
178		} else {
179			$this->posxtva = 110;
180			$this->posxup = 126;
181			$this->posxqty = 145;
182			$this->posxunit = 162;
183		}
184
185		if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) {
186			$this->posxup = $this->posxtva; // posxtva is picture position reference
187		}
188		$this->posxpicture = $this->posxtva - (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH) ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH); // width of images
189		if ($this->page_largeur < 210) { // To work with US executive format
190			$this->posxpicture -= 20;
191			$this->posxtva -= 20;
192			$this->posxup -= 20;
193			$this->posxqty -= 20;
194			$this->posxunit -= 20;
195			$this->posxdiscount -= 20;
196			$this->postotalht -= 20;
197		}
198
199		$this->tva = array();
200		$this->localtax1 = array();
201		$this->localtax2 = array();
202		$this->atleastoneratenotnull = 0;
203		$this->atleastonediscount = 0;
204	}
205
206
207	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
208	/**
209	 *  Function to build pdf onto disk
210	 *
211	 *  @param		CommandeFournisseur	$object				Id of object to generate
212	 *  @param		Translate			$outputlangs		Lang output object
213	 *  @param		string				$srctemplatepath	Full path of source filename for generator using a template file
214	 *  @param		int					$hidedetails		Do not show line details
215	 *  @param		int					$hidedesc			Do not show desc
216	 *  @param		int					$hideref			Do not show ref
217	 *  @return		int										1=OK, 0=KO
218	 */
219	public function write_file($object, $outputlangs = '', $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
220	{
221		// phpcs:enable
222		global $user, $langs, $conf, $hookmanager, $mysoc, $nblines;
223
224		if (!is_object($outputlangs)) {
225			$outputlangs = $langs;
226		}
227		// For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
228		if (!empty($conf->global->MAIN_USE_FPDF)) {
229			$outputlangs->charset_output = 'ISO-8859-1';
230		}
231
232		// Load translation files required by the page
233		$outputlangs->loadLangs(array("main", "orders", "companies", "bills", "dict", "products"));
234
235		$nblines = count($object->lines);
236
237		// Loop on each lines to detect if there is at least one image to show
238		$realpatharray = array();
239		if (!empty($conf->global->MAIN_GENERATE_SUPPLIER_ORDER_WITH_PICTURE)) {
240			for ($i = 0; $i < $nblines; $i++) {
241				if (empty($object->lines[$i]->fk_product)) {
242					continue;
243				}
244
245				$objphoto = new Product($this->db);
246				$objphoto->fetch($object->lines[$i]->fk_product);
247
248				if (!empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) {
249					$pdir = get_exdir($objphoto->id, 2, 0, 0, $objphoto, 'product').$object->lines[$i]->fk_product."/photos/";
250					$dir = $conf->product->dir_output.'/'.$pdir;
251				} else {
252					$pdir = get_exdir($objphoto->id, 0, 0, 0, $objphoto, 'product');
253					$dir = $conf->product->dir_output.'/'.$pdir;
254				}
255				$realpath = '';
256				foreach ($objphoto->liste_photos($dir, 1) as $key => $obj) {
257					if (empty($conf->global->CAT_HIGH_QUALITY_IMAGES)) {		// If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo
258						if ($obj['photo_vignette']) {
259							$filename = $obj['photo_vignette'];
260						} else {
261							$filename = $obj['photo'];
262						}
263					} else {
264						$filename = $obj['photo'];
265					}
266					$realpath = $dir.$filename;
267					break;
268				}
269
270				if ($realpath) {
271					$realpatharray[$i] = $realpath;
272				}
273			}
274		}
275		if (count($realpatharray) == 0) {
276			$this->posxpicture = $this->posxtva;
277		}
278
279		if ($conf->fournisseur->commande->dir_output) {
280			$object->fetch_thirdparty();
281
282			$deja_regle = 0;
283			$amount_credit_notes_included = 0;
284			$amount_deposits_included = 0;
285			//$amount_credit_notes_included = $object->getSumCreditNotesUsed();
286			//$amount_deposits_included = $object->getSumDepositsUsed();
287
288			// Definition of $dir and $file
289			if ($object->specimen) {
290				$dir = $conf->fournisseur->commande->dir_output;
291				$file = $dir."/SPECIMEN.pdf";
292			} else {
293				$objectref = dol_sanitizeFileName($object->ref);
294				$objectrefsupplier = dol_sanitizeFileName($object->ref_supplier);
295				$dir = $conf->fournisseur->commande->dir_output.'/'.$objectref;
296				$file = $dir."/".$objectref.".pdf";
297				if (!empty($conf->global->SUPPLIER_REF_IN_NAME)) {
298					$file = $dir."/".$objectref.($objectrefsupplier ? "_".$objectrefsupplier : "").".pdf";
299				}
300			}
301
302			if (!file_exists($dir)) {
303				if (dol_mkdir($dir) < 0) {
304					$this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
305					return 0;
306				}
307			}
308
309			if (file_exists($dir)) {
310				// Add pdfgeneration hook
311				if (!is_object($hookmanager)) {
312					include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
313					$hookmanager = new HookManager($this->db);
314				}
315				$hookmanager->initHooks(array('pdfgeneration'));
316				$parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
317				global $action;
318				$reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
319
320				$nblines = count($object->lines);
321
322				$pdf = pdf_getInstance($this->format);
323				$default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
324				$heightforinfotot = 50; // Height reserved to output the info and total part
325				$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
326				$heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin)
327				if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)) {
328					$heightforfooter += 6;
329				}
330				$pdf->SetAutoPageBreak(1, 0);
331
332				if (class_exists('TCPDF')) {
333					$pdf->setPrintHeader(false);
334					$pdf->setPrintFooter(false);
335				}
336				$pdf->SetFont(pdf_getPDFFont($outputlangs));
337				// Set path to the background PDF File
338				if (!empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) {
339					$pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND);
340					$tplidx = $pdf->importPage(1);
341				}
342
343				$pdf->Open();
344				$pagenb = 0;
345				$pdf->SetDrawColor(128, 128, 128);
346
347				$pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
348				$pdf->SetSubject($outputlangs->transnoentities("PurchaseOrder"));
349				$pdf->SetCreator("Dolibarr ".DOL_VERSION);
350				$pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
351
352				$pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PurchaseOrder")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
353				if (!empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) {
354					$pdf->SetCompression(false);
355				}
356
357				$pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
358
359				// Positionne $this->atleastonediscount si on a au moins une remise
360				for ($i = 0; $i < $nblines; $i++) {
361					if ($object->lines[$i]->remise_percent) {
362						$this->atleastonediscount++;
363					}
364				}
365				if (empty($this->atleastonediscount)) {
366					$delta = ($this->postotalht - $this->posxdiscount);
367					$this->posxpicture += $delta;
368					$this->posxtva += $delta;
369					$this->posxup += $delta;
370					$this->posxqty += $delta;
371					$this->posxunit += $delta;
372					$this->posxdiscount += $delta;
373					// post of fields after are not modified, stay at same position
374				}
375
376				// New page
377				$pdf->AddPage();
378				if (!empty($tplidx)) {
379					$pdf->useTemplate($tplidx);
380				}
381				$pagenb++;
382				$top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs);
383				$pdf->SetFont('', '', $default_font_size - 1);
384				$pdf->MultiCell(0, 3, ''); // Set interline to 3
385				$pdf->SetTextColor(0, 0, 0);
386
387				$tab_top = 90 + $top_shift;
388				$tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD) ? 42 + $top_shift : 10);
389
390				// Incoterm
391				if (!empty($conf->incoterm->enabled)) {
392					$desc_incoterms = $object->getIncotermsForPDF();
393					if ($desc_incoterms) {
394						$tab_top -= 2;
395
396						$pdf->SetFont('', '', $default_font_size - 1);
397						$pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($desc_incoterms), 0, 1);
398						$nexY = $pdf->GetY();
399						$height_incoterms = $nexY - $tab_top;
400
401						// Rect takes a length in 3rd parameter
402						$pdf->SetDrawColor(192, 192, 192);
403						$pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_incoterms + 1);
404
405						$tab_top = $nexY + 6;
406					}
407				}
408
409				// Affiche notes
410				if (!empty($object->note_public)) {
411					$tab_top -= 2;
412
413					$pdf->SetFont('', '', $default_font_size - 1);
414					$pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($object->note_public), 0, 1);
415					$nexY = $pdf->GetY();
416					$height_note = $nexY - $tab_top;
417
418					// Rect takes a length in 3rd parameter
419					$pdf->SetDrawColor(192, 192, 192);
420					$pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_note + 1);
421
422					$tab_top = $nexY + 6;
423				}
424
425				$iniY = $tab_top + 7;
426				$curY = $tab_top + 7;
427				$nexY = $tab_top + 7;
428
429				// Loop on each lines
430				for ($i = 0; $i < $nblines; $i++) {
431					$curY = $nexY;
432					$pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
433					$pdf->SetTextColor(0, 0, 0);
434
435					// Define size of image if we need it
436					$imglinesize = array();
437					if (!empty($realpatharray[$i])) {
438						$imglinesize = pdf_getSizeForImage($realpatharray[$i]);
439					}
440
441					$pdf->setTopMargin($tab_top_newpage);
442					$pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext + $heightforinfotot); // The only function to edit the bottom margin of current page to set it.
443					$pageposbefore = $pdf->getPage();
444
445					$showpricebeforepagebreak = 1;
446					$posYAfterImage = 0;
447					$posYAfterDescription = 0;
448
449					// We start with Photo of product line
450					if (!empty($imglinesize['width']) && !empty($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) {	// If photo too high, we moved completely on new page
451						$pdf->AddPage('', '', true);
452						if (!empty($tplidx)) {
453							$pdf->useTemplate($tplidx);
454						}
455						if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) {
456							$this->_pagehead($pdf, $object, 0, $outputlangs);
457						}
458						$pdf->setPage($pageposbefore + 1);
459
460						$curY = $tab_top_newpage;
461
462						// Allows data in the first page if description is long enough to break in multiples pages
463						if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {
464							$showpricebeforepagebreak = 1;
465						} else {
466							$showpricebeforepagebreak = 0;
467						}
468					}
469
470					if (!empty($imglinesize['width']) && !empty($imglinesize['height'])) {
471						$curX = $this->posxpicture - 1;
472						$pdf->Image($realpatharray[$i], $curX + (($this->posxtva - $this->posxpicture - $imglinesize['width']) / 2), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi
473						// $pdf->Image does not increase value return by getY, so we save it manually
474						$posYAfterImage = $curY + $imglinesize['height'];
475					}
476					// Description of product line
477					$curX = $this->posxdesc - 1;
478					$showpricebeforepagebreak = 1;
479
480					$pdf->startTransaction();
481					if ($posYAfterImage > 0) {
482						$descWidth = $this->posxpicture - $curX;
483					} else {
484						$descWidth = $this->posxtva - $curX;
485					}
486					pdf_writelinedesc($pdf, $object, $i, $outputlangs, $descWidth, 3, $curX, $curY, $hideref, $hidedesc, 1);
487
488					$pageposafter = $pdf->getPage();
489					if ($pageposafter > $pageposbefore) {	// There is a pagebreak
490						$pdf->rollbackTransaction(true);
491						$pageposafter = $pageposbefore;
492						//print $pageposafter.'-'.$pageposbefore;exit;
493						$pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
494						pdf_writelinedesc($pdf, $object, $i, $outputlangs, $descWidth, 3, $curX, $curY, $hideref, $hidedesc, 1);
495						$posyafter = $pdf->GetY();
496						if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) {	// There is no space left for total+free text
497							if ($i == ($nblines - 1)) {	// No more lines, and no space left to show total, so we create a new page
498								$pdf->AddPage('', '', true);
499								if (!empty($tplidx)) {
500									$pdf->useTemplate($tplidx);
501								}
502								if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) {
503									$this->_pagehead($pdf, $object, 0, $outputlangs);
504								}
505								$pdf->setPage($pageposafter + 1);
506							}
507						} else {
508							// We found a page break
509							// Allows data in the first page if description is long enough to break in multiples pages
510							if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {
511								$showpricebeforepagebreak = 1;
512							} else {
513								$showpricebeforepagebreak = 0;
514							}
515						}
516					} else // No pagebreak
517					{
518						$pdf->commitTransaction();
519					}
520
521					$nexY = $pdf->GetY();
522					$pageposafter = $pdf->getPage();
523					$pdf->setPage($pageposbefore);
524					$pdf->setTopMargin($this->marge_haute);
525					$pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
526
527					// We suppose that a too long description is moved completely on next page
528					if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
529						$pdf->setPage($pageposafter);
530						$curY = $tab_top_newpage;
531					}
532
533					$pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par defaut
534
535					// VAT Rate
536					if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
537						$vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
538						$pdf->SetXY($this->posxtva, $curY);
539						$pdf->MultiCell($this->posxup - $this->posxtva - 1, 3, $vat_rate, 0, 'R');
540					}
541
542					// Unit price before discount
543					if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_PURCHASE_ORDER_WITHOUT_UNIT_PRICE)) {
544						$up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);
545						$pdf->SetXY($this->posxup, $curY);
546						$pdf->MultiCell($this->posxqty - $this->posxup - 0.8, 3, $up_excl_tax, 0, 'R', 0);
547					}
548
549					// Quantity
550					$qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
551					$pdf->SetXY($this->posxqty, $curY);
552					$pdf->MultiCell($this->posxunit - $this->posxqty - 0.8, 4, $qty, 0, 'R'); // Enough for 6 chars
553
554					// Unit
555					if (!empty($conf->global->PRODUCT_USE_UNITS)) {
556						$unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager);
557						$pdf->SetXY($this->posxunit, $curY);
558						$pdf->MultiCell($this->posxdiscount - $this->posxunit - 0.8, 4, $unit, 0, 'L');
559					}
560
561					// Discount on line
562					$pdf->SetXY($this->posxdiscount, $curY);
563					if ($object->lines[$i]->remise_percent) {
564						$remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);
565						$pdf->MultiCell($this->postotalht - $this->posxdiscount - 1, 3, $remise_percent, 0, 'R');
566					}
567
568					// Total HT line
569					if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_PURCHASE_ORDER_WITHOUT_TOTAL_COLUMN)) {
570						$total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs);
571						$pdf->SetXY($this->postotalht, $curY);
572						$pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->postotalht, 3, $total_excl_tax, 0, 'R', 0);
573					}
574
575					// Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva
576					if (!empty($conf->multicurrency->enabled) && $object->multicurrency_tx != 1) {
577						$tvaligne = $object->lines[$i]->multicurrency_total_tva;
578					} else {
579						$tvaligne = $object->lines[$i]->total_tva;
580					}
581
582					$localtax1ligne = $object->lines[$i]->total_localtax1;
583					$localtax2ligne = $object->lines[$i]->total_localtax2;
584					$localtax1_rate = $object->lines[$i]->localtax1_tx;
585					$localtax2_rate = $object->lines[$i]->localtax2_tx;
586					$localtax1_type = $object->lines[$i]->localtax1_type;
587					$localtax2_type = $object->lines[$i]->localtax2_type;
588
589					if (!empty($object->remise_percent)) {
590						$tvaligne -= ($tvaligne * $object->remise_percent) / 100;
591					}
592					if (!empty($object->remise_percent)) {
593						$localtax1ligne -= ($localtax1ligne * $object->remise_percent) / 100;
594					}
595					if (!empty($object->remise_percent)) {
596						$localtax2ligne -= ($localtax2ligne * $object->remise_percent) / 100;
597					}
598
599					$vatrate = (string) $object->lines[$i]->tva_tx;
600
601					// Retrieve type from database for backward compatibility with old records
602					if ((!isset($localtax1_type) || $localtax1_type == '' || !isset($localtax2_type) || $localtax2_type == '') // if tax type not defined
603					&& (!empty($localtax1_rate) || !empty($localtax2_rate))) { // and there is local tax
604						$localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $mysoc, $object->thirdparty);
605						$localtax1_type = isset($localtaxtmp_array[0]) ? $localtaxtmp_array[0] : '';
606						$localtax2_type = isset($localtaxtmp_array[2]) ? $localtaxtmp_array[2] : '';
607					}
608
609					// retrieve global local tax
610					if ($localtax1_type && $localtax1ligne != 0) {
611						$this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne;
612					}
613					if ($localtax2_type && $localtax2ligne != 0) {
614						$this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne;
615					}
616
617					if (($object->lines[$i]->info_bits & 0x01) == 0x01) {
618						$vatrate .= '*';
619					}
620					if (!isset($this->tva[$vatrate])) {
621						$this->tva[$vatrate] = 0;
622					}
623					$this->tva[$vatrate] += $tvaligne;
624
625					if ($posYAfterImage > $posYAfterDescription) {
626						$nexY = $posYAfterImage;
627					}
628
629					// Add line
630					if (!empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblines - 1)) {
631						$pdf->setPage($pageposafter);
632						$pdf->SetLineStyle(array('dash'=>'1,1', 'color'=>array(80, 80, 80)));
633						//$pdf->SetDrawColor(190,190,200);
634						$pdf->line($this->marge_gauche, $nexY + 1, $this->page_largeur - $this->marge_droite, $nexY + 1);
635						$pdf->SetLineStyle(array('dash'=>0));
636					}
637
638					$nexY += 2; // Add space between lines
639
640					// Detect if some page were added automatically and output _tableau for past pages
641					while ($pagenb < $pageposafter) {
642						$pdf->setPage($pagenb);
643						if ($pagenb == 1) {
644							$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
645						} else {
646							$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
647						}
648						$this->_pagefoot($pdf, $object, $outputlangs, 1);
649						$pagenb++;
650						$pdf->setPage($pagenb);
651						$pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
652						if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) {
653							$this->_pagehead($pdf, $object, 0, $outputlangs);
654						}
655					}
656					if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) {
657						if ($pagenb == 1) {
658							$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
659						} else {
660							$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
661						}
662						$this->_pagefoot($pdf, $object, $outputlangs, 1);
663						// New page
664						$pdf->AddPage();
665						if (!empty($tplidx)) {
666							$pdf->useTemplate($tplidx);
667						}
668						$pagenb++;
669						if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) {
670							$this->_pagehead($pdf, $object, 0, $outputlangs);
671						}
672					}
673				}
674
675				// Show square
676				if ($pagenb == 1) {
677					$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code);
678					$bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
679				} else {
680					$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code);
681					$bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
682				}
683
684				// Affiche zone infos
685				$posy = $this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs);
686
687				// Affiche zone totaux
688				$posy = $this->_tableau_tot($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs);
689
690				// Affiche zone versements
691				if ($deja_regle || $amount_credit_notes_included || $amount_deposits_included) {
692					$posy = $this->_tableau_versements($pdf, $object, $posy, $outputlangs);
693				}
694
695				// Pied de page
696				$this->_pagefoot($pdf, $object, $outputlangs);
697				if (method_exists($pdf, 'AliasNbPages')) {
698					$pdf->AliasNbPages();
699				}
700
701				$pdf->Close();
702
703				$pdf->Output($file, 'F');
704
705				// Add pdfgeneration hook
706				$hookmanager->initHooks(array('pdfgeneration'));
707				$parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
708				global $action;
709				$reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
710				if ($reshook < 0) {
711					$this->error = $hookmanager->error;
712					$this->errors = $hookmanager->errors;
713				}
714
715				if (!empty($conf->global->MAIN_UMASK)) {
716					@chmod($file, octdec($conf->global->MAIN_UMASK));
717				}
718
719				$this->result = array('fullpath'=>$file);
720
721				return 1; // No error
722			} else {
723				$this->error = $langs->trans("ErrorCanNotCreateDir", $dir);
724				return 0;
725			}
726		} else {
727			$this->error = $langs->trans("ErrorConstantNotDefined", "SUPPLIER_OUTPUTDIR");
728			return 0;
729		}
730	}
731
732	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
733	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
734	/**
735	 *  Show payments table
736	 *
737	 *  @param	TCPDF		$pdf     		Object PDF
738	 *  @param  CommandeFournisseur		$object			Object order
739	 *	@param	int			$posy			Position y in PDF
740	 *	@param	Translate	$outputlangs	Object langs for output
741	 *	@return int							<0 if KO, >0 if OK
742	 */
743	protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs)
744	{
745		// phpcs:enable
746	}
747
748	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
749	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
750	/**
751	 *   Show miscellaneous information (payment mode, payment term, ...)
752	 *
753	 *   @param		TCPDF		$pdf     		Object PDF
754	 *   @param		CommandeFournisseur		$object			Object to show
755	 *   @param		int			$posy			Y
756	 *   @param		Translate	$outputlangs	Langs object
757	 *   @return	integer
758	 */
759	protected function _tableau_info(&$pdf, $object, $posy, $outputlangs)
760	{
761		// phpcs:enable
762		global $conf, $mysoc;
763		$default_font_size = pdf_getPDFFontSize($outputlangs);
764
765		// If France, show VAT mention if not applicable
766		if ($this->emetteur->country_code == 'FR' && empty($mysoc->tva_assuj)) {
767			$pdf->SetFont('', 'B', $default_font_size - 2);
768			$pdf->SetXY($this->marge_gauche, $posy);
769			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0);
770
771			$posy = $pdf->GetY() + 4;
772		}
773
774		$posxval = 52;
775
776		// Show payments conditions
777		if (!empty($object->cond_reglement_code) || $object->cond_reglement_id) {
778			$pdf->SetFont('', 'B', $default_font_size - 2);
779			$pdf->SetXY($this->marge_gauche, $posy);
780			$titre = $outputlangs->transnoentities("PaymentConditions").':';
781			$pdf->MultiCell(80, 4, $titre, 0, 'L');
782
783			$pdf->SetFont('', '', $default_font_size - 2);
784			$pdf->SetXY($posxval, $posy);
785			$lib_condition_paiement = $outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code) != ('PaymentCondition'.$object->cond_reglement_code) ? $outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code) : $outputlangs->convToOutputCharset($object->cond_reglement_doc ? $object->cond_reglement_doc : $object->cond_reglement_label);
786			$lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement);
787			$pdf->MultiCell(80, 4, $lib_condition_paiement, 0, 'L');
788
789			$posy = $pdf->GetY() + 3;
790		}
791
792		// Show payment mode
793		if (!empty($object->mode_reglement_code)) {
794			$pdf->SetFont('', 'B', $default_font_size - 2);
795			$pdf->SetXY($this->marge_gauche, $posy);
796			$titre = $outputlangs->transnoentities("PaymentMode").':';
797			$pdf->MultiCell(80, 5, $titre, 0, 'L');
798
799			$pdf->SetFont('', '', $default_font_size - 2);
800			$pdf->SetXY($posxval, $posy);
801			$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);
802			$pdf->MultiCell(80, 5, $lib_mode_reg, 0, 'L');
803
804			$posy = $pdf->GetY() + 2;
805		}
806
807		return $posy;
808	}
809
810	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
811	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
812	/**
813	 *  Show total to pay
814	 *
815	 *  @param	TCPDF		$pdf            Object PDF
816	 *	@param  Facture		$object         Object invoice
817	 *	@param  int			$deja_regle     Montant deja regle
818	 *	@param	int			$posy			Position depart
819	 *	@param	Translate	$outputlangs	Objet langs
820	 *	@return int							Position pour suite
821	 */
822	protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs)
823	{
824		// phpcs:enable
825		global $conf, $mysoc;
826
827		$default_font_size = pdf_getPDFFontSize($outputlangs);
828
829		$tab2_top = $posy;
830		$tab2_hl = 4;
831		$pdf->SetFont('', '', $default_font_size - 1);
832
833		// Tableau total
834		$col1x = 120;
835		$col2x = 170;
836		if ($this->page_largeur < 210) { // To work with US executive format
837			$col2x -= 20;
838		}
839		$largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
840
841		$useborder = 0;
842		$index = 0;
843
844		// Total HT
845		$pdf->SetFillColor(255, 255, 255);
846		$pdf->SetXY($col1x, $tab2_top + 0);
847		$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1);
848
849		$total_ht = ((!empty($conf->multicurrency->enabled) && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht);
850		$pdf->SetXY($col2x, $tab2_top + 0);
851		$pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + (!empty($object->remise) ? $object->remise : 0)), 0, 'R', 1);
852
853		// Show VAT by rates and total
854		$pdf->SetFillColor(248, 248, 248);
855
856		$this->atleastoneratenotnull = 0;
857		foreach ($this->tva as $tvakey => $tvaval) {
858			if ($tvakey > 0) {    // On affiche pas taux 0
859				$this->atleastoneratenotnull++;
860
861				$index++;
862				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
863
864				$tvacompl = '';
865
866				if (preg_match('/\*/', $tvakey)) {
867					$tvakey = str_replace('*', '', $tvakey);
868					$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
869				}
870
871				$totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).' ';
872				$totalvat .= vatrate($tvakey, 1).$tvacompl;
873				$pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
874
875				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
876				$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval), 0, 'R', 1);
877			}
878		}
879		if (!$this->atleastoneratenotnull) { // If no vat at all
880			$index++;
881			$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
882			$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code), 0, 'L', 1);
883
884			$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
885			$pdf->MultiCell($largcol2, $tab2_hl, price($object->total_tva), 0, 'R', 1);
886
887			// Total LocalTax1
888			if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION == 'localtax1on' && $object->total_localtax1 > 0) {
889				$index++;
890				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
891				$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code), 0, 'L', 1);
892				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
893				$pdf->MultiCell($largcol2, $tab2_hl, price($object->total_localtax1), $useborder, 'R', 1);
894			}
895
896			// Total LocalTax2
897			if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION == 'localtax2on' && $object->total_localtax2 > 0) {
898				$index++;
899				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
900				$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code), 0, 'L', 1);
901				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
902				$pdf->MultiCell($largcol2, $tab2_hl, price($object->total_localtax2), $useborder, 'R', 1);
903			}
904		} else {
905			//if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
906			//{
907				//Local tax 1
908			foreach ($this->localtax1 as $localtax_type => $localtax_rate) {
909				if (in_array((string) $localtax_type, array('2', '4', '6'))) {
910					continue;
911				}
912
913				foreach ($localtax_rate as $tvakey => $tvaval) {
914					if ($tvakey != 0) {    // On affiche pas taux 0
915						//$this->atleastoneratenotnull++;
916
917						$index++;
918						$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
919
920						$tvacompl = '';
921						if (preg_match('/\*/', $tvakey)) {
922							$tvakey = str_replace('*', '', $tvakey);
923							$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
924						}
925						$totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).' ';
926						$totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
927						$pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
928
929						$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
930						$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
931					}
932				}
933			}
934
935			//if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
936			//{
937				//Local tax 2
938			foreach ($this->localtax2 as $localtax_type => $localtax_rate) {
939				if (in_array((string) $localtax_type, array('2', '4', '6'))) {
940					continue;
941				}
942
943				foreach ($localtax_rate as $tvakey => $tvaval) {
944					if ($tvakey != 0) {    // On affiche pas taux 0
945						//$this->atleastoneratenotnull++;
946
947						$index++;
948						$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
949
950						$tvacompl = '';
951						if (preg_match('/\*/', $tvakey)) {
952							$tvakey = str_replace('*', '', $tvakey);
953							$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
954						}
955						$totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' ';
956						$totalvat .= vatrate(abs($tvakey), 1).$tvacompl;
957						$pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1);
958
959						$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
960						$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval), 0, 'R', 1);
961					}
962				}
963			}
964		}
965
966		// Total TTC
967		$index++;
968		$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
969		$pdf->SetTextColor(0, 0, 60);
970		$pdf->SetFillColor(224, 224, 224);
971		$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1);
972
973		$total_ttc = (!empty($conf->multicurrency->enabled) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
974		$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
975		$pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc), $useborder, 'R', 1);
976		$pdf->SetFont('', '', $default_font_size - 1);
977		$pdf->SetTextColor(0, 0, 0);
978
979		$creditnoteamount = 0;
980		$depositsamount = 0;
981		//$creditnoteamount=$object->getSumCreditNotesUsed();
982		//$depositsamount=$object->getSumDepositsUsed();
983		//print "x".$creditnoteamount."-".$depositsamount;exit;
984		$resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT');
985		if (!empty($object->paye)) {
986			$resteapayer = 0;
987		}
988
989		if ($deja_regle > 0) {
990			// Already paid + Deposits
991			$index++;
992
993			$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
994			$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid"), 0, 'L', 0);
995			$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
996			$pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle), 0, 'R', 0);
997
998			$index++;
999			$pdf->SetTextColor(0, 0, 60);
1000			$pdf->SetFillColor(224, 224, 224);
1001			$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1002			$pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1);
1003
1004			$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1005			$pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer), $useborder, 'R', 1);
1006
1007			$pdf->SetFont('', '', $default_font_size - 1);
1008			$pdf->SetTextColor(0, 0, 0);
1009		}
1010
1011		$index++;
1012		return ($tab2_top + ($tab2_hl * $index));
1013	}
1014
1015	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1016	/**
1017	 *   Show table for lines
1018	 *
1019	 *   @param		TCPDF		$pdf     		Object PDF
1020	 *   @param		string		$tab_top		Top position of table
1021	 *   @param		string		$tab_height		Height of table (rectangle)
1022	 *   @param		int			$nexY			Y (not used)
1023	 *   @param		Translate	$outputlangs	Langs object
1024	 *   @param		int			$hidetop		Hide top bar of array
1025	 *   @param		int			$hidebottom		Hide bottom bar of array
1026	 *   @param		string		$currency		Currency code
1027	 *   @return	void
1028	 */
1029	protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '')
1030	{
1031		global $conf;
1032
1033		// Force to disable hidetop and hidebottom
1034		$hidebottom = 0;
1035		if ($hidetop) {
1036			$hidetop = -1;
1037		}
1038
1039		$currency = !empty($currency) ? $currency : $conf->currency;
1040		$default_font_size = pdf_getPDFFontSize($outputlangs);
1041
1042		// Amount in (at tab_top - 1)
1043		$pdf->SetTextColor(0, 0, 0);
1044		$pdf->SetFont('', '', $default_font_size - 2);
1045
1046		if (empty($hidetop)) {
1047			$titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
1048			$pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
1049			$pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
1050
1051			//$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
1052			if (!empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) {
1053				$pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite - $this->marge_gauche, 5, 'F', null, explode(',', $conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR));
1054			}
1055		}
1056
1057		$pdf->SetDrawColor(128, 128, 128);
1058		$pdf->SetFont('', '', $default_font_size - 1);
1059
1060		// Output Rect
1061		$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
1062
1063		if (empty($hidetop)) {
1064			$pdf->line($this->marge_gauche, $tab_top + 5, $this->page_largeur - $this->marge_droite, $tab_top + 5); // line takes a position y in 2nd parameter and 4th parameter
1065
1066			$pdf->SetXY($this->posxdesc - 1, $tab_top + 1);
1067			$pdf->MultiCell(108, 2, $outputlangs->transnoentities("Designation"), '', 'L');
1068		}
1069
1070		if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) {
1071			$pdf->line($this->posxtva, $tab_top, $this->posxtva, $tab_top + $tab_height);
1072			if (empty($hidetop)) {
1073				$pdf->SetXY($this->posxtva - 3, $tab_top + 1);
1074				$pdf->MultiCell($this->posxup - $this->posxtva + 3, 2, $outputlangs->transnoentities("VAT"), '', 'C');
1075			}
1076		}
1077
1078		$pdf->line($this->posxup, $tab_top, $this->posxup, $tab_top + $tab_height);
1079		if (empty($hidetop)) {
1080			$pdf->SetXY($this->posxup - 1, $tab_top + 1);
1081			$pdf->MultiCell($this->posxqty - $this->posxup - 1, 2, $outputlangs->transnoentities("PriceUHT"), '', 'C');
1082		}
1083
1084		$pdf->line($this->posxqty - 1, $tab_top, $this->posxqty - 1, $tab_top + $tab_height);
1085		if (empty($hidetop)) {
1086			$pdf->SetXY($this->posxqty - 1, $tab_top + 1);
1087			$pdf->MultiCell($this->posxunit - $this->posxqty - 1, 2, $outputlangs->transnoentities("Qty"), '', 'C');
1088		}
1089
1090		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
1091			$pdf->line($this->posxunit - 1, $tab_top, $this->posxunit - 1, $tab_top + $tab_height);
1092			if (empty($hidetop)) {
1093				$pdf->SetXY($this->posxunit - 1, $tab_top + 1);
1094				$pdf->MultiCell($this->posxdiscount - $this->posxunit - 1, 2, $outputlangs->transnoentities("Unit"), '', 'C');
1095			}
1096		}
1097
1098		$pdf->line($this->posxdiscount - 1, $tab_top, $this->posxdiscount - 1, $tab_top + $tab_height);
1099		if (empty($hidetop)) {
1100			if ($this->atleastonediscount) {
1101				$pdf->SetXY($this->posxdiscount - 1, $tab_top + 1);
1102				$pdf->MultiCell($this->postotalht - $this->posxdiscount + 1, 2, $outputlangs->transnoentities("ReductionShort"), '', 'C');
1103			}
1104		}
1105
1106		if ($this->atleastonediscount) {
1107			$pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height);
1108		}
1109		if (empty($hidetop)) {
1110			$pdf->SetXY($this->postotalht - 1, $tab_top + 1);
1111			$pdf->MultiCell(30, 2, $outputlangs->transnoentities("TotalHTShort"), '', 'C');
1112		}
1113	}
1114
1115	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1116	/**
1117	 *  Show top header of page.
1118	 *
1119	 *  @param	TCPDF		$pdf     		Object PDF
1120	 *  @param  CommandeFournisseur		$object     	Object to show
1121	 *  @param  int	    	$showaddress    0=no, 1=yes
1122	 *  @param  Translate	$outputlangs	Object lang for output
1123	 *  @return	void
1124	 */
1125	protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs)
1126	{
1127		global $langs, $conf, $mysoc;
1128
1129		$ltrdirection = 'L';
1130		if ($outputlangs->trans("DIRECTION") == 'rtl') $ltrdirection = 'R';
1131
1132		// Load translation files required by the page
1133		$outputlangs->loadLangs(array("main", "orders", "companies", "bills", "sendings"));
1134
1135		$default_font_size = pdf_getPDFFontSize($outputlangs);
1136
1137		// Do not add the BACKGROUND as this is for suppliers
1138		//pdf_pagehead($pdf,$outputlangs,$this->page_hauteur);
1139
1140		//Affiche le filigrane brouillon - Print Draft Watermark
1141		/*if($object->statut==0 && (! empty($conf->global->COMMANDE_DRAFT_WATERMARK)) )
1142		{
1143			pdf_watermark($pdf,$outputlangs,$this->page_hauteur,$this->page_largeur,'mm',$conf->global->COMMANDE_DRAFT_WATERMARK);
1144		}*/
1145		//Print content
1146
1147		$pdf->SetTextColor(0, 0, 60);
1148		$pdf->SetFont('', 'B', $default_font_size + 3);
1149
1150		$posx = $this->page_largeur - $this->marge_droite - 100;
1151		$posy = $this->marge_haute;
1152
1153		$pdf->SetXY($this->marge_gauche, $posy);
1154
1155		// Logo
1156		$logo = $conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
1157		if ($this->emetteur->logo) {
1158			if (is_readable($logo)) {
1159				$height = pdf_getHeightForLogo($logo);
1160				$pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
1161			} else {
1162				$pdf->SetTextColor(200, 0, 0);
1163				$pdf->SetFont('', 'B', $default_font_size - 2);
1164				$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
1165				$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToModuleSetup"), 0, 'L');
1166			}
1167		} else {
1168			$text = $this->emetteur->name;
1169			$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);
1170		}
1171
1172		$pdf->SetFont('', 'B', $default_font_size + 3);
1173		$pdf->SetXY($posx, $posy);
1174		$pdf->SetTextColor(0, 0, 60);
1175		$title = $outputlangs->transnoentities("SupplierOrder")." ".$outputlangs->convToOutputCharset($object->ref);
1176		$pdf->MultiCell(100, 3, $title, '', 'R');
1177		$posy += 1;
1178
1179		if ($object->ref_supplier) {
1180			$posy += 4;
1181			$pdf->SetFont('', 'B', $default_font_size);
1182			$pdf->SetXY($posx, $posy);
1183			$pdf->SetTextColor(0, 0, 60);
1184			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefSupplier")." : ".$outputlangs->convToOutputCharset($object->ref_supplier), '', 'R');
1185			$posy += 1;
1186		}
1187
1188		$pdf->SetFont('', '', $default_font_size - 1);
1189
1190		if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) {
1191			$object->fetch_projet();
1192			if (!empty($object->project->ref)) {
1193				$posy += 3;
1194				$pdf->SetXY($posx, $posy);
1195				$pdf->SetTextColor(0, 0, 60);
1196				$pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->project->title), '', 'R');
1197			}
1198		}
1199
1200		if (!empty($conf->global->PDF_SHOW_PROJECT)) {
1201			$object->fetch_projet();
1202			if (!empty($object->project->ref)) {
1203				$outputlangs->load("projects");
1204				$posy += 4;
1205				$pdf->SetXY($posx, $posy);
1206				$langs->load("projects");
1207				$pdf->SetTextColor(0, 0, 60);
1208				$pdf->MultiCell(100, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R');
1209			}
1210		}
1211
1212		if (!empty($object->date_commande)) {
1213			$posy += 5;
1214			$pdf->SetXY($posx, $posy);
1215			$pdf->SetTextColor(0, 0, 60);
1216			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("OrderDate")." : ".dol_print_date($object->date_commande, "day", false, $outputlangs, true), '', 'R');
1217		} else {
1218			$posy += 5;
1219			$pdf->SetXY($posx, $posy);
1220			$pdf->SetTextColor(255, 0, 0);
1221			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("OrderToProcess"), '', 'R');
1222		}
1223
1224		$pdf->SetTextColor(0, 0, 60);
1225		$usehourmin = 'day';
1226		if (!empty($conf->global->SUPPLIER_ORDER_USE_HOUR_FOR_DELIVERY_DATE)) {
1227			$usehourmin = 'dayhour';
1228		}
1229		if (!empty($object->delivery_date)) {
1230			$posy += 4;
1231			$pdf->SetXY($posx - 90, $posy);
1232			$pdf->MultiCell(190, 3, $outputlangs->transnoentities("DateDeliveryPlanned")." : ".dol_print_date($object->delivery_date, $usehourmin, false, $outputlangs, true), '', 'R');
1233		}
1234
1235		if ($object->thirdparty->code_fournisseur) {
1236			$posy += 4;
1237			$pdf->SetXY($posx, $posy);
1238			$pdf->SetTextColor(0, 0, 60);
1239			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("SupplierCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_fournisseur), '', 'R');
1240		}
1241
1242		// Get contact
1243		if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) {
1244			$arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1245			if (count($arrayidcontact) > 0) {
1246				$usertmp = new User($this->db);
1247				$usertmp->fetch($arrayidcontact[0]);
1248				$posy += 4;
1249				$pdf->SetXY($posx, $posy);
1250				$pdf->SetTextColor(0, 0, 60);
1251				$pdf->MultiCell(100, 3, $langs->trans("BuyerName")." : ".$usertmp->getFullName($langs), '', 'R');
1252			}
1253		}
1254
1255		$posy += 1;
1256		$pdf->SetTextColor(0, 0, 60);
1257
1258		$top_shift = 0;
1259		// Show list of linked objects
1260		$current_y = $pdf->getY();
1261		$posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size);
1262		if ($current_y < $pdf->getY()) {
1263			$top_shift = $pdf->getY() - $current_y;
1264		}
1265
1266		if ($showaddress) {
1267			// Sender properties
1268			$carac_emetteur = '';
1269			// Add internal contact of proposal if defined
1270			$arrayidcontact = $object->getIdContact('internal', 'SALESREPFOLL');
1271			if (count($arrayidcontact) > 0) {
1272				$object->fetch_user($arrayidcontact[0]);
1273				$carac_emetteur .= ($carac_emetteur ? "\n" : '').$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs))."\n";
1274			}
1275
1276			$carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
1277
1278			// Show sender
1279			$posy = 42 + $top_shift;
1280			$posx = $this->marge_gauche;
1281			if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1282				$posx = $this->page_largeur - $this->marge_droite - 80;
1283			}
1284			$hautcadre = 40;
1285
1286			// Show sender frame
1287			$pdf->SetTextColor(0, 0, 0);
1288			$pdf->SetFont('', '', $default_font_size - 2);
1289			$pdf->SetXY($posx, $posy - 5);
1290			$pdf->MultiCell(80, 5, $outputlangs->transnoentities("BillFrom"), 0, $ltrdirection);
1291			$pdf->SetXY($posx, $posy);
1292			$pdf->SetFillColor(230, 230, 230);
1293			$pdf->MultiCell(82, $hautcadre, "", 0, 'R', 1);
1294			$pdf->SetTextColor(0, 0, 60);
1295
1296			// Show sender name
1297			$pdf->SetXY($posx + 2, $posy + 3);
1298			$pdf->SetFont('', 'B', $default_font_size);
1299			$pdf->MultiCell(80, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, $ltrdirection);
1300			$posy = $pdf->getY();
1301
1302			// Show sender information
1303			$pdf->SetXY($posx + 2, $posy);
1304			$pdf->SetFont('', '', $default_font_size - 1);
1305			$pdf->MultiCell(80, 4, $carac_emetteur, 0, $ltrdirection);
1306
1307
1308			// If CUSTOMER contact defined on order, we use it. Note: Even if this is a supplier object, the code for external contat that follow order is 'CUSTOMER'
1309			$usecontact = false;
1310			$arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
1311			if (count($arrayidcontact) > 0) {
1312				$usecontact = true;
1313				$result = $object->fetch_contact($arrayidcontact[0]);
1314			}
1315
1316			// Recipient name
1317			if ($usecontact && ($object->contact->socid != $object->thirdparty->id && (!isset($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT) || !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)))) {
1318				$thirdparty = $object->contact;
1319			} else {
1320				$thirdparty = $object->thirdparty;
1321			}
1322
1323			$carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);
1324
1325			$carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : ''), $usecontact, 'target', $object);
1326
1327			// Show recipient
1328			$widthrecbox = 100;
1329			if ($this->page_largeur < 210) {
1330				$widthrecbox = 84; // To work with US executive format
1331			}
1332			$posy = 42 + $top_shift;
1333			$posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
1334			if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {
1335				$posx = $this->marge_gauche;
1336			}
1337
1338			// Show recipient frame
1339			$pdf->SetTextColor(0, 0, 0);
1340			$pdf->SetFont('', '', $default_font_size - 2);
1341			$pdf->SetXY($posx + 2, $posy - 5);
1342			$pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo"), 0, $ltrdirection);
1343			$pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
1344
1345			// Show recipient name
1346			$pdf->SetXY($posx + 2, $posy + 3);
1347			$pdf->SetFont('', 'B', $default_font_size);
1348			$pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, $ltrdirection);
1349
1350			$posy = $pdf->getY();
1351
1352			// Show recipient information
1353			$pdf->SetFont('', '', $default_font_size - 1);
1354			$pdf->SetXY($posx + 2, $posy);
1355			$pdf->MultiCell($widthrecbox, 4, $carac_client, 0, $ltrdirection);
1356		}
1357
1358		return $top_shift;
1359	}
1360
1361	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1362	/**
1363	 *  Show footer of page. Need this->emetteur object
1364	 *
1365	 *  @param	TCPDF		$pdf     			PDF
1366	 *  @param	CommandeFournisseur		$object				Object to show
1367	 *  @param	Translate	$outputlangs		Object lang for output
1368	 *  @param	int			$hidefreetext		1=Hide free text
1369	 *  @return	int								Return height of bottom margin including footer text
1370	 */
1371	protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
1372	{
1373		global $conf;
1374		$showdetails = empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS) ? 0 : $conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS;
1375		return pdf_pagefoot($pdf, $outputlangs, 'SUPPLIER_ORDER_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext);
1376	}
1377}
1378