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 $form = Form->new('');
33 $form->{format} = 'pdf';
34 $form->{cwd} = getcwd();
35 $form->{templates} = $::instance_conf->get_templates;
36 $form->{IN} = $params{template};
37 $form->{tmpdir} = $form->{cwd} . '/' . $userspath;
38 my ($suffix) = $params{template} =~ m{\.(.+)};
40 my $vars = $params{variables} || {};
41 $form->{$_} = $vars->{$_} for keys %{ $vars };
44 ($temp_fh, $form->{tmpfile}) = File::Temp::tempfile(
45 'kivitendo-printXXXXXX',
46 SUFFIX => ".${suffix}",
48 UNLINK => ($::lx_office_conf{debug} && $::lx_office_conf{debug}->{keep_temp_files})? 0 : 1,
51 my $parser = SL::Template::LaTeX->new(
58 my $result = $parser->parse($temp_fh);
65 die $parser->get_error;
68 if (($params{return} || 'content') eq 'file_name') {
69 my $new_name = $userspath . '/keep-' . $form->{tmpfile};
70 rename $userspath . '/' . $form->{tmpfile}, $new_name;
77 my $pdf = File::Slurp::read_file($userspath . '/' . $form->{tmpfile});
85 my ($class, %params) = @_;
87 return scalar(File::Slurp::read_file($params{file_names}->[0])) if scalar(@{ $params{file_names} }) < 2;
89 my ($temp_fh, $temp_name) = File::Temp::tempfile(
90 'kivitendo-printXXXXXX',
92 DIR => $::lx_office_conf{paths}->{userspath},
93 UNLINK => ($::lx_office_conf{debug} && $::lx_office_conf{debug}->{keep_temp_files})? 0 : 1,
97 my $input_names = join ' ', String::ShellQuote::shell_quote(@{ $params{file_names} });
98 my $exe = $::lx_office_conf{applications}->{ghostscript} || 'gs';
99 my $output = `$exe -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=${temp_name} ${input_names} 2>&1`;
101 die "Executing gs failed: $ERRNO" if !defined $output;
102 die $output if $? != 0;
104 return scalar File::Slurp::read_file($temp_name);
108 my ($class, %params) = @_;
110 $params{name} or croak "Missing parameter 'name'";
112 my $path = $::instance_conf->get_templates;
113 my $extension = $params{extension} || "tex";
114 my ($printer, $language) = ('', '');
116 if ($params{printer} || $params{printer_id}) {
117 if ($params{printer} && !ref $params{printer}) {
118 $printer = '_' . $params{printer};
120 $printer = $params{printer} || SL::DB::Printer->new(id => $params{printer_id})->load;
121 $printer = $printer->template_code ? '_' . $printer->template_code : '';
125 if ($params{language} || $params{language_id}) {
126 if ($params{language} && !ref $params{language}) {
127 $language = '_' . $params{language};
129 $language = $params{language} || SL::DB::Language->new(id => $params{language_id})->load;
130 $language = $language->template_code ? '_' . $language->template_code : '';
134 my @template_files = (
135 $params{name} . "${language}${printer}",
136 $params{name} . "${language}",
141 if ($params{email}) {
142 unshift @template_files, (
143 $params{name} . "_email${language}${printer}",
144 $params{name} . "_email${language}",
148 @template_files = map { "${_}.${extension}" } uniq grep { $_ } @template_files;
150 my $template = first { -f ($path . "/$_") } @template_files;
152 return wantarray ? ($template, @template_files) : $template;
164 SL::Helper::CreatePDF - A helper for creating PDFs from template files
168 # Retrieve a sales order from the database and create a PDF for
170 my $order = SL::DB::Order->new(id => …)->load;
171 my $print_form = Form->new('');
172 $print_form->{type} = 'invoice';
173 $print_form->{formname} = 'invoice',
174 $print_form->{format} = 'pdf',
175 $print_form->{media} = 'file';
177 $order->flatten_to_form($print_form, format_amounts => 1);
178 $print_form->prepare_for_printing;
180 my $pdf = SL::Helper::CreatePDF->create_pdf(
181 template => 'sales_order',
182 variables => $print_form,
189 =item C<create_pdf %params>
191 Parses a LaTeX template file, creates a PDF for it and returns either
192 its content or its file name. The recognized parameters are:
196 =item * C<template> – mandatory. The template file name relative to
197 the users' templates directory. Must be an existing file name,
198 e.g. one retrieved by L</find_template>.
200 =item * C<variables> – optional hash reference containing variables
201 available to the template.
203 =item * C<return> – optional scalar containing either C<content> (the
204 default) or C<file_name>. If it is set to C<file_name> then the file
205 name of the temporary file containing the PDF is returned, and the
206 caller is responsible for deleting it. Otherwise a scalar containing
207 the PDF itself is returned and all temporary files have already been
208 deleted by L</create_pdf>.
212 =item C<find_template %params>
214 Searches the user's templates directory for a template file name to
215 use. The file names considered depend on the parameters; they can
216 contain a template base name and suffixes for email, language and
217 printers. As a fallback the name C<default.$extension> is also
220 The return value depends on the context. In scalar context the
221 template file name that matches the given parameters is returned. It's
222 a file name relative to the user's templates directory. If no template
223 file is found then C<undef> is returned.
225 In list context the first element is the same value as in scalar
226 context. Additionally a list of considered template file names is
229 The recognized parameters are:
233 =item * C<name> – mandatory. The template's file name basis
234 without any additional suffix or extension, e.g. C<sales_quotation>.
236 =item * C<extension> – optional file name extension to use without the
237 dot. Defaults to C<tex>.
239 =item * C<email> – optional flag indicating whether or not the
240 template is to be sent via email. If set to true then template file
241 names containing C<_email> are considered as well.
243 =item * C<language> and C<language_id> – optional parameters
244 indicating the language to be used. C<language> can be either a string
245 containing the language code to use or an instance of
246 C<SL::DB::Language>. C<language_id> can contain the ID of the
247 C<SL::DB:Language> instance to load and use. If given template file
248 names containing C<_language_template_code> are considered as well.
250 =item * C<printer> and C<printer_id> – optional parameters indicating
251 the printer to be used. C<printer> can be either a string containing
252 the printer code to use or an instance of
253 C<SL::DB::Printer>. C<printer_id> can contain the ID of the
254 C<SL::DB:Printer> instance to load and use. If given template file
255 names containing C<_printer_template_code> are considered as well.
259 =item C<merge_pdfs %params>
261 Merges two or more PDFs into a single PDF by using the external
262 application ghostscript.
264 The recognized parameters are:
268 =item * C<file_names> – mandatory array reference containing the file
273 Note that this function relies on the presence of the external
274 application ghostscript. The executable to use is configured via
275 kivitendo's configuration file setting C<application.ghostscript>.
285 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>