Issues (2811)

public/htdocs/barcode/printsheet.php (1 issue)

Labels
Severity
1
<?php
2
3
/* Copyright (C) 2003       Rodolphe Quiedeville        <[email protected]>
4
 * Copyright (C) 2003	    Jean-Louis Bergamo	        <[email protected]>
5
 * Copyright (C) 2006-2017  Laurent Destailleur	        <[email protected]>
6
 * Copyright (C) 2024		MDW							<[email protected]>
7
 * Copyright (C) 2024       Rafael San José             <[email protected]>
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21
 */
22
23
use Dolibarr\Code\Core\Classes\Form;
24
use Dolibarr\Code\Core\Classes\FormBarCode;
25
use Dolibarr\Code\Core\Classes\GenericObject;
26
use Dolibarr\Code\Product\Classes\Product;
27
use Dolibarr\Code\Societe\Classes\Societe;
28
use Dolibarr\Lib\AveryLabels;
29
use Dolibarr\Lib\ViewMain;
30
31
/**
32
 *  \file       htdocs/barcode/printsheet.php
33
 *  \ingroup    member
34
 *  \brief      Page to print sheets with barcodes using the document templates into core/modules/printsheets
35
 */
36
37
// Do not use GETPOST, the function does not exists yet.
38
if (!empty($_POST['mode']) && $_POST['mode'] === 'label') { // Page is called to build a PDF and output, we must not renew the token.
39
    if (!defined('NOTOKENRENEWAL')) {
40
        define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on)
41
    }
42
}
43
44
// Load Dolibarr environment
45
require constant('DOL_DOCUMENT_ROOT') . '/main.inc.php';
46
require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
47
48
// Load translation files required by the page
49
$langs->loadLangs(array('admin', 'members', 'errors'));
50
51
// Choice of print year or current year.
52
$now = dol_now();
53
$year = dol_print_date($now, '%Y');
54
$month = dol_print_date($now, '%m');
55
$day = dol_print_date($now, '%d');
56
$forbarcode = GETPOST('forbarcode', 'alphanohtml');
57
$fk_barcode_type = GETPOSTINT('fk_barcode_type');
58
$mode = GETPOST('mode', 'aZ09');
59
$modellabel = GETPOST("modellabel", 'aZ09'); // Doc template to use
60
$numberofsticker = GETPOSTINT('numberofsticker');
61
62
$mesg = '';
63
64
$action = GETPOST('action', 'aZ09');
65
66
$producttmp = new Product($db);
67
$thirdpartytmp = new Societe($db);
68
69
// Security check (enable the most restrictive one)
70
//if ($user->socid > 0) accessforbidden();
71
//if ($user->socid > 0) $socid = $user->socid;
72
if (!isModEnabled('barcode')) {
73
    accessforbidden('Module not enabled');
74
}
75
if (!$user->hasRight('barcode', 'read')) {
76
    accessforbidden();
77
}
78
restrictedArea($user, 'barcode');
79
80
// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
81
$hookmanager->initHooks(array('printsheettools'));
82
83
$parameters = array();
84
85
// Note that $action and $object may have been modified by some
86
$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action);
87
if ($reshook < 0) {
88
    setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
89
}
90
91
/*
92
 * Actions
93
 */
94
95
if (empty($reshook)) {
96
    if (GETPOST('submitproduct') && GETPOST('submitproduct')) {
97
        $action = ''; // We reset because we don't want to build doc
98
        if (GETPOSTINT('productid') > 0) {
99
            $result = $producttmp->fetch(GETPOSTINT('productid'));
100
            if ($result < 0) {
101
                setEventMessage($producttmp->error, 'errors');
102
            }
103
            $forbarcode = $producttmp->barcode;
104
            $fk_barcode_type = $producttmp->barcode_type;
105
106
            if (empty($fk_barcode_type) && getDolGlobalString('PRODUIT_DEFAULT_BARCODE_TYPE')) {
107
                $fk_barcode_type = getDolGlobalString('PRODUIT_DEFAULT_BARCODE_TYPE');
108
            }
109
110
            if (empty($forbarcode) || empty($fk_barcode_type)) {
111
                setEventMessages($langs->trans("DefinitionOfBarCodeForProductNotComplete", $producttmp->getNomUrl()), null, 'warnings');
112
            }
113
        }
114
    }
115
    if (GETPOST('submitthirdparty') && GETPOST('submitthirdparty')) {
116
        $action = ''; // We reset because we don't want to build doc
117
        if (GETPOSTINT('socid') > 0) {
118
            $thirdpartytmp->fetch(GETPOSTINT('socid'));
119
            $forbarcode = $thirdpartytmp->barcode;
120
            $fk_barcode_type = $thirdpartytmp->barcode_type_code;
121
122
            if (empty($fk_barcode_type) && getDolGlobalString('GENBARCODE_BARCODETYPE_THIRDPARTY')) {
123
                $fk_barcode_type = getDolGlobalString('GENBARCODE_BARCODETYPE_THIRDPARTY');
124
            }
125
126
            if (empty($forbarcode) || empty($fk_barcode_type)) {
127
                setEventMessages($langs->trans("DefinitionOfBarCodeForThirdpartyNotComplete", $thirdpartytmp->getNomUrl()), null, 'warnings');
128
            }
129
        }
130
    }
131
132
    if ($action == 'builddoc') {
133
        $result = 0;
134
        $error = 0;
135
136
        if (empty($forbarcode)) {           // barcode value
137
            setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("BarcodeValue")), null, 'errors');
138
            $error++;
139
        }
140
        $MAXLENGTH = 51200; // Limit set to 50Ko
141
        if (dol_strlen($forbarcode) > $MAXLENGTH) {         // barcode value
142
            setEventMessages($langs->trans("ErrorFieldTooLong", $langs->transnoentitiesnoconv("BarcodeValue")) . ' (' . $langs->trans("RequireXStringMax", $MAXLENGTH) . ')', null, 'errors');
143
            $error++;
144
        }
145
        if (empty($fk_barcode_type)) {      // barcode type = barcode encoding
146
            setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("BarcodeType")), null, 'errors');
147
            $error++;
148
        }
149
150
        if (!$error) {
151
            // Get encoder (barcode_type_coder) from barcode type id (barcode_type)
152
            $stdobject = new GenericObject($db);
153
            $stdobject->barcode_type = $fk_barcode_type;
154
            $result = $stdobject->fetch_barcode();
155
            if ($result <= 0) {
156
                $error++;
157
                setEventMessages('Failed to get bar code type information ' . $stdobject->error, $stdobject->errors, 'errors');
158
            }
159
        }
160
161
        if (!$error) {
162
            $code = $forbarcode;
163
            $generator = $stdobject->barcode_type_coder; // coder (loaded by fetch_barcode). Engine.
164
            $encoding = strtoupper($stdobject->barcode_type_code); // code (loaded by fetch_barcode). Example 'ean', 'isbn', ...
165
166
            $diroutput = $conf->barcode->dir_temp;
167
            dol_mkdir($diroutput);
168
169
            // Generate barcode
170
            $dirbarcode = array_merge(array("/core/modules/barcode/doc/"), $conf->modules_parts['barcode']);
171
172
            foreach ($dirbarcode as $reldir) {
173
                $dir = dol_buildpath($reldir, 0);
174
                $newdir = dol_osencode($dir);
175
176
                // Check if directory exists (we do not use dol_is_dir to avoid loading files.lib.php)
177
                if (!is_dir($newdir)) {
178
                    continue;
179
                }
180
181
                $result = @include_once $newdir . $generator . '.modules.php';
182
                if ($result) {
183
                    break;
184
                }
185
            }
186
187
            // Load barcode class for generating barcode image
188
            $classname = "mod" . ucfirst($generator);
189
            $module = new $classname($db);
190
            '@phan-var-force ModeleBarCode $module';
191
            if ($generator != 'tcpdfbarcode') {
192
                // May be phpbarcode
193
                $template = 'standardlabel';
194
                $is2d = false;
195
                if ($module->encodingIsSupported($encoding)) {
196
                    $barcodeimage = $conf->barcode->dir_temp . '/barcode_' . $code . '_' . $encoding . '.png';
197
                    dol_delete_file($barcodeimage);
198
                    // File is created with full name $barcodeimage = $conf->barcode->dir_temp.'/barcode_'.$code.'_'.$encoding.'.png';
199
                    $result = $module->writeBarCode($code, $encoding, 'Y', 4, 1);
200
                    if ($result <= 0 || !dol_is_file($barcodeimage)) {
201
                        $error++;
202
                        setEventMessages('Failed to generate image file of barcode for code=' . $code . ' encoding=' . $encoding . ' file=' . basename($barcodeimage), null, 'errors');
203
                        setEventMessages($module->error, null, 'errors');
204
                    }
205
                } else {
206
                    $error++;
207
                    setEventMessages("Error, encoding " . $encoding . " is not supported by encoder " . $generator . '. You must choose another barcode type or install a barcode generation engine that support ' . $encoding, null, 'errors');
208
                }
209
            } else {
210
                $template = 'tcpdflabel';
211
                $encoding = $module->getTcpdfEncodingType($encoding); //convert to TCPDF compatible encoding types
212
                $is2d = $module->is2d;
213
            }
214
        }
215
216
        if (!$error) {
217
            // List of values to scan for a replacement
218
            $substitutionarray = array(
219
                '%LOGIN%' => $user->login,
220
                '%COMPANY%' => $mysoc->name,
221
                '%ADDRESS%' => $mysoc->address,
222
                '%ZIP%' => $mysoc->zip,
223
                '%TOWN%' => $mysoc->town,
224
                '%COUNTRY%' => $mysoc->country,
225
                '%COUNTRY_CODE%' => $mysoc->country_code,
226
                '%EMAIL%' => $mysoc->email,
227
                '%YEAR%' => $year,
228
                '%MONTH%' => $month,
229
                '%DAY%' => $day,
230
                '%DOL_MAIN_URL_ROOT%' => DOL_MAIN_URL_ROOT,
231
                '%SERVER%' => "http://" . $_SERVER["SERVER_NAME"] . "/",
232
            );
233
            complete_substitutions_array($substitutionarray, $langs);
234
235
            $arrayofrecords = array();
236
            // For labels
237
            if ($mode == 'label') {
238
                $txtforsticker = "%PHOTO%"; // Photo will be barcode image, %BARCODE% possible when using TCPDF generator
239
                $textleft = make_substitutions(getDolGlobalString('BARCODE_LABEL_LEFT_TEXT', $txtforsticker), $substitutionarray);
240
                $textheader = make_substitutions(getDolGlobalString('BARCODE_LABEL_HEADER_TEXT'), $substitutionarray);
241
                $textfooter = make_substitutions(getDolGlobalString('BARCODE_LABEL_FOOTER_TEXT'), $substitutionarray);
242
                $textright = make_substitutions(getDolGlobalString('BARCODE_LABEL_RIGHT_TEXT'), $substitutionarray);
243
                $forceimgscalewidth = getDolGlobalString('BARCODE_FORCEIMGSCALEWIDTH', 1);
244
                $forceimgscaleheight = getDolGlobalString('BARCODE_FORCEIMGSCALEHEIGHT', 1);
245
246
                $MAXSTICKERS = 1000;
247
                if ($numberofsticker <= $MAXSTICKERS) {
248
                    for ($i = 0; $i < $numberofsticker; $i++) {
249
                        $arrayofrecords[] = array(
250
                            'textleft' => $textleft,
251
                            'textheader' => $textheader,
252
                            'textfooter' => $textfooter,
253
                            'textright' => $textright,
254
                            'code' => $code,
255
                            'encoding' => $encoding,
256
                            'is2d' => $is2d,
257
                            'photo' => !empty($barcodeimage) ? $barcodeimage : ''   // Photo must be a file that exists with format supported by TCPDF
258
                        );
259
                    }
260
                } else {
261
                    $mesg = $langs->trans("ErrorQuantityIsLimitedTo", $MAXSTICKERS);
262
                    $error++;
263
                }
264
            }
265
266
            // Build and output PDF
267
            if (!$error && $mode == 'label') {
268
                if (!count($arrayofrecords)) {
269
                    $mesg = $langs->trans("ErrorRecordNotFound");
270
                }
271
                if (empty($modellabel) || $modellabel == '-1') {
272
                    $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("DescADHERENT_ETIQUETTE_TYPE"));
273
                }
274
275
                $outfile = $langs->trans("BarCode") . '_sheets_' . dol_print_date(dol_now(), 'dayhourlog') . '.pdf';
276
277
                if (!$mesg) {
278
                    $outputlangs = $langs;
279
280
                    $previousConf = getDolGlobalInt('TCPDF_THROW_ERRORS_INSTEAD_OF_DIE');
281
                    $conf->global->TCPDF_THROW_ERRORS_INSTEAD_OF_DIE = 1;
282
283
                    // This generates and send PDF to output
284
                    // TODO Move
285
                    try {
286
                        $result = doc_label_pdf_create($db, $arrayofrecords, $modellabel, $outputlangs, $diroutput, $template, dol_sanitizeFileName($outfile));
0 ignored issues
show
The function doc_label_pdf_create was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

286
                        $result = /** @scrutinizer ignore-call */ doc_label_pdf_create($db, $arrayofrecords, $modellabel, $outputlangs, $diroutput, $template, dol_sanitizeFileName($outfile));
Loading history...
287
                    } catch (Exception $e) {
288
                        $mesg = $langs->trans('ErrorGeneratingBarcode');
289
                    }
290
291
                    $conf->global->TCPDF_THROW_ERRORS_INSTEAD_OF_DIE = $previousConf;
292
                }
293
            }
294
295
            if ($result <= 0 || $mesg || $error) {
296
                if (empty($mesg)) {
297
                    $mesg = 'Error ' . $result;
298
                }
299
300
                setEventMessages($mesg, null, 'errors');
301
            } else {
302
                $db->close();
303
                exit;
304
            }
305
        }
306
    }
307
}
308
309
/*
310
 * View
311
 */
312
313
$form = new Form($db);
314
315
ViewMain::llxHeader('', $langs->trans("BarCodePrintsheet"), '', '', 0, 0, '', '', '', 'mod-barcode page-printsheet');
316
317
print load_fiche_titre($langs->trans("BarCodePrintsheet"), '', 'barcode');
318
print '<br>';
319
320
print '<span class="opacitymedium">' . $langs->trans("PageToGenerateBarCodeSheets", $langs->transnoentitiesnoconv("BuildPageToPrint")) . '</span><br>';
321
print '<br>';
322
323
//print img_picto('','puce').' '.$langs->trans("PrintsheetForOneBarCode").'<br>';
324
//print '<br>';
325
326
print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST">'; // The target is for brothers that open the file instead of downloading it
327
print '<input type="hidden" name="mode" value="label">';
328
print '<input type="hidden" name="action" value="builddoc">';
329
print '<input type="hidden" name="token" value="' . currentToken() . '">'; // The page will not renew the token but force download of a file, so we must use here currentToken
330
331
print '<div class="tagtable">';
332
333
// Sheet format
334
print '	<div class="tagtr">';
335
print '	<div class="tagtd">';
336
print $langs->trans("DescADHERENT_ETIQUETTE_TYPE") . ' &nbsp; ';
337
print '</div><div class="tagtd maxwidthonsmartphone" style="overflow: hidden; white-space: nowrap;">';
338
339
// List of possible labels (defined into $_Avery_Labels variable set into core/lib/format_cards.lib.php)
340
$_Avery_Labels = AveryLabels::getAveryLabels();
341
$arrayoflabels = array();
342
foreach (array_keys($_Avery_Labels) as $codecards) {
343
    $labeltoshow = $_Avery_Labels[$codecards]['name'];
344
    //$labeltoshow.=' ('.$_Avery_Labels[$row['code']]['paper-size'].')';
345
    $arrayoflabels[$codecards] = $labeltoshow;
346
}
347
asort($arrayoflabels);
348
print $form->selectarray('modellabel', $arrayoflabels, (GETPOST('modellabel') ? GETPOST('modellabel') : getDolGlobalString('ADHERENT_ETIQUETTE_TYPE')), 1, 0, 0, '', 0, 0, 0, '', '', 1);
349
print '</div></div>';
350
351
// Number of stickers to print
352
print '	<div class="tagtr">';
353
print '	<div class="tagtd">';
354
print $langs->trans("NumberOfStickers") . ' &nbsp; ';
355
print '</div><div class="tagtd maxwidthonsmartphone" style="overflow: hidden; white-space: nowrap;">';
356
print '<input size="4" type="text" name="numberofsticker" value="' . (GETPOST('numberofsticker') ? GETPOSTINT('numberofsticker') : 10) . '">';
357
print '</div></div>';
358
359
print '</div>';
360
361
362
print '<br>';
363
364
365
// Add javascript to make choice dynamic
366
print '<script type="text/javascript">
367
jQuery(document).ready(function() {
368
	function init_selectors()
369
	{
370
		if (jQuery("#fillmanually:checked").val() == "fillmanually")
371
		{
372
			jQuery("#submitproduct").prop("disabled", true);
373
			jQuery("#submitthirdparty").prop("disabled", true);
374
			jQuery("#search_productid").prop("disabled", true);
375
			jQuery("#socid").prop("disabled", true);
376
			jQuery(".showforproductselector").hide();
377
			jQuery(".showforthirdpartyselector").hide();
378
		}
379
		if (jQuery("#fillfromproduct:checked").val() == "fillfromproduct")
380
		{
381
			jQuery("#submitproduct").removeAttr("disabled");
382
			jQuery("#submitthirdparty").prop("disabled", true);
383
			jQuery("#search_productid").removeAttr("disabled");
384
			jQuery("#socid").prop("disabled", true);
385
			jQuery(".showforproductselector").show();
386
			jQuery(".showforthirdpartyselector").hide();
387
		}
388
		if (jQuery("#fillfromthirdparty:checked").val() == "fillfromthirdparty")
389
		{
390
			jQuery("#submitproduct").prop("disabled", true);
391
			jQuery("#submitthirdparty").removeAttr("disabled");
392
			jQuery("#search_productid").prop("disabled", true);
393
			jQuery("#socid").removeAttr("disabled");
394
			jQuery(".showforproductselector").hide();
395
			jQuery(".showforthirdpartyselector").show();
396
		}
397
	}
398
	init_selectors();
399
	jQuery(".radiobarcodeselect").click(function() {
400
		init_selectors();
401
	});
402
403
	function init_gendoc_button()
404
	{
405
		if (jQuery("#select_fk_barcode_type").val() > 0 && jQuery("#forbarcode").val())
406
		{
407
			jQuery("#submitformbarcodegen").removeAttr("disabled");
408
		}
409
		else
410
		{
411
			jQuery("#submitformbarcodegen").prop("disabled", true);
412
		}
413
	}
414
	init_gendoc_button();
415
	jQuery("#select_fk_barcode_type").change(function() {
416
		init_gendoc_button();
417
	});
418
	jQuery("#forbarcode").keyup(function() {
419
		init_gendoc_button()
420
	});
421
});
422
</script>';
423
424
// Checkbox to select from free text
425
print '<input id="fillmanually" type="radio" ' . ((!GETPOST("selectorforbarcode") || GETPOST("selectorforbarcode") == 'fillmanually') ? 'checked ' : '') . 'name="selectorforbarcode" value="fillmanually" class="radiobarcodeselect"><label for="fillmanually"> ' . $langs->trans("FillBarCodeTypeAndValueManually") . '</label>';
426
print '<br>';
427
428
if ($user->hasRight('produit', 'lire') || $user->hasRight('service', 'lire')) {
429
    print '<input id="fillfromproduct" type="radio" ' . ((GETPOST("selectorforbarcode") == 'fillfromproduct') ? 'checked ' : '') . 'name="selectorforbarcode" value="fillfromproduct" class="radiobarcodeselect"><label for="fillfromproduct"> ' . $langs->trans("FillBarCodeTypeAndValueFromProduct") . '</label>';
430
    print '<br>';
431
    print '<div class="showforproductselector">';
432
    $form->select_produits(GETPOSTINT('productid'), 'productid', '', '', 0, -1, 2, '', 0, array(), 0, '1', 0, 'minwidth400imp', 1);
433
    print ' &nbsp; <input type="submit" class="button small" id="submitproduct" name="submitproduct" value="' . (dol_escape_htmltag($langs->trans("GetBarCode"))) . '">';
434
    print '</div>';
435
}
436
437
if ($user->hasRight('societe', 'lire')) {
438
    print '<input id="fillfromthirdparty" type="radio" ' . ((GETPOST("selectorforbarcode") == 'fillfromthirdparty') ? 'checked ' : '') . 'name="selectorforbarcode" value="fillfromthirdparty" class="radiobarcodeselect"><label for="fillfromthirdparty"> ' . $langs->trans("FillBarCodeTypeAndValueFromThirdParty") . '</label>';
439
    print '<br>';
440
    print '<div class="showforthirdpartyselector">';
441
    print $form->select_company(GETPOSTINT('socid'), 'socid', '', 'SelectThirdParty', 0, 0, array(), 0, 'minwidth300');
442
    print ' &nbsp; <input type="submit" id="submitthirdparty" name="submitthirdparty" class="button showforthirdpartyselector small" value="' . (dol_escape_htmltag($langs->trans("GetBarCode"))) . '">';
443
    print '</div>';
444
}
445
446
print '<br>';
447
448
if ($producttmp->id > 0) {
449
    print $langs->trans("BarCodeDataForProduct", '') . ' ' . $producttmp->getNomUrl(1) . '<br>';
450
}
451
if ($thirdpartytmp->id > 0) {
452
    print $langs->trans("BarCodeDataForThirdparty", '') . ' ' . $thirdpartytmp->getNomUrl(1) . '<br>';
453
}
454
455
print '<div class="tagtable">';
456
457
// Barcode type
458
print '	<div class="tagtr">';
459
print '	<div class="tagtd" style="overflow: hidden; white-space: nowrap; max-width: 300px;">';
460
print $langs->trans("BarcodeType") . ' &nbsp; ';
461
print '</div><div class="tagtd" style="overflow: hidden; white-space: nowrap; max-width: 300px;">';
462
$formbarcode = new FormBarCode($db);
463
print $formbarcode->selectBarcodeType($fk_barcode_type, 'fk_barcode_type', 1);
464
print '</div></div>';
465
466
// Barcode value
467
print '	<div class="tagtr">';
468
print '	<div class="tagtd" style="overflow: hidden; white-space: nowrap; max-width: 300px;">';
469
print $langs->trans("BarcodeValue") . ' &nbsp; ';
470
print '</div><div class="tagtd" style="overflow: hidden; white-space: nowrap; max-width: 300px;">';
471
print '<input size="16" type="text" name="forbarcode" id="forbarcode" value="' . $forbarcode . '">';
472
print '</div></div>';
473
474
/*
475
$barcodestickersmask=GETPOST('barcodestickersmask');
476
print '<br>'.$langs->trans("BarcodeStickersMask").':<br>';
477
print '<textarea cols="40" type="text" name="barcodestickersmask" value="'.GETPOST('barcodestickersmask').'">'.$barcodestickersmask.'</textarea>';
478
print '<br>';
479
*/
480
481
print '</div>';
482
483
print '<br><input type="submit" class="button" id="submitformbarcodegen" ' . ((GETPOST("selectorforbarcode") && GETPOST("selectorforbarcode")) ? '' : 'disabled ') . 'value="' . $langs->trans("BuildPageToPrint") . '">';
484
485
print '</form>';
486
print '<br>';
487
488
// End of page
489
ViewMain::llxFooter();
490
$db->close();
491