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