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 my $userspath = $::lx_office_conf{paths}->{userspath};
32 my $vars = $params{variables} || {};
33 my $form = Form->new('');
34 $form->{$_} = $vars->{$_} for keys %{ $vars };
35 $form->{format} = 'pdf';
36 $form->{cwd} = getcwd();
37 $form->{templates} = $::instance_conf->get_templates;
38 $form->{IN} = $params{template};
39 $form->{tmpdir} = $form->{cwd} . '/' . $userspath;
40 my ($suffix) = $params{template} =~ m{\.(.+)};
43 ($temp_fh, $form->{tmpfile}) = File::Temp::tempfile(
44 'kivitendo-printXXXXXX',
45 SUFFIX => ".${suffix}",
47 UNLINK => ($::lx_office_conf{debug} && $::lx_office_conf{debug}->{keep_temp_files})? 0 : 1,
50 my $parser = SL::Template::LaTeX->new(
57 my $result = $parser->parse($temp_fh);
64 die $parser->get_error;
67 if (($params{return} || 'content') eq 'file_name') {
68 my $new_name = $userspath . '/keep-' . $form->{tmpfile};
69 rename $userspath . '/' . $form->{tmpfile}, $new_name;
76 my $pdf = File::Slurp::read_file($userspath . '/' . $form->{tmpfile});
84 my ($class, %params) = @_;
86 return scalar(File::Slurp::read_file($params{file_names}->[0])) if scalar(@{ $params{file_names} }) < 2;
88 my ($temp_fh, $temp_name) = File::Temp::tempfile(
89 'kivitendo-printXXXXXX',
91 DIR => $::lx_office_conf{paths}->{userspath},
92 UNLINK => ($::lx_office_conf{debug} && $::lx_office_conf{debug}->{keep_temp_files})? 0 : 1,
96 my $input_names = join ' ', String::ShellQuote::shell_quote(@{ $params{file_names} });
97 my $exe = $::lx_office_conf{applications}->{ghostscript} || 'gs';
98 my $output = `$exe -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=${temp_name} ${input_names} 2>&1`;
100 die "Executing gs failed: $ERRNO" if !defined $output;
101 die $output if $? != 0;
103 return scalar File::Slurp::read_file($temp_name);
107 my ($class, %params) = @_;
109 $params{name} or croak "Missing parameter 'name'";
111 my $path = $::instance_conf->get_templates;
112 my $extension = $params{extension} || "tex";
113 my ($printer, $language) = ('', '');
115 if ($params{printer} || $params{printer_id}) {
116 if ($params{printer} && !ref $params{printer}) {
117 $printer = '_' . $params{printer};
119 $printer = $params{printer} || SL::DB::Printer->new(id => $params{printer_id})->load;
120 $printer = $printer->template_code ? '_' . $printer->template_code : '';
124 if ($params{language} || $params{language_id}) {
125 if ($params{language} && !ref $params{language}) {
126 $language = '_' . $params{language};
128 $language = $params{language} || SL::DB::Language->new(id => $params{language_id})->load;
129 $language = $language->template_code ? '_' . $language->template_code : '';
133 my @template_files = (
134 $params{name} . "${language}${printer}",
135 $params{name} . "${language}",
140 if ($params{email}) {
141 unshift @template_files, (
142 $params{name} . "_email${language}${printer}",
143 $params{name} . "_email${language}",
147 @template_files = map { "${_}.${extension}" } uniq grep { $_ } @template_files;
149 my $template = first { -f ($path . "/$_") } @template_files;
151 return wantarray ? ($template, @template_files) : $template;
163 SL::Helper::CreatePDF - A helper for creating PDFs from template files
167 # Retrieve a sales order from the database and create a PDF for
169 my $order = SL::DB::Order->new(id => …)->load;
170 my $print_form = Form->new('');
171 $print_form->{type} = 'invoice';
172 $print_form->{formname} = 'invoice',
173 $print_form->{format} = 'pdf',
174 $print_form->{media} = 'file';
176 $order->flatten_to_form($print_form, format_amounts => 1);
177 $print_form->prepare_for_printing;
179 my $pdf = SL::Helper::CreatePDF->create_pdf(
180 template => 'sales_order',
181 variables => $print_form,
188 =item C<create_pdf %params>
190 Parses a LaTeX template file, creates a PDF for it and returns either
191 its content or its file name. The recognized parameters are:
195 =item * C<template> – mandatory. The template file name relative to
196 the users' templates directory. Must be an existing file name,
197 e.g. one retrieved by L</find_template>.
199 =item * C<variables> – optional hash reference containing variables
200 available to the template.
202 =item * C<return> – optional scalar containing either C<content> (the
203 default) or C<file_name>. If it is set to C<file_name> then the file
204 name of the temporary file containing the PDF is returned, and the
205 caller is responsible for deleting it. Otherwise a scalar containing
206 the PDF itself is returned and all temporary files have already been
207 deleted by L</create_pdf>.
211 =item C<find_template %params>
213 Searches the user's templates directory for a template file name to
214 use. The file names considered depend on the parameters; they can
215 contain a template base name and suffixes for email, language and
216 printers. As a fallback the name C<default.$extension> is also
219 The return value depends on the context. In scalar context the
220 template file name that matches the given parameters is returned. It's
221 a file name relative to the user's templates directory. If no template
222 file is found then C<undef> is returned.
224 In list context the first element is the same value as in scalar
225 context. Additionally a list of considered template file names is
228 The recognized parameters are:
232 =item * C<name> – mandatory. The template's file name basis
233 without any additional suffix or extension, e.g. C<sales_quotation>.
235 =item * C<extension> – optional file name extension to use without the
236 dot. Defaults to C<tex>.
238 =item * C<email> – optional flag indicating whether or not the
239 template is to be sent via email. If set to true then template file
240 names containing C<_email> are considered as well.
242 =item * C<language> and C<language_id> – optional parameters
243 indicating the language to be used. C<language> can be either a string
244 containing the language code to use or an instance of
245 C<SL::DB::Language>. C<language_id> can contain the ID of the
246 C<SL::DB:Language> instance to load and use. If given template file
247 names containing C<_language_template_code> are considered as well.
249 =item * C<printer> and C<printer_id> – optional parameters indicating
250 the printer to be used. C<printer> can be either a string containing
251 the printer code to use or an instance of
252 C<SL::DB::Printer>. C<printer_id> can contain the ID of the
253 C<SL::DB:Printer> instance to load and use. If given template file
254 names containing C<_printer_template_code> are considered as well.
258 =item C<merge_pdfs %params>
260 Merges two or more PDFs into a single PDF by using the external
261 application ghostscript.
263 The recognized parameters are:
267 =item * C<file_names> – mandatory array reference containing the file
272 Note that this function relies on the presence of the external
273 application ghostscript. The executable to use is configured via
274 kivitendo's configuration file setting C<application.ghostscript>.
284 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>