dolibarr 24.0.0-beta
pdf_standard_stock.modules.php
1<?php
2
3/* Copyright (C) 2017 Laurent Destailleur <eldy@stocks.sourceforge.net>
4 * Copyright (C) 2022 Ferran Marcet <fmarcet@2byte.es>
5 * Copyright (C) 2022 Nicolas Silobre <nsilobre@ns-info90.fr>
6 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
7 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
8 * Copyright (C) 2024 Nick Fragoulis
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
31require_once DOL_DOCUMENT_ROOT.'/core/modules/stock/modules_stock.php';
32require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
33require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.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/files.lib.php';
37require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
38
39
44{
48 public $wref;
52 public $posxdesc;
56 public $posxlabel;
60 public $posxtva;
64 public $posxqty;
68 public $posxup;
72 public $posxunit;
76 public $posxdiscount;
80 public $postotalht;
81
85 public $tabTitleHeight;
86
87
93 public function __construct($db)
94 {
95 global $conf, $langs, $mysoc;
96
97 // Load traductions files required by page
98 $langs->loadLangs(array("main", "companies"));
99
100 $this->db = $db;
101 $this->name = "standard";
102 $this->description = $langs->trans("DocumentModelStandardPDF");
103
104 // Page size for A4 format
105 $this->type = 'pdf';
106 $formatarray = pdf_getFormat();
107 $this->page_largeur = $formatarray['width'];
108 $this->page_hauteur = $formatarray['height'];
109 $this->format = array($this->page_largeur, $this->page_hauteur);
110 $this->marge_gauche = getDolGlobalInt('MAIN_PDF_MARGIN_LEFT', 10);
111 $this->marge_droite = getDolGlobalInt('MAIN_PDF_MARGIN_RIGHT', 10);
112 $this->marge_haute = getDolGlobalInt('MAIN_PDF_MARGIN_TOP', 10);
113 $this->marge_basse = getDolGlobalInt('MAIN_PDF_MARGIN_BOTTOM', 10);
114 $this->corner_radius = getDolGlobalInt('MAIN_PDF_FRAME_CORNER_RADIUS', 0);
115 $this->option_logo = 1; // Display logo
116 $this->option_multilang = 1; // Available in several languages
117 $this->option_freetext = 0; // Support add of a personalised text
118
119 // Define position of columns
120 $this->wref = 35;
121 $this->posxdesc = $this->marge_gauche + 1;
122 $this->posxlabel = $this->posxdesc + $this->wref;
123 $this->posxtva = 80;
124 $this->posxqty = 95;
125 $this->posxup = 115;
126 $this->posxunit = 135;
127 $this->posxdiscount = 155;
128 $this->postotalht = 175;
129
130 if (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT') || getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN')) {
131 $this->posxtva = $this->posxup;
132 }
133 $this->posxpicture = $this->posxtva - getDolGlobalInt('MAIN_DOCUMENTS_WITH_PICTURE_WIDTH', 20); // width of images
134 if ($this->page_largeur < 210) { // To work with US executive format
135 $this->posxpicture -= 20;
136 $this->posxtva -= 20;
137 $this->posxup -= 20;
138 $this->posxqty -= 20;
139 $this->posxunit -= 20;
140 $this->posxdiscount -= 20;
141 $this->postotalht -= 20;
142 }
143
144 $this->tabTitleHeight = 11;
145
146 if ($mysoc === null) {
147 dol_syslog(get_class($this).'::__construct() Global $mysoc should not be null.'. getCallerInfoString(), LOG_ERR);
148 return;
149 }
150
151 // Get source company
152 $this->emetteur = $mysoc;
153 if (!$this->emetteur->country_code) {
154 $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default if not defined
155 }
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 (getDolGlobalString('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", "sendings"));
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 $productstatic = new Product($this->db);
199
200 if (!file_exists($dir)) {
201 if (dol_mkdir($dir) < 0) {
202 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
203 return -1;
204 }
205 }
206
207 if (file_exists($dir)) {
208 // Add pdfgeneration hook
209 if (!is_object($hookmanager)) {
210 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
211 $hookmanager = new HookManager($this->db);
212 }
213 $hookmanager->initHooks(array('pdfgeneration'));
214 $parameters = array('file' => $file, 'object' => $object, 'outputlangs' => $outputlangs);
215 global $action;
216 $reshook = $hookmanager->executeHooks('beforePDFCreation', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
217
218 // Create pdf instance
219 $pdf = pdf_getInstance($this->format);
220 $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
221 $pdf->setAutoPageBreak(true, 0);
222
223 $heightforinfotot = 40; // Height reserved to output the info and total part
224 $heightforfreetext = getDolGlobalInt('MAIN_PDF_FREETEXT_HEIGHT', 5); // Height reserved to output the free text on last page
225 $heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin)
226 if (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS')) {
227 $heightforfooter += 6;
228 }
229
230 if (class_exists('TCPDF')) {
231 $pdf->setPrintHeader(false);
232 $pdf->setPrintFooter(false);
233 }
234 $pdf->SetFont(pdf_getPDFFont($outputlangs));
235 // Set path to the background PDF File
236 if (!getDolGlobalString('MAIN_DISABLE_FPDI') && getDolGlobalString('MAIN_ADD_PDF_BACKGROUND')) {
237 $pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/' . getDolGlobalString('MAIN_ADD_PDF_BACKGROUND'));
238 $tplidx = $pdf->importPage(1);
239 }
240
241 $pdf->Open();
242 $pagenb = 0;
243 $pdf->SetDrawColor(128, 128, 128);
244
245 $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
246 $pdf->SetSubject($outputlangs->transnoentities("Stock"));
247 $pdf->SetCreator("Dolibarr ".DOL_VERSION);
248 $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getAnonymisableFullName($outputlangs)));
249 $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("Stock")." ".$outputlangs->convToOutputCharset($object->label));
250 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
251 $pdf->SetCompression(false);
252 }
253
254 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
255 $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
256
257
258 // New page
259 $pdf->AddPage();
260 if (!empty($tplidx)) {
261 $pdf->useTemplate($tplidx);
262 }
263 $pagenb++;
264 $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs);
265 $pdf->SetFont('', '', $default_font_size - 1);
266 $pdf->MultiCell(0, 3, ''); // Set interline to 3
267 $pdf->SetTextColor(0, 0, 0);
268
269 $tab_top = 65 + $top_shift;
270 $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 42 + $top_shift : 10);
271
272 $tab_height = $this->page_hauteur - $tab_top - $heightforfooter - $heightforfreetext;
273
274
275 // Show list of product in warehouse */
276
277 $totalunit = 0;
278 $totalvalue = $totalvaluesell = 0;
279
280 $sortfield = 'p.ref';
281 $sortorder = 'ASC';
282
283 $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,";
284 $sql .= " ps.reel as value";
285 $sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps, ".MAIN_DB_PREFIX."product as p";
286 $sql .= " WHERE ps.fk_product = p.rowid";
287 $sql .= " AND ps.reel <> 0"; // We do not show if stock is 0 (no product in this warehouse)
288 $sql .= " AND ps.fk_entrepot = ".((int) $object->id);
289 $sql .= $this->db->order($sortfield, $sortorder);
290
291 //dol_syslog('List products', LOG_DEBUG);
292 $resql = $this->db->query($sql);
293 if ($resql) {
294 $num = $this->db->num_rows($resql);
295 $nblines = $num;
296
297 $nexY = $tab_top + $this->tabTitleHeight;
298
299 for ($i = 0; $i < $nblines; $i++) {
300 $curY = $nexY;
301
302 $objp = $this->db->fetch_object($resql);
303
304 // Multilangs
305 if (getDolGlobalInt('MAIN_MULTILANGS')) { // si l'option est active
306 $sql = "SELECT label";
307 $sql .= " FROM ".MAIN_DB_PREFIX."product_lang";
308 $sql .= " WHERE fk_product = ".((int) $objp->rowid);
309 $sql .= " AND lang = '".$this->db->escape($langs->getDefaultLang())."'";
310 $sql .= " LIMIT 1";
311
312 $result = $this->db->query($sql);
313 if ($result) {
314 $objtp = $this->db->fetch_object($result);
315 if ($objtp->label != '') {
316 $objp->produit = $objtp->label;
317 }
318 }
319 }
320
321 $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
322 $pdf->SetTextColor(0, 0, 0);
323
324 $pdf->setTopMargin($tab_top_newpage);
325 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext + $heightforinfotot); // The only function to edit the bottom margin of current page to set it.
326 $pageposbefore = $pdf->getPage();
327
328 // Description of product line
329 $curX = $this->posxdesc - 1;
330
331 $showpricebeforepagebreak = 1;
332
333 $pdf->startTransaction();
334 $pdf->writeHTMLCell($this->wref, 3, $curX, $curY, $outputlangs->convToOutputCharset($objp->ref), 0, 1, false, true, 'J', true);
335 //pdf_writelinedesc($pdf, $object, $i, $outputlangs, $this->posxtva - $curX, 3, $curX, $curY, $hideref, $hidedesc);
336 $pageposafter = $pdf->getPage();
337 if ($pageposafter > $pageposbefore) { // There is a pagebreak
338 $pdf->rollbackTransaction(true);
339 $pageposafter = $pageposbefore;
340 //print $pageposafter.'-'.$pageposbefore;exit;
341 $pdf->setPageOrientation('', true, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
342 $pdf->writeHTMLCell($this->wref, 4, $curX, $curY, $outputlangs->convToOutputCharset($objp->ref), 0, 1, false, true, 'J', true);
343 //pdf_writelinedesc($pdf, $object, $i, $outputlangs, $this->posxtva - $curX, 4, $curX, $curY, $hideref, $hidedesc);
344 $pageposafter = $pdf->getPage();
345 $posyafter = $pdf->GetY();
346 if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) { // There is no space left for total+free text
347 if ($i == ($nblines - 1)) { // No more lines, and no space left to show total, so we create a new page
348 $pdf->AddPage('', '', true);
349 if (!empty($tplidx)) {
350 $pdf->useTemplate($tplidx);
351 }
352 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
353 $this->_pagehead($pdf, $object, 0, $outputlangs);
354 }
355 $pdf->setPage($pageposafter + 1);
356 }
357 } else {
358 // We found a page break
359
360 // Allows data in the first page if description is long enough to break in multiples pages
361 if (getDolGlobalString('MAIN_PDF_DATA_ON_FIRST_PAGE')) {
362 $showpricebeforepagebreak = 1;
363 } else {
364 $showpricebeforepagebreak = 0;
365 }
366 }
367 } else { // No pagebreak
368 $pdf->commitTransaction();
369 }
370 $posYAfterDescription = $pdf->GetY();
371
372 $nexY = $pdf->GetY();
373 $pageposafter = $pdf->getPage();
374
375 $pdf->setPage($pageposbefore);
376 $pdf->setTopMargin($this->marge_haute);
377 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
378
379 // We suppose that a too long description is moved completely on next page
380 if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
381 $pdf->setPage($pageposafter);
382 $curY = $tab_top_newpage;
383 }
384
385 $pdf->SetFont('', '', $default_font_size - 1); // On repositionne la police par default
386
387 $productstatic->id = $objp->rowid;
388 $productstatic->ref = $objp->ref;
389 $productstatic->label = $objp->produit;
390 $productstatic->type = $objp->type;
391 $productstatic->entity = $objp->entity;
392 $productstatic->status_batch = $objp->tobatch;
393
394 // Ref.
395 //$pdf->SetXY($this->posxdesc, $curY);
396 //$pdf->MultiCell($this->wref, 3, $productstatic->ref, 0, 'L');
397
398 // Label
399 $pdf->SetXY($this->posxlabel + 0.8, $curY);
400 $pdf->MultiCell($this->posxqty - $this->posxlabel - 0.8, 3, dol_trunc($productstatic->label, 24), 0, 'L');
401
402 // Quantity
403 $valtoshow = price2num($objp->value, 'MS');
404 $towrite = (empty($valtoshow) ? '0' : $valtoshow);
405
406 $pdf->SetXY($this->posxqty, $curY);
407 $pdf->MultiCell($this->posxup - $this->posxqty - 0.8, 3, $towrite, 0, 'R');
408
409 // AWP
410 $totalunit += $objp->value;
411
412 $pdf->SetXY($this->posxup, $curY);
413 $pdf->MultiCell($this->posxunit - $this->posxup - 0.8, 3, price(price2num($objp->ppmp, 'MU'), 0, $outputlangs), 0, 'R');
414
415 // Total PMP
416 $pdf->SetXY($this->posxunit, $curY);
417 $pdf->MultiCell($this->posxdiscount - $this->posxunit - 0.8, 3, price(price2num($objp->ppmp * $objp->value, 'MT'), 0, $outputlangs), 0, 'R');
418 $totalvalue += price2num($objp->ppmp * $objp->value, 'MT');
419
420 $pricemin = 0;
421 // Price sell min
422 if (!getDolGlobalString('PRODUIT_MULTIPRICES') && !getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
423 $pricemin = $objp->price;
424 $pdf->SetXY($this->posxdiscount, $curY);
425 $pdf->MultiCell($this->postotalht - $this->posxdiscount, 3, price(price2num($pricemin, 'MU'), 0, $outputlangs), 0, 'R', false);
426
427 // Total sell min
428 $pdf->SetXY($this->postotalht, $curY);
429 $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->postotalht, 3, price(price2num($pricemin * $objp->value, 'MT'), 0, $outputlangs), 0, 'R', false);
430 }
431 $totalvaluesell += price2num($pricemin * $objp->value, 'MT');
432
433 // Add line
434 if (getDolGlobalString('MAIN_PDF_DASH_BETWEEN_LINES') && $i < ($nblines - 1)) {
435 $pdf->setPage($pageposafter);
436 $pdf->SetLineStyle(array('dash' => '1,1', 'color' => array(80, 80, 80)));
437 //$pdf->SetDrawColor(190,190,200);
438 $pdf->line($this->marge_gauche, $nexY + 1, $this->page_largeur - $this->marge_droite, $nexY + 1);
439 $pdf->SetLineStyle(array('dash' => 0));
440 }
441
442 $nexY += 2; // Add space between lines
443
444 // Detect if some page were added automatically and output _tableau for past pages
445 while ($pagenb < $pageposafter) {
446 $pdf->setPage($pagenb);
447 if ($pagenb == 1) {
448 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
449 } else {
450 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
451 }
452 $this->_pagefoot($pdf, $object, $outputlangs, 1);
453 $pagenb++;
454 $pdf->setPage($pagenb);
455 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
456 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
457 $this->_pagehead($pdf, $object, 0, $outputlangs);
458 }
459 if (!empty($tplidx)) {
460 $pdf->useTemplate($tplidx);
461 }
462 }
463 if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) {
464 if ($pagenb == 1) {
465 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
466 } else {
467 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
468 }
469 $this->_pagefoot($pdf, $object, $outputlangs, 1);
470 // New page
471 $pdf->AddPage();
472 if (!empty($tplidx)) {
473 $pdf->useTemplate($tplidx);
474 }
475 $pagenb++;
476 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
477 $this->_pagehead($pdf, $object, 0, $outputlangs);
478 }
479 }
480 }
481
482 $this->db->free($resql);
483
487 //$nexY = $pdf->GetY();
488 $nexY += 2;
489 $curY = $nexY;
490
491 if ($nblines > 0) {
492 $pdf->SetLineStyle(array('dash' => '0', 'color' => array(200, 200, 200)));
493 $pdf->line($this->marge_gauche, $curY - 1, $this->page_largeur - $this->marge_droite, $curY - 1);
494 $pdf->SetLineStyle(array('dash' => 0));
495
496 $pdf->SetFont('', 'B', $default_font_size - 1);
497 $pdf->SetTextColor(0, 0, 0);
498
499 // Ref.
500 $pdf->SetXY($this->posxdesc, $curY);
501 $pdf->MultiCell($this->wref, 3, $langs->trans("Total"), 0, 'L');
502
503 // Quantity
504 $valtoshow = price2num($totalunit, 'MS');
505 $towrite = empty($valtoshow) ? '0' : $valtoshow;
506
507 $pdf->SetXY($this->posxqty, $curY);
508 $pdf->MultiCell($this->posxup - $this->posxqty - 0.8, 3, $towrite, 0, 'R');
509
510 // Total PMP
511 $pdf->SetXY($this->posxunit, $curY);
512 $pdf->MultiCell($this->posxdiscount - $this->posxunit - 0.8, 3, price(price2num($totalvalue, 'MT'), 0, $outputlangs), 0, 'R');
513
514 // Price sell min
515 if (!getDolGlobalString('PRODUIT_MULTIPRICES') && !getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
516 // Total sell min
517 $pdf->SetXY($this->postotalht, $curY);
518 $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->postotalht, 3, price(price2num($totalvaluesell, 'MT'), 0, $outputlangs), 0, 'R', false);
519 }
520 }
521 } else {
522 dol_print_error($this->db);
523 }
524
525 // Displays notes
526 $notetoshow = empty($object->note_public) ? '' : $object->note_public;
527
528 if ($notetoshow) {
529 $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
530 complete_substitutions_array($substitutionarray, $outputlangs, $object);
531 $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
532 $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);
533
534 $tab_top = 88;
535
536 $pdf->SetFont('', '', $default_font_size - 1);
537 $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
538 $nexY = $pdf->GetY();
539 $height_note = $nexY - $tab_top;
540
541 // Rect takes a length in 3rd parameter
542 $pdf->SetDrawColor(192, 192, 192);
543 $pdf->RoundedRect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_note + 2, $this->corner_radius, '1234', 'D');
544
545 $tab_height -= $height_note;
546 $tab_top = $nexY + 6;
547 } else {
548 $height_note = 0;
549 }
550
551 /*$iniY = $tab_top + 7;
552 $curY = $tab_top + 7;
553 $nexY = $tab_top + 7;
554
555 $tab_top = $tab_top_newpage + 25 + $top_shift;*/
556
557 // Show square
558 if ($pagenb == 1) {
559 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code);
560 $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
561 } else {
562 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code);
563 $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
564 }
565
566 $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
567
568 // Affiche zone infos
569 //$posy=$this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs);
570
571 // Affiche zone totaux
572 //$posy=$this->_tableau_tot($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs);
573
574 // Pied de page
575 $this->_pagefoot($pdf, $object, $outputlangs);
576 if (method_exists($pdf, 'AliasNbPages')) {
577 $pdf->AliasNbPages(); // @phan-suppress-current-line PhanUndeclaredMethod
578 }
579
580 $pdf->Close();
581
582 $pdf->Output($file, 'F');
583
584 // Add pdfgeneration hook
585 $hookmanager->initHooks(array('pdfgeneration'));
586 $parameters = array('file' => $file, 'object' => $object, 'outputlangs' => $outputlangs);
587 global $action;
588 $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
589 $this->warnings = $hookmanager->warnings;
590 if ($reshook < 0) {
591 $this->error = $hookmanager->error;
592 $this->errors = $hookmanager->errors;
593 dolChmod($file);
594 return -1;
595 }
596
597 dolChmod($file);
598
599 $this->result = array('fullpath' => $file);
600
601 return 1; // No error
602 } else {
603 $this->error = $langs->trans("ErrorCanNotCreateDir", $dir);
604 return 0;
605 }
606 } else {
607 $this->error = $langs->trans("ErrorConstantNotDefined", "PRODUCT_OUTPUTDIR");
608 return 0;
609 }
610 }
611
612 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
626 protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '')
627 {
628 global $conf;
629
630 // Force to disable hidetop and hidebottom
631 $hidebottom = 0;
632 if ($hidetop) {
633 $hidetop = -1;
634 }
635
636 $currency = !empty($currency) ? $currency : $conf->currency;
637 $default_font_size = pdf_getPDFFontSize($outputlangs);
638
639 // Amount in (at tab_top - 1)
640 $pdf->SetTextColor(0, 0, 0);
641 $pdf->SetFont('', '', $default_font_size - 2);
642
643 if (empty($hidetop)) {
644 $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
645 $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);
646 $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
647
648 //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
649 if (getDolGlobalString('MAIN_PDF_TITLE_BACKGROUND_COLOR')) {
650 $pdf->RoundedRect($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite - $this->marge_gauche, 5, $this->corner_radius, '1001', 'F', array(), explode(',', getDolGlobalString('MAIN_PDF_TITLE_BACKGROUND_COLOR')));
651 }
652 }
653
654 $pdf->SetDrawColor(128, 128, 128);
655
656 $pdf->SetFont('', 'B', $default_font_size - 3);
657
658 // Output Rect
659 $this->printRoundedRect($pdf, $this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $tab_height, $this->corner_radius, $hidetop, $hidebottom, 'D'); // Rect takes a length in 3rd parameter and 4th parameter
660
661 $pdf->SetLineStyle(array('dash' => '0', 'color' => array(200, 200, 200)));
662 $pdf->SetDrawColor(200, 200, 200);
663 $pdf->line($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite, $tab_top);
664 $pdf->SetLineStyle(array('dash' => 0));
665 $pdf->SetDrawColor(128, 128, 128);
666 $pdf->SetTextColor(0, 0, 0);
667
668
669 if (empty($hidetop)) {
670 $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
671 $pdf->SetXY($this->posxdesc - 1, $tab_top + 1);
672 $pdf->MultiCell($this->wref, 3, $outputlangs->transnoentities("Ref"), '', 'L');
673 }
674
675 $pdf->line($this->posxlabel - 1, $tab_top, $this->posxlabel - 1, $tab_top + $tab_height);
676 if (empty($hidetop)) {
677 $pdf->SetXY($this->posxlabel - 1, $tab_top + 1);
678 $pdf->MultiCell($this->posxqty - $this->posxlabel - 1, 2, $outputlangs->transnoentities("Label"), '', 'C');
679 }
680
681 $pdf->line($this->posxqty - 1, $tab_top, $this->posxqty - 1, $tab_top + $tab_height);
682 if (empty($hidetop)) {
683 $pdf->SetXY($this->posxqty - 1, $tab_top + 1);
684 $pdf->MultiCell($this->posxup - $this->posxqty - 1, 2, $outputlangs->transnoentities("Units"), '', 'C');
685 }
686
687 $pdf->line($this->posxup - 1, $tab_top, $this->posxup - 1, $tab_top + $tab_height);
688 if (empty($hidetop)) {
689 $pdf->SetXY($this->posxup - 1, $tab_top + 1);
690 $pdf->MultiCell($this->posxunit - $this->posxup - 1, 2, $outputlangs->transnoentities("AverageUnitPricePMPShort"), '', 'C');
691 }
692
693 $pdf->line($this->posxunit - 1, $tab_top, $this->posxunit - 1, $tab_top + $tab_height);
694 if (empty($hidetop)) {
695 $pdf->SetXY($this->posxunit - 1, $tab_top + 1);
696 $pdf->MultiCell($this->posxdiscount - $this->posxunit - 1, 2, $outputlangs->transnoentities("EstimatedStockValueShort"), '', 'C');
697 }
698
699 $pdf->line($this->posxdiscount - 1, $tab_top, $this->posxdiscount - 1, $tab_top + $tab_height);
700 if (empty($hidetop)) {
701 $pdf->SetXY($this->posxdiscount - 1, $tab_top + 1);
702 $pdf->MultiCell($this->postotalht - $this->posxdiscount + 1, 2, $outputlangs->transnoentities("SellPriceMin"), '', 'C');
703 }
704
705 $pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height);
706 if (empty($hidetop)) {
707 $pdf->SetXY($this->postotalht - 1, $tab_top + 1);
708 $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->postotalht, 2, $outputlangs->transnoentities("EstimatedStockValueSellShort"), '', 'C');
709 }
710
711 if (empty($hidetop)) {
712 $pdf->SetDrawColor(200, 200, 200);
713 $pdf->SetLineStyle(array('dash' => '0', 'color' => array(200, 200, 200)));
714 $pdf->line($this->marge_gauche, $tab_top + $this->tabTitleHeight, $this->page_largeur - $this->marge_droite, $tab_top + $this->tabTitleHeight);
715 $pdf->SetLineStyle(array('dash' => 0));
716 }
717 }
718
719 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
730 protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $titlekey = "")
731 {
732 global $conf, $langs;
733
734 // Load traductions files required by page
735 $outputlangs->loadLangs(array("main", "propal", "companies", "bills", "orders", "stocks"));
736
737 $default_font_size = pdf_getPDFFontSize($outputlangs);
738
739 pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
740
741 // Show Draft Watermark
742 if ($object->statut == 0 && (getDolGlobalString('STOCK_DRAFT_WATERMARK'))) {
743 pdf_watermark($pdf, $outputlangs, $this->page_hauteur, $this->page_largeur, 'mm', $conf->global->STOCK_DRAFT_WATERMARK);
744 }
745
746 $pdf->SetTextColor(0, 0, 60);
747 $pdf->SetFont('', 'B', $default_font_size + 3);
748
749 $posy = $this->marge_haute;
750 $posx = $this->page_largeur - $this->marge_droite - 100;
751
752 $pdf->SetXY($this->marge_gauche, $posy);
753
754 // Logo
755 $height = 0;
756 $logo = $conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
757 if ($this->emetteur->logo) {
758 if (is_readable($logo)) {
759 $height = pdf_getHeightForLogo($logo);
760 $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
761 } else {
762 $pdf->SetTextColor(200, 0, 0);
763 $pdf->SetFont('', 'B', $default_font_size - 2);
764 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
765 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
766 }
767 } else {
768 $text = $this->emetteur->name;
769 $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
770 }
771
772 $yafterleft = $pdf->GetY() + $height;
773
774 $pdf->SetFont('', 'B', $default_font_size + 3);
775 $pdf->SetXY($posx, $posy);
776 $pdf->SetTextColor(0, 0, 60);
777
778 $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Warehouse").' '.$outputlangs->convToOutputCharset($object->label), '', 'R');
779
780 $posy += 6;
781 $pdf->SetFont('', '', $default_font_size - 1);
782 $pdf->SetXY($posx, $posy);
783 $pdf->SetTextColor(0, 0, 60);
784 if (!empty($object->lieu)) {
785 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Label").' : '.$object->lieu, '', 'R');
786 }
787
788
789 $posy += 4;
790 $pdf->SetXY($posx, $posy);
791 $pdf->SetTextColor(0, 0, 60);
792
793 // Parent warehouse
794 $e = new Entrepot($this->db);
795 $hasparent = (!empty($object->fk_parent) && $e->fetch($object->fk_parent) > 0);
796
797 if ($hasparent) {
798 $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ParentWarehouse").' :', '', 'R');
799
800 $posy += 4;
801 $pdf->SetXY($posx - 50, $posy);
802 $pdf->MultiCell(150, 3, $e->label, '', 'R');
803 }
804
805 $yafterright = $pdf->GetY();
806
807 // Description
808 $nbpage = $pdf->getPage();
809 if ($nbpage == 1) {
810 $nexY = max($yafterleft, $yafterright);
811 $nexY += 5;
812 $pdf->SetXY($posx, $posy);
813 $pdf->writeHTMLCell(190, 2, $this->marge_gauche, $nexY, '<b>'.$outputlangs->transnoentities("Description").' : </b>'.nl2br($object->description), 0, 1);
814 $nexY = $pdf->GetY();
815
816 $calcproductsunique = $object->nb_different_products();
817 $calcproducts = $object->nb_products();
818
819 // Total nb of different products
820 $pdf->writeHTMLCell(190, 2, $this->marge_gauche, $nexY, '<b>'.$outputlangs->transnoentities("NumberOfDifferentProducts").' : </b>'.(empty($calcproductsunique['nb']) ? '0' : $calcproductsunique['nb']), 0, 1);
821 $nexY = $pdf->GetY();
822
823 // Nb of products
824 $valtoshow = price2num($calcproducts['nb'], 'MS');
825 $pdf->writeHTMLCell(190, 2, $this->marge_gauche, $nexY, '<b>'.$outputlangs->transnoentities("NumberOfProducts").' : </b>'.(empty($valtoshow) ? '0' : $valtoshow), 0, 1);
826 $nexY = $pdf->GetY();
827
828 // Value
829 $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);
830 $nexY = $pdf->GetY();
831
832 // Value
833 $pdf->writeHTMLCell(190, 2, $this->marge_gauche, $nexY, '<b>'.$outputlangs->transnoentities("Date").' : </b>'.dol_print_date(dol_now(), 'dayhour'), 0, 1);
834 $nexY = $pdf->GetY();
835
836 // Last movement
837 $sql = "SELECT max(m.datem) as datem";
838 $sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement as m";
839 $sql .= " WHERE m.fk_entrepot = ".((int) $object->id);
840 $lastmovementdate = 0;
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}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
printRoundedRect($pdf, $x, $y, $w, $h, $r, $hidetop=0, $hidebottom=0, $style='D')
Print a rounded rectangle on the PDF.
Class to manage warehouses.
Class to manage hooks.
Parent class for stock models of doc generators.
Class to manage products or services.
Class to build documents using ODF templates generator.
_tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='')
Show table for lines.
write_file($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0)
Function to build a document on disk.
_pagefoot(&$pdf, $object, $outputlangs, $hidefreetext=0)
Show footer of page.
_pagehead(&$pdf, $object, $showaddress, $outputlangs, $titlekey="")
Show top header of page.
global $mysoc
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
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...
dol_now($mode='gmt')
Return date for now.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
getCallerInfoString()
Get caller info as a string that can be appended to a log message.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
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.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return a 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_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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 a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
pdf_watermark($pdf, $outputlangs, $h, $w, $unit, $text)
Add a draft watermark on PDF files.
Definition pdf.lib.php:1155
pdf_getFormat($outputlangs=null, $mode='setup')
Return array with format properties of default PDF format.
Definition pdf.lib.php:87
pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, $h, $align, $default_font_size)
Show linked objects for PDF generation.
Definition pdf.lib.php:1808
pdf_getPDFFontSize($outputlangs)
Return font size to use for PDF generation.
Definition pdf.lib.php:294
pdf_getHeightForLogo($logo, $url=false)
Return height to use for Logo onto PDF.
Definition pdf.lib.php:317
pdf_pagehead($pdf, $outputlangs, $page_height)
Show header of page for PDF generation.
Definition pdf.lib.php:747
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:1421
pdf_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition pdf.lib.php:273
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:1135
pdf_getInstance($format='', $metric='mm', $pagetype='P')
Return a PDF instance object.
Definition pdf.lib.php:129
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:130
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:133