dolibarr 25.0.0-alpha
pdf_strato.modules.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2010 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2008 Raphael Bertrand (Resultic) <raphael.bertrand@resultic.fr>
6 * Copyright (C) 2011 Fabrice CHERRIER
7 * Copyright (C) 2013-2024 Philippe Grand <philippe.grand@atoo-net.com>
8 * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
9 * Copyright (C) 2018-2026 Frédéric France <frederic.france@free.fr>
10 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
11 * Copyright (C) 2024 Nick Fragoulis
12 * Copyright (C) 2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
13 * Copyright (C) 2024 Éric Seigne <eric.seigne@cap-rel.fr>
14 * Copyright (C) 2025 William Mead <william@m34d.com>
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program. If not, see <https://www.gnu.org/licenses/>.
28 * or see https://www.gnu.org/
29 */
30
36require_once DOL_DOCUMENT_ROOT.'/core/modules/contract/modules_contract.php';
37require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
38require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
39require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
40require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
41require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
42
43
48{
52 public $db;
53
57 public $entity;
58
62 public $name;
63
67 public $description;
68
72 public $update_main_doc_field;
73
77 public $type;
78
83 public $version = 'dolibarr';
84
88 public $recipient;
89
95 public function __construct($db)
96 {
97 global $langs, $mysoc;
98
99 $this->db = $db;
100 $this->name = 'strato';
101 $this->description = $langs->trans("StandardContractsTemplate");
102 $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template
103
104 // Dimension page
105 $this->type = 'pdf';
106 $formatarray = pdf_getFormat();
107
108 $this->page_largeur = $formatarray['width'];
109 $this->page_hauteur = $formatarray['height'];
110 $this->format = array($this->page_largeur, $this->page_hauteur);
111 $this->marge_gauche = getDolGlobalInt('MAIN_PDF_MARGIN_LEFT', 10);
112 $this->marge_droite = getDolGlobalInt('MAIN_PDF_MARGIN_RIGHT', 10);
113 $this->marge_haute = getDolGlobalInt('MAIN_PDF_MARGIN_TOP', 10);
114 $this->marge_basse = getDolGlobalInt('MAIN_PDF_MARGIN_BOTTOM', 10);
115 $this->corner_radius = getDolGlobalInt('MAIN_PDF_FRAME_CORNER_RADIUS', 0);
116 $this->option_logo = 1; // Display logo
117 $this->option_tva = 0; // Manage the vat option FACTURE_TVAOPTION
118 $this->option_modereg = 0; // Display payment mode
119 $this->option_condreg = 0; // Display payment terms
120 $this->option_multilang = 0; // Available in several languages
121 $this->option_draft_watermark = 1; // Support add of a watermark on drafts
122
123 // Define position of columns
124 $this->posxdesc = $this->marge_gauche + 1;
125
126 if ($mysoc === null) {
127 dol_syslog(get_class($this).'::__construct() Global $mysoc should not be null.'. getCallerInfoString(), LOG_ERR);
128 return;
129 }
130
131 // Get source company
132 $this->emetteur = $mysoc;
133 if (empty($this->emetteur->country_code)) {
134 $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined
135 }
136 }
137
138 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
150 public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
151 {
152 // phpcs:enable
153 global $user, $langs, $conf, $mysoc, $db, $hookmanager, $nblines;
154
155 if (!is_object($outputlangs)) {
156 $outputlangs = $langs;
157 }
158 // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
159 if (getDolGlobalString('MAIN_USE_FPDF')) {
160 $outputlangs->charset_output = 'ISO-8859-1';
161 }
162
163 // Load translation files required by page
164 $outputlangs->loadLangs(array("main", "dict", "companies", "contracts", "compta"));
165
166 // Show Draft Watermark
167 if ($object->status == $object::STATUS_DRAFT && (getDolGlobalString('CONTRACT_DRAFT_WATERMARK'))) {
168 $this->watermark = getDolGlobalString('CONTRACT_DRAFT_WATERMARK');
169 }
170
171 global $outputlangsbis;
172 $outputlangsbis = null;
173 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE') && $outputlangs->defaultlang != getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
174 $outputlangsbis = new Translate('', $conf);
175 $outputlangsbis->setDefaultLang(getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE'));
176 $outputlangsbis->loadLangs(array("main", "dict", "companies", "contracts", "compta"));
177 }
178
179 $nblines = count($object->lines);
180
181 if ($conf->contract->multidir_output[$conf->entity]) {
182 $object->fetch_thirdparty();
183
184 // Definition of $dir and $file
185 if ($object->specimen) {
187 $file = $dir."/SPECIMEN.pdf";
188 } else {
189 $objectref = dol_sanitizeFileName($object->ref);
190 $dir = getMultidirOutput($object)."/".$objectref;
191 $file = $dir."/".$objectref.".pdf";
192 }
193
194 if ($dir === null) {
195 dol_syslog(get_class($this).'::'.__METHOD__."Target directory should not be null.". getCallerInfoString(), LOG_ERR);
196 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", "Null dir");
197 return 0;
198 }
199
200 if (!file_exists($dir)) {
201 if (dol_mkdir($dir) < 0) {
202 $this->error = $langs->transnoentitiesnoconv("ErrorCanNotCreateDir", $dir);
203 return 0;
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 // Set nblines with the new lines content after hook
219 $nblines = (is_array($object->lines) ? count($object->lines) : 0);
220
221 // Create pdf instance
222 $pdf = pdf_getInstance($this->format);
223 $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
224 $pdf->setAutoPageBreak(true, 0);
225
226 $heightforinfotot = 50; // Height reserved to output the info and total part
227 $heightforfreetext = getDolGlobalInt('MAIN_PDF_FREETEXT_HEIGHT', 5); // Height reserved to output the free text on last page
228 $heightforfooter = $this->marge_basse + 9; // Height reserved to output the footer (value include bottom margin)
229 if (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS')) {
230 $heightforfooter += 6;
231 }
232
233 if (class_exists('TCPDF')) {
234 $pdf->setPrintHeader(false);
235 $pdf->setPrintFooter(false);
236 }
237 $pdf->SetFont(pdf_getPDFFont($outputlangs));
238 // Set path to the background PDF File
239 if (getDolGlobalString('MAIN_ADD_PDF_BACKGROUND')) {
240 $logodir = $conf->mycompany->dir_output;
241 if (!empty($conf->mycompany->multidir_output[$object->entity ?? $conf->entity])) {
242 $logodir = $conf->mycompany->multidir_output[$object->entity ?? $conf->entity];
243 }
244 $pagecount = $pdf->setSourceFile($logodir.'/' . getDolGlobalString('MAIN_ADD_PDF_BACKGROUND'));
245 $tplidx = $pdf->importPage(1);
246 }
247
248 $pdf->Open();
249 $pagenb = 0;
250 $pdf->SetDrawColor(128, 128, 128);
251
252 $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
253 $pdf->SetSubject($outputlangs->transnoentities("Contract"));
254 $pdf->SetCreator("Dolibarr ".DOL_VERSION);
255 $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getAnonymisableFullName($outputlangs)));
256 $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("Contract")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
257 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
258 $pdf->SetCompression(false);
259 }
260
261 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
262 $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
263
264 // New page
265 $pdf->AddPage();
266 if (!empty($tplidx)) {
267 $pdf->useTemplate($tplidx);
268 }
269 $pagenb++;
270 $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs, (is_object($outputlangsbis) ? $outputlangsbis : null));
271 $pdf->SetFont('', '', $default_font_size - 1);
272 $pdf->MultiCell(0, 3, ''); // Set interline to 3
273 $pdf->SetTextColor(0, 0, 0);
274
275 $tab_top = 80 + $this->marge_haute;
276 $tab_top_newpage = (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD') ? 32 + $this->marge_haute : $this->marge_haute);
277
278 // Display notes
279 $notetoshow = empty($object->note_public) ? '' : $object->note_public;
280
281 // Extrafields in note
282 $extranote = $this->getExtrafieldsInHtml($object, $outputlangs);
283 if (!empty($extranote)) {
284 $notetoshow = dol_concatdesc($notetoshow, $extranote);
285 }
286
287 if (!empty($notetoshow)) {
288 $tab_top -= 2;
289
290 $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);
291 complete_substitutions_array($substitutionarray, $outputlangs, $object);
292 $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
293 $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);
294
295 $pdf->SetFont('', '', $default_font_size - 1);
296 $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($notetoshow), 0, 1);
297 $nexY = $pdf->GetY();
298 $height_note = $nexY - $tab_top;
299
300 // Rect takes a length in 3rd parameter
301 $pdf->SetDrawColor(192, 192, 192);
302 $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');
303
304 $tab_top = $nexY + 6;
305 }
306
307 $iniY = $tab_top + 7;
308 $curY = $tab_top + 7;
309 $nexY = $tab_top + 2;
310
311 $pdf->SetXY($this->marge_gauche, $tab_top);
312
313 $pdf->MultiCell(0, 2, ''); // Set interline to 3. Then writeMultiCell must use 3 also.
314
315 $nblines = count($object->lines);
316
317 // Loop on each lines
318 for ($i = 0; $i < $nblines; $i++) {
319 $objectligne = $object->lines[$i];
320
321 $valide = $objectligne->id ? 1 : 0;
322
323 if ($valide > 0 || $object->specimen) {
324 $curX = $this->posxdesc - 1;
325 $curY = $nexY;
326 $pdf->SetFont('', '', $default_font_size - 1); // Into loop to work with multipage
327 $pdf->SetTextColor(0, 0, 0);
328
329 $pdf->setTopMargin($tab_top_newpage);
330 $pdf->setPageOrientation('', true, $heightforfooter + $heightforfreetext + $heightforinfotot); // The only function to edit the bottom margin of current page to set it.
331 $pageposbefore = $pdf->getPage();
332
333 // Description of product line
334
335 if (!empty($objectligne->date_start)) {
336 $datei = dol_print_date((int) $objectligne->date_start, 'day', false, $outputlangs, true);
337 } else {
338 $datei = $langs->trans("Unknown");
339 }
340
341 if (!empty($objectligne->date_end)) {
342 $durationi = convertSecondToTime((int) $objectligne->date_end - (int) $objectligne->date_start, 'allwithouthour');
343 $datee = dol_print_date($objectligne->date_end, 'day', false, $outputlangs, true);
344 } else {
345 $durationi = $langs->trans("Unknown");
346 $datee = $langs->trans("Unknown");
347 }
348
349 if (!empty($objectligne->date_start_real)) {
350 $daters = dol_print_date((int) $objectligne->date_start_real, 'day', false, $outputlangs, true);
351 } else {
352 $daters = $langs->trans("Unknown");
353 }
354
355 if (!empty($objectligne->date_end_real)) {
356 $datere = dol_print_date((int) $objectligne->date_end_real, 'day', false, $outputlangs, true);
357 } else {
358 $datere = $langs->trans("Unknown");
359 }
360
361 $txtpredefinedservice = $objectligne->product_ref;
362 if ($objectligne->product_label) {
363 $txtpredefinedservice .= ' - ';
364 $txtpredefinedservice .= $objectligne->product_label;
365 }
366
367 $desc = dol_htmlentitiesbr($objectligne->desc, 1); // Desc (not empty for free lines)
368 $txt = '';
369 if (!getDolGlobalString('CONTRACT_HIDE_QTY_ON_PDF')) {
370 $txt .= $outputlangs->transnoentities("Quantity") . ' : <strong>' . $objectligne->qty . '</strong>';
371 }
372 if (!getDolGlobalString('CONTRACT_HIDE_PRICE_ON_PDF')) {
373 $txt .= ' - ' . $outputlangs->transnoentities("UnitPrice") . ' : <strong>' . price($objectligne->subprice) . '</strong>';
374 }
375 if (!getDolGlobalString('CONTRACT_HIDE_PLANNED_DATE_ON_PDF')) {
376 $txt .= '<br>';
377 $txt .= $outputlangs->transnoentities("DateStartPlannedShort")." : <strong>".$datei."</strong> - ".$outputlangs->transnoentities("DateEndPlanned")." : <strong>".$datee.'</strong>';
378 }
379 if (!getDolGlobalString('CONTRACT_HIDE_REAL_DATE_ON_PDF')) {
380 $txt .= '<br>';
381 $txt .= $outputlangs->transnoentities("DateStartRealShort")." : <strong>".$daters.'</strong>';
382 if (!empty($objectligne->date_end_real)) {
383 $txt .= " - ".$outputlangs->transnoentities("DateEndRealShort")." : <strong>".$datere.'</strong>';
384 }
385 }
386
387 $pdf->startTransaction();
388 $pdf->writeHTMLCell(0, 0, $curX, $curY, dol_concatdesc($txtpredefinedservice, dol_concatdesc($txt, $desc)), false, 1, false);
389 $pageposafter = $pdf->getPage();
390 if ($pageposafter > $pageposbefore) { // There is a pagebreak
391 $pdf->rollbackTransaction(true);
392 $pageposafter = $pageposbefore;
393 //print $pageposafter.'-'.$pageposbefore;exit;
394 $pdf->setPageOrientation('', true, $heightforfooter); // The only function to edit the bottom margin of current page to set it.
395 $pdf->writeHTMLCell(0, 0, $curX, $curY, dol_concatdesc($txtpredefinedservice, dol_concatdesc($txt, $desc)), false, 1, false);
396 $pageposafter = $pdf->getPage();
397 $posyafter = $pdf->GetY();
398 if ($posyafter > ($this->page_hauteur - ($heightforfooter + $heightforfreetext + $heightforinfotot))) { // There is no space left for total+free text
399 if ($i == ($nblines - 1)) { // No more lines, and no space left to show total, so we create a new page
400 $pdf->AddPage('', '', true);
401 if (!empty($tplidx)) {
402 $pdf->useTemplate($tplidx);
403 }
404 if (!getDolGlobalInt('MAIN_PDF_DONOTREPEAT_HEAD')) {
405 $this->_pagehead($pdf, $object, 0, $outputlangs);
406 }
407 $pdf->setPage($pageposafter + 1);
408 }
409 } else {
410 // We found a page break
411
412 // Allows data in the first page if description is long enough to break in multiples pages
413 if (getDolGlobalString('MAIN_PDF_DATA_ON_FIRST_PAGE')) {
414 $showpricebeforepagebreak = 1;
415 } else {
416 $showpricebeforepagebreak = 0;
417 }
418 }
419 } else { // No pagebreak
420 $pdf->commitTransaction();
421 }
422 $posYAfterDescription = $pdf->GetY();
423
424 $nexY = $pdf->GetY() + 2;
425 $pageposafter = $pdf->getPage();
426
427 $pdf->setPage($pageposbefore);
428 $pdf->setTopMargin($this->marge_haute);
429 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
430
431 // We suppose that a too long description is moved completely on next page
432 if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
433 $pdf->setPage($pageposafter);
434 $curY = $tab_top_newpage;
435 }
436
437 $pdf->SetFont('', '', $default_font_size - 1); // We reposition the default font
438
439 // Detect if some page were added automatically and output _tableau for past pages
440 while ($pagenb < $pageposafter) {
441 $pdf->setPage($pagenb);
442 if ($pagenb == 1) {
443 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter - $heightforfreetext, 0, $outputlangs, 0, 1);
444 } else {
445 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter - $heightforfreetext, 0, $outputlangs, 1, 1);
446 }
447 $this->_pagefoot($pdf, $object, $outputlangs, 1);
448 $pagenb++;
449 $pdf->setPage($pagenb);
450 $pdf->setPageOrientation('', true, 0); // The only function to edit the bottom margin of current page to set it.
451 if (!getDolGlobalString('MAIN_PDF_DONOTREPEAT_HEAD')) {
452 $this->_pagehead($pdf, $object, 0, $outputlangs);
453 }
454 if (!empty($tplidx)) {
455 $pdf->useTemplate($tplidx);
456 }
457 }
458
459 if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) { // @phan-suppress-current-line PhanUndeclaredProperty
460 if ($pagenb == 1) {
461 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter - $heightforfreetext, 0, $outputlangs, 0, 1);
462 } else {
463 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter - $heightforfreetext, 0, $outputlangs, 1, 1);
464 }
465 $this->_pagefoot($pdf, $object, $outputlangs, 1);
466 // New page
467 $pdf->AddPage();
468 if (!empty($tplidx)) {
469 $pdf->useTemplate($tplidx);
470 }
471 $pagenb++;
472 }
473 }
474 }
475
476
477 // Show square
478 if ($pagenb == 1) {
479 $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0);
480 $this->tabSignature($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, $outputlangs);
481 $bottomlasttab = $this->page_hauteur - $heightforfooter - $heightforfooter + 1;
482 } else {
483 $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0);
484 $this->tabSignature($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, $outputlangs);
485 $bottomlasttab = $this->page_hauteur - $heightforfooter - $heightforfooter + 1;
486 }
487
488 $this->_pagefoot($pdf, $object, $outputlangs);
489 if (method_exists($pdf, 'AliasNbPages')) {
490 $pdf->AliasNbPages(); // @phan-suppress-current-line PhanUndeclaredMethod
491 }
492
493 // Add terms of sale
494 if (getDolGlobalString('MAIN_INFO_CONTRACT_TERMSOFSALE') && getDolGlobalInt('MAIN_PDF_ADD_TERMSOFSALE_CONTRACT')) {
495 $termsofsalefilename = getDolGlobalString('MAIN_INFO_CONTRACT_TERMSOFSALE');
496 $termsofsale = $conf->contract->dir_output.'/'.$termsofsalefilename;
497 if (!empty($conf->contract->multidir_output[$object->entity ?? $conf->entity])) {
498 $termsofsale = $conf->contract->multidir_output[$object->entity ?? $conf->entity].'/'.$termsofsalefilename;
499 }
500 if (file_exists($termsofsale) && is_readable($termsofsale)) {
501 $pagecount = $pdf->setSourceFile($termsofsale);
502 for ($i = 1; $i <= $pagecount; $i++) {
503 $tplIdx = $pdf->importPage($i);
504 if ($tplIdx !== false) {
505 $s = $pdf->getTemplatesize($tplIdx);
506 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
507 $pdf->useTemplate($tplIdx);
508 } else {
509 setEventMessages(null, array($termsofsale.' cannot be added, probably protected PDF'), 'warnings');
510 }
511 }
512 }
513 }
514
515 $pdf->Close();
516
517 $pdf->Output($file, 'F');
518
519 // Add pdfgeneration hook
520 $hookmanager->initHooks(array('pdfgeneration'));
521 $parameters = array('file' => $file, 'object' => $object, 'outputlangs' => $outputlangs);
522 global $action;
523 $reshook = $hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
524 $this->warnings = $hookmanager->warnings;
525 if ($reshook < 0) {
526 $this->error = $hookmanager->error;
527 $this->errors = $hookmanager->errors;
528 dolChmod($file);
529 return -1;
530 }
531
532 dolChmod($file);
533
534 $this->result = array('fullpath' => $file);
535
536 return 1; // No error
537 } else {
538 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
539 return 0;
540 }
541 } else {
542 $this->error = $langs->transnoentities("ErrorConstantNotDefined", "CONTRACT_OUTPUTDIR");
543 return 0;
544 }
545 }
546
547 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
560 protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0)
561 {
562 global $conf;
563
564 // Force to disable hidetop and hidebottom
565 $hidebottom = 0;
566 if ($hidetop) {
567 $hidetop = -1;
568 }
569
570 //$default_font_size = pdf_getPDFFontSize($outputlangs);
571
572 /*
573 $pdf->SetXY($this->marge_gauche, $tab_top);
574 $pdf->MultiCell(190,8,$outputlangs->transnoentities("Description"),0,'L',0);
575 $pdf->line($this->marge_gauche, $tab_top + 8, $this->page_largeur-$this->marge_droite, $tab_top + 8);
576
577 $pdf->SetFont('','', $default_font_size - 1);
578
579 $pdf->MultiCell(0, 3, ''); // Set interline to 3
580 $pdf->SetXY($this->marge_gauche, $tab_top + 8);
581 $text=$object->description;
582 if ($object->duree > 0)
583 {
584 $totaltime=convertSecondToTime($object->duree,'all',$conf->global->MAIN_DURATION_OF_WORKDAY);
585 $text.=($text?' - ':'').$langs->trans("Total").": ".$totaltime;
586 }
587 $desc=dol_htmlentitiesbr($text,1);
588 //print $outputlangs->convToOutputCharset($desc); exit;
589
590 $pdf->writeHTMLCell(180, 3, 10, $tab_top + 8, $outputlangs->convToOutputCharset($desc), 0, 1);
591 $nexY = $pdf->GetY();
592
593 $pdf->line($this->marge_gauche, $nexY, $this->page_largeur-$this->marge_droite, $nexY);
594
595 $pdf->MultiCell(0, 3, ''); // Set interline to 3. Then writeMultiCell must use 3 also.
596 */
597
598 // Output Rect
599 $this->printRoundedRect($pdf, $this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $tab_height + 3, $this->corner_radius, $hidetop, $hidebottom, 'D'); // Rect takes a length in 3rd parameter and 4th parameter
600 }
601
611 protected function tabSignature(&$pdf, $tab_top, $tab_height, $outputlangs)
612 {
613 $pdf->SetDrawColor(128, 128, 128);
614 $posmiddle = $this->marge_gauche + round(($this->page_largeur - $this->marge_gauche - $this->marge_droite) / 2);
615 $posy = $tab_top + $tab_height + 3 + 3;
616
617 if (!getDolGlobalString('CONTRACT_HIDE_MYCOMPANY_SIGNATURE_SECTION_PDF')) {
618 $pdf->SetXY($this->marge_gauche, $posy);
619 $pdf->MultiCell($posmiddle - $this->marge_gauche - 5, 5, $outputlangs->transnoentities("ContactNameAndSignature", $this->emetteur->name), 0, 'L', false);
620
621 $pdf->SetXY($this->marge_gauche, $posy + 5);
622 $pdf->RoundedRect($this->marge_gauche, $posy + 5, $posmiddle - $this->marge_gauche - 5, 20, $this->corner_radius, '1234', 'D');
623 }
624
625 if (!getDolGlobalString('CONTRACT_HIDE_THIRPARTY_SIGNATURE_SECTION_PDF') && is_object($this->recipient)) {
626 $pdf->SetXY($posmiddle + 5, $posy);
627 $recipientname = pdfBuildThirdpartyName($this->recipient, $outputlangs);
628 $pdf->MultiCell($this->page_largeur - $this->marge_droite - $posmiddle - 5, 5, $outputlangs->transnoentities("ContactNameAndSignature", $recipientname), 0, 'L', false);
629
630 $pdf->SetXY($posmiddle + 5, $posy + 5);
631 $pdf->RoundedRect($posmiddle + 5, $posy + 5, $this->page_largeur - $this->marge_droite - $posmiddle - 5, 20, $this->corner_radius, '1234', 'D');
632 }
633 }
634
635 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
647 protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null, $titlekey = "Contract")
648 {
649 // phpcs:enable
650 global $conf;
651
652 $top_shift = 0;
653
654 $ltrdirection = 'L';
655 if ($outputlangs->trans("DIRECTION") == 'rtl') {
656 $ltrdirection = 'R';
657 }
658
659 // Load traductions files required by page
660 $outputlangs->loadLangs(array("main", "dict", "contract", "companies"));
661
662 $default_font_size = pdf_getPDFFontSize($outputlangs);
663
664 pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
665
666 $pdf->SetTextColor(0, 0, 60);
667 $pdf->SetFont('', 'B', $default_font_size + 3);
668
669 $w = 100;
670
671 $posy = $this->marge_haute;
672 $posx = $this->page_largeur - $this->marge_droite - $w;
673
674 $pdf->SetXY($this->marge_gauche, $posy);
675
676 // Logo
677 $logodir = $conf->mycompany->dir_output;
678 $multidiroutput = getMultidirOutput($object, 'mycompany');
679 if (!empty($multidiroutput)) {
680 $logodir = $multidiroutput;
681 }
682 pdf_writeLogoOrCompanyName($pdf, $outputlangs, $this->emetteur, $logodir, $this->marge_gauche, $posy, $w, $default_font_size, $ltrdirection);
683
684 $pdf->SetFont('', 'B', $default_font_size + 3);
685 $pdf->SetXY($posx, $posy);
686 $pdf->SetTextColor(0, 0, 60);
687 $title = $outputlangs->transnoentities($titlekey);
688 $title .= ' '.$outputlangs->convToOutputCharset($object->ref);
689 if ($object->status == $object::STATUS_DRAFT) {
690 $pdf->SetTextColor(128, 0, 0);
691 $title .= ' - '.$outputlangs->transnoentities("NotValidated");
692 }
693 $pdf->MultiCell($w, 3, $title, '', 'R');
694
695 $pdf->SetFont('', 'B', $default_font_size);
696
697 /*
698 $posy += 5;
699 $pdf->SetXY($posx, $posy);
700 $pdf->SetTextColor(0, 0, 60);
701 $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Ref")." : ".$outputlangs->convToOutputCharset($object->ref), '', 'R');
702 */
703
704 $posy += 3;
705 $pdf->SetFont('', '', $default_font_size - 1);
706
707 $posy += 4;
708 $pdf->SetXY($posx, $posy);
709 $pdf->SetTextColor(0, 0, 60);
710 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Date")." : ".dol_print_date($object->date_contrat, "day", false, $outputlangs, true), '', 'R');
711
712 if (!getDolGlobalString('MAIN_PDF_HIDE_CUSTOMER_CODE') && $object->thirdparty->code_client) {
713 $posy += 4;
714 $pdf->SetXY($posx, $posy);
715 $pdf->SetTextColor(0, 0, 60);
716 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities((string) $object->thirdparty->code_client), '', 'R');
717 }
718
719 if (!getDolGlobalString('MAIN_PDF_HIDE_CUSTOMER_ACCOUNTING_CODE') && $object->thirdparty->code_compta_client) {
720 $posy += 4;
721 $pdf->SetXY($posx, $posy);
722 $pdf->SetTextColor(0, 0, 60);
723 $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerAccountancyCode")." : ".$outputlangs->transnoentities((string) $object->thirdparty->code_compta_client), '', 'R');
724 }
725
726 if ($showaddress) {
727 // Sender properties
728 $carac_emetteur = '';
729 // Add internal contact of object if defined
730 $arrayidcontact = $object->getIdContact('internal', 'INTERREPFOLL');
731 if (count($arrayidcontact) > 0) {
732 $object->fetch_user($arrayidcontact[0]);
733 $labelbeforecontactname = ($outputlangs->transnoentities("FromContactName") != 'FromContactName' ? $outputlangs->transnoentities("FromContactName") : $outputlangs->transnoentities("Name"));
734 $carac_emetteur .= ($carac_emetteur ? "\n" : '').$labelbeforecontactname.": ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs));
735 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ' (' : '';
736 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && !empty($object->user->office_phone)) ? $object->user->office_phone : '';
737 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') && getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ', ' : '';
738 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT') && !empty($object->user->email)) ? $object->user->email : '';
739 $carac_emetteur .= (getDolGlobalInt('PDF_SHOW_PHONE_AFTER_USER_CONTACT') || getDolGlobalInt('PDF_SHOW_EMAIL_AFTER_USER_CONTACT')) ? ')' : '';
740 $carac_emetteur .= "\n";
741 }
742
743 $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
744
745 // Show sender
746 $posy = 32 + $this->marge_haute;
747 $posx = $this->marge_gauche;
748 if (getDolGlobalString('MAIN_INVERT_SENDER_RECIPIENT')) {
749 $posx = $this->page_largeur - $this->marge_droite - 80;
750 }
751 $hautcadre = 40;
752
753 // Show sender frame
754 if (!getDolGlobalString('MAIN_PDF_NO_SENDER_FRAME')) {
755 $pdf->SetTextColor(0, 0, 0);
756 $pdf->SetFont('', '', $default_font_size - 2);
757 $pdf->SetXY($posx, $posy - 5);
758 $pdf->SetXY($posx, $posy);
759 $pdf->SetFillColor(230, 230, 230);
760 $pdf->RoundedRect($posx, $posy, 82, $hautcadre, $this->corner_radius, '1234', 'F');
761 $pdf->SetTextColor(0, 0, 60);
762 }
763
764 // Show sender name
765 if (!getDolGlobalString('MAIN_PDF_HIDE_SENDER_NAME')) {
766 $pdf->SetXY($posx + 2, $posy + 3);
767 $pdf->SetTextColor(0, 0, 60);
768 $pdf->SetFont('', 'B', $default_font_size);
769 $pdf->MultiCell(80, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, 'L');
770 $posy = $pdf->getY();
771 }
772
773 // Show sender information
774 $pdf->SetXY($posx + 2, $posy);
775 $pdf->SetFont('', '', $default_font_size - 1);
776 $pdf->MultiCell(80, 4, $carac_emetteur, 0, 'L');
777
778
779 // If CUSTOMER contact defined, we use it
780 $usecontact = false;
781 $arrayidcontact = $object->getIdContact('external', 'CUSTOMER');
782 if (count($arrayidcontact) > 0) {
783 $usecontact = true;
784 $result = $object->fetch_contact($arrayidcontact[0]);
785 }
786
787 // Recipient name
788 if ($usecontact && ($object->contact->socid != $object->thirdparty->id) && (!isset($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT) || getDolGlobalString('MAIN_USE_COMPANY_NAME_OF_CONTACT'))) {
789 $this->recipient = $object->contact;
790 } else {
791 $this->recipient = $object->thirdparty;
792 }
793
794 $recipientname = '';
795 if ($this->recipient instanceof Contact || $this->recipient instanceof Societe) {
796 $recipientname = pdfBuildThirdpartyName($this->recipient, $outputlangs);
797 }
798
799 $mode = 'target';
800 $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, (isset($object->contact) ? $object->contact : ''), ($usecontact ? 1 : 0), $mode, $object);
801
802 // Show recipient
803 $widthrecbox = getDolGlobalString('MAIN_PDF_USE_ISO_LOCATION') ? 92 : 100;
804 if ($this->page_largeur < 210) {
805 $widthrecbox = 84; // To work with US executive format
806 }
807 $posy = getDolGlobalString('MAIN_PDF_USE_ISO_LOCATION') ? 30 : 32;
808 $posy += $top_shift + $this->marge_haute;
809 $posx = $this->page_largeur - $this->marge_droite - $widthrecbox;
810 if (getDolGlobalString('MAIN_INVERT_SENDER_RECIPIENT')) {
811 $posx = $this->marge_gauche;
812 }
813
814 // Show recipient frame
815 if (!getDolGlobalString('MAIN_PDF_NO_RECIPENT_FRAME')) {
816 $pdf->SetTextColor(0, 0, 0);
817 $pdf->SetFont('', '', $default_font_size - 2);
818 $pdf->SetXY($posx + 2, $posy - 5);
819 $pdf->RoundedRect($posx, $posy, $widthrecbox, $hautcadre, $this->corner_radius, '1234', 'D');
820 $pdf->SetTextColor(0, 0, 0);
821 }
822
823 // Show recipient name
824 $pdf->SetXY($posx + 2, $posy + 3);
825 $pdf->SetFont('', 'B', $default_font_size);
826 $pdf->MultiCell($widthrecbox, 4, $recipientname, 0, $ltrdirection);
827
828 $posy = $pdf->getY();
829
830 // Show recipient information
831 $pdf->SetFont('', '', $default_font_size - 1);
832 $pdf->SetXY($posx + 2, $posy);
833 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
834 $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, $ltrdirection);
835 }
836
837 $pdf->SetTextColor(0, 0, 0);
838
839 return $top_shift;
840 }
841
842 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
852 protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0)
853 {
854 $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0);
855 return pdf_pagefoot($pdf, $outputlangs, 'CONTRACT_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext, $this->page_largeur, $this->watermark);
856 }
857}
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 contact/addresses.
Class to manage hooks.
Parent class to manage intervention document templates.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
Class to build contracts documents with model Strato.
write_file($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0)
Function to build pdf on disk.
tabSignature(&$pdf, $tab_top, $tab_height, $outputlangs)
Show footer signature of page.
_pagefoot(&$pdf, $object, $outputlangs, $hidefreetext=0)
Show footer of page.
_pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis=null, $titlekey="Contract")
Show top header of page.
__construct($db)
Constructor.
_tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0)
Show table for lines.
global $mysoc
convertSecondToTime($iSecond, $format='all', $lengthOfDay=86400, $lengthOfWeek=7)
Return, in clear text, value of a number of seconds in days, hours and minutes.
Definition date.lib.php:248
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...
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.
getMultidirOutput($object, $module='', $forobject=0, $mode='output')
Return the full path of the directory where a module (or an object of a module) stores its files.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
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_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)
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
pdf_getFormat($outputlangs=null, $mode='setup')
Return array with format properties of default PDF format.
Definition pdf.lib.php:87
pdf_getPDFFontSize($outputlangs)
Return font size to use for PDF generation.
Definition pdf.lib.php:294
pdf_pagehead($pdf, $outputlangs, $page_height)
Show header of page for PDF generation.
Definition pdf.lib.php:790
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:1464
pdf_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition pdf.lib.php:273
pdf_build_address($outputlangs, $sourcecompany, $targetcompany='', $targetcontact='', $usecontact=0, $mode='source', $object=null)
Return a string with full address formatted for output on PDF documents.
Definition pdf.lib.php:479
pdf_writeLogoOrCompanyName($pdf, $outputlangs, $emetteur, $logodir, $posx, $posy, $w, $default_font_size, $align)
Output company logo on top-left of a PDF page header, or the company name as fallback text if no logo...
Definition pdf.lib.php:349
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:1178
pdf_getInstance($format='', $metric='mm', $pagetype='P')
Return a PDF instance object.
Definition pdf.lib.php:129
pdfBuildThirdpartyName($thirdparty, Translate $outputlangs, $includealias=0)
Returns the name of the thirdparty.
Definition pdf.lib.php:434
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