1 package SL::Helper::CreatePDF;
7 use English qw(-no_match_vars);
10 use List::MoreUtils qw(uniq);
11 use List::Util qw(first);
12 use String::ShellQuote ();
20 use SL::Template::LaTeX;
22 use Exporter 'import';
23 our @EXPORT_OK = qw(create_pdf merge_pdfs find_template);
29 my ($class, %params) = @_;
31 return __PACKAGE__->create_parsed_file(
33 template_type => 'LaTeX',
38 sub create_parsed_file {
39 my ($class, %params) = @_;
41 my $userspath = $::lx_office_conf{paths}->{userspath};
42 my $vars = $params{variables} || {};
43 my $form = Form->new('');
44 $form->{$_} = $vars->{$_} for keys %{ $vars };
45 $form->{format} = lc($params{format} || 'pdf');
46 $form->{cwd} = getcwd();
47 $form->{templates} = $::instance_conf->get_templates;
48 $form->{IN} = $params{template};
49 $form->{tmpdir} = $form->{cwd} . '/' . $userspath;
50 my ($suffix) = $params{template} =~ m{\.(.+)};
52 my ($temp_fh, $tmpfile) = File::Temp::tempfile(
53 'kivitendo-printXXXXXX',
54 SUFFIX => ".${suffix}",
56 UNLINK => ($::lx_office_conf{debug} && $::lx_office_conf{debug}->{keep_temp_files})? 0 : 1,
59 $form->{tmpfile} = $tmpfile;
61 my $parser = SL::Template::create(
62 type => ($params{template_type} || 'LaTeX'),
63 source => $form->{IN},
65 myconfig => \%::myconfig,
66 userspath => $userspath,
69 my $result = $parser->parse($temp_fh);
76 die $parser->get_error;
79 if (($params{return} || 'content') eq 'file_name') {
80 my $new_name = $userspath . '/keep-' . $tmpfile;
81 rename $tmpfile, $new_name;
88 my $content = File::Slurp::read_file($tmpfile);
96 my ($class, %params) = @_;
98 return scalar(File::Slurp::read_file($params{file_names}->[0])) if scalar(@{ $params{file_names} }) < 2;
100 my ($temp_fh, $temp_name) = File::Temp::tempfile(
101 'kivitendo-printXXXXXX',
103 DIR => $::lx_office_conf{paths}->{userspath},
104 UNLINK => ($::lx_office_conf{debug} && $::lx_office_conf{debug}->{keep_temp_files})? 0 : 1,
108 my $input_names = join ' ', String::ShellQuote::shell_quote(@{ $params{file_names} });
109 my $exe = $::lx_office_conf{applications}->{ghostscript} || 'gs';
110 my $output = `$exe -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=${temp_name} ${input_names} 2>&1`;
112 die "Executing gs failed: $ERRNO" if !defined $output;
113 die $output if $? != 0;
115 return scalar File::Slurp::read_file($temp_name);
119 my ($class, %params) = @_;
121 $params{name} or croak "Missing parameter 'name'";
123 my $path = $::instance_conf->get_templates;
124 my $extension = $params{extension} || "tex";
125 my ($printer, $language) = ('', '');
127 if ($params{printer} || $params{printer_id}) {
128 if ($params{printer} && !ref $params{printer}) {
129 $printer = '_' . $params{printer};
131 $printer = $params{printer} || SL::DB::Printer->new(id => $params{printer_id})->load;
132 $printer = $printer->template_code ? '_' . $printer->template_code : '';
136 if ($params{language} || $params{language_id}) {
137 if ($params{language} && !ref $params{language}) {
138 $language = '_' . $params{language};
140 $language = $params{language} || SL::DB::Language->new(id => $params{language_id})->load;
141 $language = $language->template_code ? '_' . $language->template_code : '';
145 my @template_files = (
146 $params{name} . "${language}${printer}",
147 $params{name} . "${language}",
152 if ($params{email}) {
153 unshift @template_files, (
154 $params{name} . "_email${language}${printer}",
155 $params{name} . "_email${language}",
159 @template_files = map { "${_}.${extension}" } uniq grep { $_ } @template_files;
161 my $template = first { -f ($path . "/$_") } @template_files;
163 return wantarray ? ($template, @template_files) : $template;
175 SL::Helper::CreatePDF - A helper for creating PDFs from template files
179 # Retrieve a sales order from the database and create a PDF for
181 my $order = SL::DB::Order->new(id => …)->load;
182 my $print_form = Form->new('');
183 $print_form->{type} = 'invoice';
184 $print_form->{formname} = 'invoice',
185 $print_form->{format} = 'pdf',
186 $print_form->{media} = 'file';
188 $order->flatten_to_form($print_form, format_amounts => 1);
189 $print_form->prepare_for_printing;
191 my $pdf = SL::Helper::CreatePDF->create_pdf(
192 template => 'sales_order',
193 variables => $print_form,
200 =item C<create_pdf %params>
202 Parses a LaTeX template file, creates a PDF for it and returns either
203 its content or its file name. The recognized parameters are the same
204 as the ones for L</create_parsed_file> with C<format> and
205 C<template_type> being pre-set.
207 =item C<create_parsed_file %params>
209 Parses a template file and returns either its content or its file
210 name. The recognized parameters are:
214 =item * C<template> – mandatory. The template file name relative to
215 the users' templates directory. Must be an existing file name,
216 e.g. one retrieved by L</find_template>.
218 =item * C<variables> – optional hash reference containing variables
219 available to the template.
221 =item * C<return> – optional scalar containing either C<content> (the
222 default) or C<file_name>. If it is set to C<file_name> then the file
223 name of the temporary file containing the PDF is returned, and the
224 caller is responsible for deleting it. Otherwise a scalar containing
225 the PDF itself is returned and all temporary files have already been
226 deleted by L</create_pdf>.
228 =item * C<format> – optional, defaults to C<pdf> and determines the
229 output format. Can be set to C<html> for HTML output if
230 C<template_type> is set to C<HTML> as well.
232 =item * C<template_type> – optional, defaults to C<LaTeX> and
233 determines the template's format. Can be set to C<HTML> for HTML
234 output if C<format> is set to C<html> as well.
238 =item C<find_template %params>
240 Searches the user's templates directory for a template file name to
241 use. The file names considered depend on the parameters; they can
242 contain a template base name and suffixes for email, language and
243 printers. As a fallback the name C<default.$extension> is also
246 The return value depends on the context. In scalar context the
247 template file name that matches the given parameters is returned. It's
248 a file name relative to the user's templates directory. If no template
249 file is found then C<undef> is returned.
251 In list context the first element is the same value as in scalar
252 context. Additionally a list of considered template file names is
255 The recognized parameters are:
259 =item * C<name> – mandatory. The template's file name basis
260 without any additional suffix or extension, e.g. C<sales_quotation>.
262 =item * C<extension> – optional file name extension to use without the
263 dot. Defaults to C<tex>.
265 =item * C<email> – optional flag indicating whether or not the
266 template is to be sent via email. If set to true then template file
267 names containing C<_email> are considered as well.
269 =item * C<language> and C<language_id> – optional parameters
270 indicating the language to be used. C<language> can be either a string
271 containing the language code to use or an instance of
272 C<SL::DB::Language>. C<language_id> can contain the ID of the
273 C<SL::DB:Language> instance to load and use. If given template file
274 names containing C<_language_template_code> are considered as well.
276 =item * C<printer> and C<printer_id> – optional parameters indicating
277 the printer to be used. C<printer> can be either a string containing
278 the printer code to use or an instance of
279 C<SL::DB::Printer>. C<printer_id> can contain the ID of the
280 C<SL::DB:Printer> instance to load and use. If given template file
281 names containing C<_printer_template_code> are considered as well.
285 =item C<merge_pdfs %params>
287 Merges two or more PDFs into a single PDF by using the external
288 application ghostscript.
290 The recognized parameters are:
294 =item * C<file_names> – mandatory array reference containing the file
299 Note that this function relies on the presence of the external
300 application ghostscript. The executable to use is configured via
301 kivitendo's configuration file setting C<application.ghostscript>.
311 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>