dolibarr  19.0.0-dev
pdf_standard.modules.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2017 Laurent Destailleur <eldy@stocks.sourceforge.net>
3  * Copyright (C) 2022 Ferran Marcet <fmarcet@2byte.es>
4  * Copyright (C) 2022 Nicolas Silobre <nsilobre@ns-info90.fr>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18  * or see https://www.gnu.org/
19  */
20 
27 require_once DOL_DOCUMENT_ROOT.'/core/modules/stock/modules_stock.php';
28 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
29 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
30 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
31 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
32 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
33 require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
34 
35 
39 class pdf_standard extends ModelePDFStock
40 {
44  public $db;
45 
49  public $name;
50 
54  public $description;
55 
59  public $type;
60 
65  public $version = 'dolibarr';
66 
71  public $emetteur;
72 
73  public $wref;
74  public $posxdesc;
75  public $posxlabel;
76  public $posxtva;
77  public $posxqty;
78  public $posxup;
79  public $posxunit;
80  public $posxdiscount;
81  public $postotalht;
82 
83  public $tabTitleHeight;
84 
85 
91  public function __construct($db)
92  {
93  global $conf, $langs, $mysoc;
94 
95  // Load traductions files required by page
96  $langs->loadLangs(array("main", "companies"));
97 
98  $this->db = $db;
99  $this->name = "standard";
100  $this->description = $langs->trans("DocumentModelStandardPDF");
101 
102  // Page size for A4 format
103  $this->type = 'pdf';
104  $formatarray = pdf_getFormat();
105  $this->page_largeur = $formatarray['width'];
106  $this->page_hauteur = $formatarray['height'];
107  $this->format = array($this->page_largeur, $this->page_hauteur);
108  $this->marge_gauche = getDolGlobalInt('MAIN_PDF_MARGIN_LEFT', 10);
109  $this->marge_droite = getDolGlobalInt('MAIN_PDF_MARGIN_RIGHT', 10);
110  $this->marge_haute = getDolGlobalInt('MAIN_PDF_MARGIN_TOP', 10);
111  $this->marge_basse = getDolGlobalInt('MAIN_PDF_MARGIN_BOTTOM', 10);
112 
113  $this->option_logo = 1; // Display logo
114  $this->option_codestockservice = 0; // Display product-service code
115  $this->option_multilang = 1; // Available in several languages
116  $this->option_freetext = 0; // Support add of a personalised text
117 
118  // Get source company
119  $this->emetteur = $mysoc;
120  if (!$this->emetteur->country_code) {
121  $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default if not defined
122  }
123 
124  // Define position of columns
125  $this->wref = 35;
126  $this->posxdesc = $this->marge_gauche + 1;
127  $this->posxlabel = $this->posxdesc + $this->wref;
128  $this->posxtva = 80;
129  $this->posxqty = 95;
130  $this->posxup = 115;
131  $this->posxunit = 135;
132  $this->posxdiscount = 155;
133  $this->postotalht = 175;
134 
135  if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) || !empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {
136  $this->posxtva = $this->posxup;
137  }
138  $this->posxpicture = $this->posxtva - (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH) ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH); // width of images
139  if ($this->page_largeur < 210) { // To work with US executive format
140  $this->posxpicture -= 20;
141  $this->posxtva -= 20;
142  $this->posxup -= 20;
143  $this->posxqty -= 20;
144  $this->posxunit -= 20;
145  $this->posxdiscount -= 20;
146  $this->postotalht -= 20;
147  }
148 
149  $this->tabTitleHeight = 11;
150  }
151 
152 
153  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
165  public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
166  {
167  // phpcs:enable
168  global $user, $langs, $conf, $mysoc, $db, $hookmanager;
169 
170  if (!is_object($outputlangs)) {
171  $outputlangs = $langs;
172  }
173  // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
174  if (!empty($conf->global->MAIN_USE_FPDF)) {
175  $outputlangs->charset_output = 'ISO-8859-1';
176  }
177 
178  // Load traductions files required by page
179  $outputlangs->loadLangs(array("main", "dict", "companies", "bills", "stocks", "orders", "deliveries"));
180 
181  if ($conf->stock->dir_output) {
182  // Definition of $dir and $file
183  if ($object->specimen) {
184  $dir = $conf->stock->dir_output;
185  $file = $dir."/SPECIMEN.pdf";
186  } else {
187  $objectref = dol_sanitizeFileName($object->ref);
188  $dir = $conf->stock->dir_output."/".$objectref;
189  $file = $dir."/".$objectref.".pdf";
190  }
191 
192  $stockFournisseur = new ProductFournisseur($this->db);
193  $supplierprices = $stockFournisseur->list_product_fournisseur_price($object->id);
194  $object->supplierprices = $supplierprices;
195 
196  $productstatic = new Product($this->db);
197 
198  if (!file_exists($dir)) {
199  if (dol_mkdir($dir) < 0) {
200  $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
201  return -1;
202  }
203  }
204 
205  if (file_exists($dir)) {
206  // Add pdfgeneration hook
207  if (!is_object($hookmanager)) {
208  include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
209  $hookmanager = new HookManager($this->db);
210  }
211  $hookmanager->initHooks(array('pdfgeneration'));
212  $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
213  global $action;
214  $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
215 
216  // Create pdf instance
217  $pdf = pdf_getInstance($this->format);
218  $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
219  $pdf->SetAutoPageBreak(1, 0);
220 
221  $heightforinfotot = 40; // Height reserved to output the info and total part
222  $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
223  $heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin)
224  if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)) {
225  $heightforfooter += 6;
226  }
227 
228  if (class_exists('TCPDF')) {
229  $pdf->setPrintHeader(false);
230  $pdf->setPrintFooter(false);
231  }
232  $pdf->SetFont(pdf_getPDFFont($outputlangs));
233  // Set path to the background PDF File
234  if (empty($conf->global->MAIN_DISABLE_FPDI) && !empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) {
235  $pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND);
236  $tplidx = $pdf->importPage(1);
237  }
238 
239  $pdf->Open();
240  $pagenb = 0;
241  $pdf->SetDrawColor(128, 128, 128);
242 
243  $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
244  $pdf->SetSubject($outputlangs->transnoentities("Stock"));
245  $pdf->SetCreator("Dolibarr ".DOL_VERSION);
246  $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
247  $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("Stock")." ".$outputlangs->convToOutputCharset($object->label));
248  if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
249  $pdf->SetCompression(false);
250  }
251 
252  $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
253 
254 
255  // New page
256  $pdf->AddPage();
257  if (!empty($tplidx)) {
258  $pdf->useTemplate($tplidx);
259  }
260  $pagenb++;
261  $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs);
262  $pdf->SetFont('', '', $default_font_size - 1);
263  $pdf->MultiCell(0, 3, ''); // Set interline to 3
264  $pdf->SetTextColor(0, 0, 0);
265 
266  $tab_top = 65 + $top_shift;
267  $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
268 
269  $tab_height = $this->page_hauteur - $tab_top - $heightforfooter - $heightforfreetext;
270 
271 
272  // Show list of product in warehouse */
273 
274  $totalunit = 0;
275  $totalvalue = $totalvaluesell = 0;
276 
277  $sortfield = 'p.ref';
278  $sortorder = 'ASC';
279 
280  $sql = "SELECT p.rowid as rowid, p.ref, p.label as produit, p.tobatch, p.fk_product_type as type, p.pmp as ppmp, p.price, p.price_ttc, p.entity,";
281  $sql .= " ps.reel as value";
282  $sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps, ".MAIN_DB_PREFIX."product as p";
283  $sql .= " WHERE ps.fk_product = p.rowid";
284  $sql .= " AND ps.reel <> 0"; // We do not show if stock is 0 (no product in this warehouse)
285  $sql .= " AND ps.fk_entrepot = ".((int) $object->id);
286  $sql .= $this->db->order($sortfield, $sortorder);
287 
288  //dol_syslog('List products', LOG_DEBUG);
289  $resql = $this->db->query($sql);
290  if ($resql) {
291  $num = $this->db->num_rows($resql);
292  $i = 0;
293  $nblines = $num;
294 
295  $nexY = $tab_top + $this->tabTitleHeight;
296 
297  for ($i = 0; $i < $nblines; $i++) {
298  $curY = $nexY;
299 
300  $objp = $this->db->fetch_object($resql);
301 
302  // Multilangs
303  if (getDolGlobalInt('MAIN_MULTILANGS')) { // si l'option est active
304  $sql = "SELECT label";
305  $sql .= " FROM ".MAIN_DB_PREFIX."product_lang";
306  $sql .= " WHERE fk_product = ".((int) $objp->rowid);
307  $sql .= " AND lang = '".$this->db->escape($langs->getDefaultLang())."'";
308  $sql .= " LIMIT 1";
309 
310  $result = $this->db->query($sql);
311  if ($result) {
312  $objtp = $this->db->fetch_object($result);
313  if ($objtp->label != '') {
314  $objp->produit = $objtp->label;
315  }
316  }
317  }
318 
319  $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
320  $pdf->SetTextColor(0, 0, 0);
321 
322  $pdf->setTopMargin($tab_top_newpage);
323  $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext + $heightforinfotot); // The only function to edit the bottom margin of current page to set it.
324  $pageposbefore = $pdf->getPage();
325 
326  // Description of product line
327  $curX = $this->posxdesc - 1;
328 
329  $showpricebeforepagebreak = 1;
330 
331  $pdf->startTransaction();
332  $pdf->writeHTMLCell($this->wref, 3, $curX, $curY, $outputlangs->convToOutputCharset($objp->ref), 0, 1, false, true, 'J', true);
333  //pdf_writelinedesc($pdf, $object, $i, $outputlangs, $this->posxtva - $curX, 3, $curX, $curY, $hideref, $hidedesc);
334  $pageposafter = $pdf->getPage();
335  if ($pageposafter > $pageposbefore) { // There is a pagebreak
336  $pdf->rollbackTransaction(true);
337  $pageposafter = $pageposbefore;
338  //print $pageposafter.'-'.$pageposbefore;exit;
339  $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
340  $pdf->writeHTMLCell($this->wref, 4, $curX, $curY, $outputlangs->convToOutputCharset($objp->ref), 0, 1, false, true, 'J', true);
341  //pdf_writelinedesc($pdf, $object, $i, $outputlangs, $this->posxtva - $curX, 4, $curX, $curY, $hideref, $hidedesc);
342  $pageposafter = $pdf->getPage();
343  $posyafter = $pdf->GetY();
344  if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) { // There is no space left for total+free text
345  if ($i == ($nblines - 1)) { // No more lines, and no space left to show total, so we create a new page
346  $pdf->AddPage('', '', true);
347  if (!empty($tplidx)) {
348  $pdf->useTemplate($tplidx);
349  }
350  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
351  $this->_pagehead($pdf, $object, 0, $outputlangs);
352  }
353  $pdf->setPage($pageposafter + 1);
354  }
355  } else {
356  // We found a page break
357 
358  // Allows data in the first page if description is long enough to break in multiples pages
359  if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {
360  $showpricebeforepagebreak = 1;
361  } else {
362  $showpricebeforepagebreak = 0;
363  }
364  }
365  } else // No pagebreak
366  {
367  $pdf->commitTransaction();
368  }
369  $posYAfterDescription = $pdf->GetY();
370 
371  $nexY = $pdf->GetY();
372  $pageposafter = $pdf->getPage();
373 
374  $pdf->setPage($pageposbefore);
375  $pdf->setTopMargin($this->marge_haute);
376  $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
377 
378  // We suppose that a too long description is moved completely on next page
379  if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
380  $pdf->setPage($pageposafter);
381  $curY = $tab_top_newpage;
382  }
383 
384  $pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par defaut
385 
386  $productstatic->id = $objp->rowid;
387  $productstatic->ref = $objp->ref;
388  $productstatic->label = $objp->produit;
389  $productstatic->type = $objp->type;
390  $productstatic->entity = $objp->entity;
391  $productstatic->status_batch = $objp->tobatch;
392 
393  // Ref.
394  //$pdf->SetXY($this->posxdesc, $curY);
395  //$pdf->MultiCell($this->wref, 3, $productstatic->ref, 0, 'L');
396 
397  // Label
398  $pdf->SetXY($this->posxlabel + 0.8, $curY);
399  $pdf->MultiCell($this->posxqty - $this->posxlabel - 0.8, 3, dol_trunc($productstatic->label, 24), 0, 'L');
400 
401  // Quantity
402  $valtoshow = price2num($objp->value, 'MS');
403  $towrite = (empty($valtoshow) ? '0' : $valtoshow);
404 
405  $pdf->SetXY($this->posxqty, $curY);
406  $pdf->MultiCell($this->posxup - $this->posxqty - 0.8, 3, $towrite, 0, 'R');
407 
408  // AWP
409  $totalunit += $objp->value;
410 
411  $pdf->SetXY($this->posxup, $curY);
412  $pdf->MultiCell($this->posxunit - $this->posxup - 0.8, 3, price(price2num($objp->ppmp, 'MU'), 0, $outputlangs), 0, 'R');
413 
414  // Total PMP
415  $pdf->SetXY($this->posxunit, $curY);
416  $pdf->MultiCell($this->posxdiscount - $this->posxunit - 0.8, 3, price(price2num($objp->ppmp * $objp->value, 'MT'), 0, $outputlangs), 0, 'R');
417  $totalvalue += price2num($objp->ppmp * $objp->value, 'MT');
418 
419  // Price sell min
420  if (empty($conf->global->PRODUIT_MULTIPRICES)) {
421  $pricemin = $objp->price;
422  $pdf->SetXY($this->posxdiscount, $curY);
423  $pdf->MultiCell($this->postotalht - $this->posxdiscount, 3, price(price2num($pricemin, 'MU'), 0, $outputlangs), 0, 'R', 0);
424 
425  // Total sell min
426  $pdf->SetXY($this->postotalht, $curY);
427  $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->postotalht, 3, price(price2num($pricemin * $objp->value, 'MT'), 0, $outputlangs), 0, 'R', 0);
428  }
429  $totalvaluesell += price2num($pricemin * $objp->value, 'MT');
430 
431  // Add line
432  if (!empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblines - 1)) {
433  $pdf->setPage($pageposafter);
434  $pdf->SetLineStyle(array('dash'=>'1,1', 'color'=>array(80, 80, 80)));
435  //$pdf->SetDrawColor(190,190,200);
436  $pdf->line($this->marge_gauche, $nexY + 1, $this->page_largeur - $this->marge_droite, $nexY + 1);
437  $pdf->SetLineStyle(array('dash'=>0));
438  }
439 
440  $nexY += 2; // Add space between lines
441 
442  // Detect if some page were added automatically and output _tableau for past pages
443  while ($pagenb < $pageposafter) {
444  $pdf->setPage($pagenb);
445  if ($pagenb == 1) {
446  $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
447  } else {
448  $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
449  }
450  $this->_pagefoot($pdf, $object, $outputlangs, 1);
451  $pagenb++;
452  $pdf->setPage($pagenb);
453  $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it.
454  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
455  $this->_pagehead($pdf, $object, 0, $outputlangs);
456  }
457  if (!empty($tplidx)) {
458  $pdf->useTemplate($tplidx);
459  }
460  }
461  if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) {
462  if ($pagenb == 1) {
463  $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
464  } else {
465  $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
466  }
467  $this->_pagefoot($pdf, $object, $outputlangs, 1);
468  // New page
469  $pdf->AddPage();
470  if (!empty($tplidx)) {
471  $pdf->useTemplate($tplidx);
472  }
473  $pagenb++;
474  if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
475  $this->_pagehead($pdf, $object, 0, $outputlangs);
476  }
477  }
478  }
479 
480  $this->db->free($resql);
481 
485  //$nexY = $pdf->GetY();
486  $nexY += 2;
487  $curY = $nexY;
488 
489  if ($nblines > 0) {
490  $pdf->SetLineStyle(array('dash'=>'0', 'color'=>array(200, 200, 200)));
491  $pdf->line($this->marge_gauche, $curY - 1, $this->page_largeur - $this->marge_droite, $curY - 1);
492  $pdf->SetLineStyle(array('dash'=>0));
493 
494  $pdf->SetFont('', 'B', $default_font_size - 1);
495  $pdf->SetTextColor(0, 0, 0);
496 
497  // Ref.
498  $pdf->SetXY($this->posxdesc, $curY);
499  $pdf->MultiCell($this->wref, 3, $langs->trans("Total"), 0, 'L');
500 
501  // Quantity
502  $valtoshow = price2num($totalunit, 'MS');
503  $towrite = empty($valtoshow) ? '0' : $valtoshow;
504 
505  $pdf->SetXY($this->posxqty, $curY);
506  $pdf->MultiCell($this->posxup - $this->posxqty - 0.8, 3, $towrite, 0, 'R');
507 
508  // Total PMP
509  $pdf->SetXY($this->posxunit, $curY);
510  $pdf->MultiCell($this->posxdiscount - $this->posxunit - 0.8, 3, price(price2num($totalvalue, 'MT'), 0, $outputlangs), 0, 'R');
511 
512  // Price sell min
513  if (empty($conf->global->PRODUIT_MULTIPRICES)) {
514  // Total sell min
515  $pdf->SetXY($this->postotalht, $curY);
516  $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->postotalht, 3, price(price2num($totalvaluesell, 'MT'), 0, $outputlangs), 0, 'R', 0);
517  }
518  }
519  } else {
520  dol_print_error($this->db);
521  }
522 
523  // Displays notes
524  $notetoshow = empty($object->note_public) ? '' : $object->note_public;
525 
526  if ($notetoshow) {
527  $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
528  complete_substitutions_array($substitutionarray, $outputlangs, $object);
529  $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
530  $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);
531 
532  $tab_top = 88;
533 
534  $pdf->SetFont('', '', $default_font_size - 1);
535  $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
536  $nexY = $pdf->GetY();
537  $height_note = $nexY - $tab_top;
538 
539  // Rect takes a length in 3rd parameter
540  $pdf->SetDrawColor(192, 192, 192);
541  $pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_note + 1);
542 
543  $tab_height = $tab_height - $height_note;
544  $tab_top = $nexY + 6;
545  } else {
546  $height_note = 0;
547  }
548 
549  /*$iniY = $tab_top + 7;
550  $curY = $tab_top + 7;
551  $nexY = $tab_top + 7;
552 
553  $tab_top = $tab_top_newpage + 25 + $top_shift;*/
554 
555  // Show square
556  if ($pagenb == 1) {
557  $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code);
558  $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
559  } else {
560  $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code);
561  $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
562  }
563 
564  $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
565 
566  // Affiche zone infos
567  //$posy=$this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs);
568 
569  // Affiche zone totaux
570  //$posy=$this->_tableau_tot($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs);
571 
572  // Pied de page
573  $this->_pagefoot($pdf, $object, $outputlangs);
574  if (method_exists($pdf, 'AliasNbPages')) {
575  $pdf->AliasNbPages();
576  }
577 
578  $pdf->Close();
579 
580  $pdf->Output($file, 'F');
581 
582  // Add pdfgeneration hook
583  $hookmanager->initHooks(array('pdfgeneration'));
584  $parameters = array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
585  global $action;
586  $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
587  if ($reshook < 0) {
588  $this->error = $hookmanager->error;
589  $this->errors = $hookmanager->errors;
590  }
591 
592  dolChmod($file);
593 
594  $this->result = array('fullpath'=>$file);
595 
596  return 1; // No error
597  } else {
598  $this->error = $langs->trans("ErrorCanNotCreateDir", $dir);
599  return 0;
600  }
601  } else {
602  $this->error = $langs->trans("ErrorConstantNotDefined", "PRODUCT_OUTPUTDIR");
603  return 0;
604  }
605  }
606 
607  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
621  protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '')
622  {
623  global $conf;
624 
625  // Force to disable hidetop and hidebottom
626  $hidebottom = 0;
627  if ($hidetop) {
628  $hidetop = -1;
629  }
630 
631  $currency = !empty($currency) ? $currency : $conf->currency;
632  $default_font_size = pdf_getPDFFontSize($outputlangs);
633 
634  // Amount in (at tab_top - 1)
635  $pdf->SetTextColor(0, 0, 0);
636  $pdf->SetFont('', '', $default_font_size - 2);
637 
638  if (empty($hidetop)) {
639  $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
640  $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
641  $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
642 
643  //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
644  if (!empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) {
645  $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));
646  }
647  }
648 
649  $pdf->SetDrawColor(128, 128, 128);
650 
651  $pdf->SetFont('', 'B', $default_font_size - 3);
652 
653  // Output Rect
654  $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
655 
656  $pdf->SetLineStyle(array('dash'=>'0', 'color'=>array(200, 200, 200)));
657  $pdf->SetDrawColor(200, 200, 200);
658  $pdf->line($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite, $tab_top);
659  $pdf->SetLineStyle(array('dash'=>0));
660  $pdf->SetDrawColor(128, 128, 128);
661  $pdf->SetTextColor(0, 0, 0);
662 
663 
664  if (empty($hidetop)) {
665  $pdf->line($this->marge_gauche, $tab_top+11, $this->page_largeur-$this->marge_droite, $tab_top+11); // line takes a position y in 2nd parameter and 4th parameter
666  $pdf->SetXY($this->posxdesc - 1, $tab_top + 1);
667  $pdf->MultiCell($this->wref, 3, $outputlangs->transnoentities("Ref"), '', 'L');
668  }
669 
670  $pdf->line($this->posxlabel-1, $tab_top, $this->posxlabel-1, $tab_top + $tab_height);
671  if (empty($hidetop)) {
672  $pdf->SetXY($this->posxlabel - 1, $tab_top + 1);
673  $pdf->MultiCell($this->posxqty - $this->posxlabel - 1, 2, $outputlangs->transnoentities("Label"), '', 'C');
674  }
675 
676  $pdf->line($this->posxqty-1, $tab_top, $this->posxqty-1, $tab_top + $tab_height);
677  if (empty($hidetop)) {
678  $pdf->SetXY($this->posxqty - 1, $tab_top + 1);
679  $pdf->MultiCell($this->posxup - $this->posxqty - 1, 2, $outputlangs->transnoentities("Units"), '', 'C');
680  }
681 
682  $pdf->line($this->posxup-1, $tab_top, $this->posxup-1, $tab_top + $tab_height);
683  if (empty($hidetop)) {
684  $pdf->SetXY($this->posxup - 1, $tab_top + 1);
685  $pdf->MultiCell($this->posxunit - $this->posxup - 1, 2, $outputlangs->transnoentities("AverageUnitPricePMPShort"), '', 'C');
686  }
687 
688  $pdf->line($this->posxunit - 1, $tab_top, $this->posxunit - 1, $tab_top + $tab_height);
689  if (empty($hidetop)) {
690  $pdf->SetXY($this->posxunit - 1, $tab_top + 1);
691  $pdf->MultiCell($this->posxdiscount - $this->posxunit - 1, 2, $outputlangs->transnoentities("EstimatedStockValueShort"), '', 'C');
692  }
693 
694  $pdf->line($this->posxdiscount-1, $tab_top, $this->posxdiscount-1, $tab_top + $tab_height);
695  if (empty($hidetop)) {
696  $pdf->SetXY($this->posxdiscount - 1, $tab_top + 1);
697  $pdf->MultiCell($this->postotalht - $this->posxdiscount + 1, 2, $outputlangs->transnoentities("SellPriceMin"), '', 'C');
698  }
699 
700  $pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height);
701  if (empty($hidetop)) {
702  $pdf->SetXY($this->postotalht - 1, $tab_top + 1);
703  $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->postotalht, 2, $outputlangs->transnoentities("EstimatedStockValueSellShort"), '', 'C');
704  }
705 
706  if (empty($hidetop)) {
707  $pdf->SetDrawColor(200, 200, 200);
708  $pdf->SetLineStyle(array('dash' => '0', 'color' => array(200, 200, 200)));
709  $pdf->line($this->marge_gauche, $tab_top + $this->tabTitleHeight, $this->page_largeur - $this->marge_droite, $tab_top + $this->tabTitleHeight);
710  $pdf->SetLineStyle(array('dash' => 0));
711  }
712  }
713 
714  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
725  protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $titlekey = "")
726  {
727  global $conf, $langs, $db, $hookmanager;
728 
729  // Load traductions files required by page
730  $outputlangs->loadLangs(array("main", "propal", "companies", "bills", "orders", "stocks"));
731 
732  $default_font_size = pdf_getPDFFontSize($outputlangs);
733 
734  if ($object->type == 1) {
735  $titlekey = 'ServiceSheet';
736  } else {
737  $titlekey = 'StockSheet';
738  }
739 
740  pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
741 
742  // Show Draft Watermark
743  if ($object->statut == 0 && (!empty($conf->global->STOCK_DRAFT_WATERMARK))) {
744  pdf_watermark($pdf, $outputlangs, $this->page_hauteur, $this->page_largeur, 'mm', $conf->global->STOCK_DRAFT_WATERMARK);
745  }
746 
747  $pdf->SetTextColor(0, 0, 60);
748  $pdf->SetFont('', 'B', $default_font_size + 3);
749 
750  $posy = $this->marge_haute;
751  $posx = $this->page_largeur - $this->marge_droite - 100;
752 
753  $pdf->SetXY($this->marge_gauche, $posy);
754 
755  // Logo
756  $height = 0;
757  $logo = $conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
758  if ($this->emetteur->logo) {
759  if (is_readable($logo)) {
760  $height = pdf_getHeightForLogo($logo);
761  $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
762  } else {
763  $pdf->SetTextColor(200, 0, 0);
764  $pdf->SetFont('', 'B', $default_font_size - 2);
765  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
766  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
767  }
768  } else {
769  $text = $this->emetteur->name;
770  $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
771  }
772 
773  $yafterleft = $pdf->GetY() + $height;
774 
775  $pdf->SetFont('', 'B', $default_font_size + 3);
776  $pdf->SetXY($posx, $posy);
777  $pdf->SetTextColor(0, 0, 60);
778 
779  $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Warehouse").' '.$outputlangs->convToOutputCharset($object->label), '', 'R');
780 
781  $posy += 6;
782  $pdf->SetFont('', '', $default_font_size - 1);
783  $pdf->SetXY($posx, $posy);
784  $pdf->SetTextColor(0, 0, 60);
785  if (!empty($object->lieu)) {
786  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Label").' : '.$object->lieu, '', 'R');
787  }
788 
789 
790  $posy += 4;
791  $pdf->SetXY($posx, $posy);
792  $pdf->SetTextColor(0, 0, 60);
793 
794  // Parent warehouse
795  $e = new Entrepot($this->db);
796  $hasparent = (!empty($object->fk_parent) && $e->fetch($object->fk_parent) > 0);
797 
798  if ($hasparent) {
799  $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ParentWarehouse").' :', '', 'R');
800 
801  $posy += 4;
802  $pdf->SetXY($posx - 50, $posy);
803  $pdf->MultiCell(150, 3, $e->label, '', 'R');
804  }
805 
806  $yafterright = $pdf->GetY();
807 
808  // Description
809  $nbpage = $pdf->getPage();
810  if ($nbpage == 1) {
811  $nexY = max($yafterleft, $yafterright);
812  $nexY += 5;
813  $pdf->SetXY($posx, $posy);
814  $pdf->writeHTMLCell(190, 2, $this->marge_gauche, $nexY, '<b>'.$outputlangs->transnoentities("Description").' : </b>'.nl2br($object->description), 0, 1);
815  $nexY = $pdf->GetY();
816 
817  $calcproductsunique = $object->nb_different_products();
818  $calcproducts = $object->nb_products();
819 
820  // Total nb of different products
821  $pdf->writeHTMLCell(190, 2, $this->marge_gauche, $nexY, '<b>'.$outputlangs->transnoentities("NumberOfDifferentProducts").' : </b>'.(empty($calcproductsunique['nb']) ? '0' : $calcproductsunique['nb']), 0, 1);
822  $nexY = $pdf->GetY();
823 
824  // Nb of products
825  $valtoshow = price2num($calcproducts['nb'], 'MS');
826  $pdf->writeHTMLCell(190, 2, $this->marge_gauche, $nexY, '<b>'.$outputlangs->transnoentities("NumberOfProducts").' : </b>'.(empty($valtoshow) ? '0' : $valtoshow), 0, 1);
827  $nexY = $pdf->GetY();
828 
829  // Value
830  $pdf->writeHTMLCell(190, 2, $this->marge_gauche, $nexY, '<b>'.$outputlangs->transnoentities("EstimatedStockValueShort").' : </b>'.price((empty($calcproducts['value']) ? '0' : price2num($calcproducts['value'], 'MT')), 0, $langs, 0, -1, -1, $conf->currency), 0, 1);
831  $nexY = $pdf->GetY();
832 
833  // Value
834  $pdf->writeHTMLCell(190, 2, $this->marge_gauche, $nexY, '<b>'.$outputlangs->transnoentities("Date").' : </b>'.dol_print_date(dol_now(), 'dayhour'), 0, 1);
835  $nexY = $pdf->GetY();
836 
837  // Last movement
838  $sql = "SELECT max(m.datem) as datem";
839  $sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement as m";
840  $sql .= " WHERE m.fk_entrepot = ".((int) $object->id);
841  $resqlbis = $this->db->query($sql);
842  if ($resqlbis) {
843  $obj = $this->db->fetch_object($resqlbis);
844  $lastmovementdate = $this->db->jdate($obj->datem);
845  } else {
846  dol_print_error($this->db);
847  }
848 
849  if ($lastmovementdate) {
850  $toWrite = dol_print_date($lastmovementdate, 'dayhour').' ';
851  } else {
852  $toWrite = $outputlangs->transnoentities("None");
853  }
854 
855  $pdf->writeHTMLCell(190, 2, $this->marge_gauche, $nexY, '<b>'.$outputlangs->transnoentities("LastMovement").' : </b>'.$toWrite, 0, 1);
856  }
857  $nexY = $pdf->GetY();
858 
859  $posy += 2;
860 
861  $top_shift = 0;
862  // Show list of linked objects
863  $current_y = $pdf->getY();
864  $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size);
865  if ($current_y < $pdf->getY()) {
866  $top_shift = $pdf->getY() - $current_y;
867  }
868 
869  $pdf->SetTextColor(0, 0, 0);
870 
871  return $top_shift;
872  }
873 
874  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
884  protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
885  {
886  $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0);
887  return pdf_pagefoot($pdf, $outputlangs, 'PRODUCT_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext);
888  }
889 }
printRect($pdf, $x, $y, $l, $h, $hidetop=0, $hidebottom=0)
Rect pdf.
Class to manage warehouses.
Class to manage hooks.
Parent class for stock models of doc generators.
Class to manage predefined suppliers products.
Class to manage products or services.
Class to generate expense report based on standard model.
__construct($db)
Constructor.
_tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='')
Show table for lines.
_pagehead(&$pdf, $object, $showaddress, $outputlangs)
Show top header of page.
_pagehead(&$pdf, $object, $showaddress, $outputlangs, $titlekey="")
Show top header of page.
_pagefoot(&$pdf, $object, $outputlangs, $hidefreetext=0)
Show footer of page.
write_file($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0)
Function to build a document on disk using the generic odt module.
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
print *****$script_file(".$version.") pid cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
if(!function_exists('dolEscapeXML')) convertBackOfficeMediasLinksToPublicLinks($notetoshow)
Convert links to local wrapper to medias files into a string into a public external URL readable on i...
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
pdf_getPDFFontSize($outputlangs)
Return font size to use for PDF generation.
Definition: pdf.lib.php:289
pdf_getFormat(Translate $outputlangs=null, $mode='setup')
Return array with format properties of default PDF format.
Definition: pdf.lib.php:85
pdf_getHeightForLogo($logo, $url=false)
Return height to use for Logo onto PDF.
Definition: pdf.lib.php:314
pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_basse, $marge_gauche, $page_hauteur, $object, $showdetails=0, $hidefreetext=0, $page_largeur=0, $watermark='')
Show footer of page for PDF generation.
Definition: pdf.lib.php:1005
pdf_pagehead(&$pdf, $outputlangs, $page_height)
Show header of page for PDF generation.
Definition: pdf.lib.php:721
pdf_writeLinkedObjects(&$pdf, $object, $outputlangs, $posx, $posy, $w, $h, $align, $default_font_size)
Show linked objects for PDF generation.
Definition: pdf.lib.php:1333
pdf_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition: pdf.lib.php:266
pdf_getSubstitutionArray($outputlangs, $exclude=null, $object=null, $onlykey=0, $include=null)
Return array of possible substitutions for PDF content (without external module substitutions).
Definition: pdf.lib.php:753
pdf_getInstance($format='', $metric='mm', $pagetype='P')
Return a PDF instance object.
Definition: pdf.lib.php:127
pdf_watermark(&$pdf, $outputlangs, $h, $w, $unit, $text)
Add a draft watermark on PDF files.
Definition: pdf.lib.php:773
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:120
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:123