1 package SL::Helper::CreatePDF;
7 use English qw(-no_match_vars);
11 use List::MoreUtils qw(uniq);
12 use List::Util qw(first);
13 use String::ShellQuote ();
21 use SL::Template::LaTeX;
23 use Exporter 'import';
24 our @EXPORT_OK = qw(create_pdf merge_pdfs find_template);
30 my ($class, %params) = @_;
32 return __PACKAGE__->create_parsed_file(
34 template_type => 'LaTeX',
39 sub create_parsed_file {
40 my ($class, %params) = @_;
42 my $userspath = $::lx_office_conf{paths}->{userspath};
43 my $vars = $params{variables} || {};
44 my $form = Form->new('');
45 $form->{$_} = $vars->{$_} for keys %{ $vars };
46 $form->{format} = lc($params{format} || 'pdf');
47 $form->{cwd} = getcwd();
48 $form->{templates} = $::instance_conf->get_templates;
49 $form->{IN} = $params{template};
50 $form->{tmpdir} = $form->{cwd} . '/' . $userspath;
51 my $tmpdir = $form->{tmpdir};
52 my ($suffix) = $params{template} =~ m{\.(.+)};
54 my ($temp_fh, $tmpfile) = File::Temp::tempfile(
55 'kivitendo-printXXXXXX',
56 SUFFIX => ".${suffix}",
57 DIR => $form->{tmpdir},
58 UNLINK => ($::lx_office_conf{debug} && $::lx_office_conf{debug}->{keep_temp_files})? 0 : 1,
61 $form->{tmpfile} = $tmpfile;
63 my $parser = SL::Template::create(
64 type => ($params{template_type} || 'LaTeX'),
65 source => $form->{IN},
67 myconfig => \%::myconfig,
69 variable_content_types => $params{variable_content_types},
72 my $result = $parser->parse($temp_fh);
79 die $parser->get_error;
82 # SL::Template:** modify $form->{tmpfile} by removing its
83 # $form->{userspath} prefix. They also store the final file's actual
84 # file name in $form->{tmpfile} – but it is now relative to
85 # $form->{userspath}. Other modules return the full file name…
86 my ($volume, $directory, $file_name) = File::Spec->splitpath($form->{tmpfile});
87 my $full_file_name = File::Spec->catfile($tmpdir, $file_name);
88 if (($params{return} || 'content') eq 'file_name') {
89 my $new_name = File::Spec->catfile($tmpdir, 'keep-' . $form->{tmpfile});
90 rename $full_file_name, $new_name;
97 my $content = File::Slurp::read_file($full_file_name);
105 my ($class, %params) = @_;
107 return scalar(File::Slurp::read_file($params{file_names}->[0])) if scalar(@{ $params{file_names} }) < 2;
109 my ($temp_fh, $temp_name) = File::Temp::tempfile(
110 'kivitendo-printXXXXXX',
112 DIR => $::lx_office_conf{paths}->{userspath},
113 UNLINK => ($::lx_office_conf{debug} && $::lx_office_conf{debug}->{keep_temp_files})? 0 : 1,
117 my $input_names = join ' ', String::ShellQuote::shell_quote(@{ $params{file_names} });
118 my $exe = $::lx_office_conf{applications}->{ghostscript} || 'gs';
119 my $output = `$exe -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=${temp_name} ${input_names} 2>&1`;
121 die "Executing gs failed: $ERRNO" if !defined $output;
122 die $output if $? != 0;
124 return scalar File::Slurp::read_file($temp_name);
128 my ($class, %params) = @_;
130 $params{name} or croak "Missing parameter 'name'";
132 my $path = $::instance_conf->get_templates;
133 my $extension = $params{extension} || "tex";
134 my ($printer, $language) = ('', '');
136 if ($params{printer} || $params{printer_id}) {
137 if ($params{printer} && !ref $params{printer}) {
138 $printer = '_' . $params{printer};
140 $printer = $params{printer} || SL::DB::Printer->new(id => $params{printer_id})->load;
141 $printer = $printer->template_code ? '_' . $printer->template_code : '';
145 if ($params{language} || $params{language_id}) {
146 if ($params{language} && !ref $params{language}) {
147 $language = '_' . $params{language};
149 $language = $params{language} || SL::DB::Language->new(id => $params{language_id})->load;
150 $language = $language->template_code ? '_' . $language->template_code : '';
154 my @template_files = (
155 $params{name} . "${language}${printer}",
156 $params{name} . "${language}",
161 if ($params{email}) {
162 unshift @template_files, (
163 $params{name} . "_email${language}${printer}",
164 $params{name} . "_email${language}",
168 @template_files = map { "${_}.${extension}" } uniq grep { $_ } @template_files;
170 my $template = first { -f ($path . "/$_") } @template_files;
172 return wantarray ? ($template, @template_files) : $template;
184 SL::Helper::CreatePDF - A helper for creating PDFs from template files
188 # Retrieve a sales order from the database and create a PDF for
190 my $order = SL::DB::Order->new(id => …)->load;
191 my $print_form = Form->new('');
192 $print_form->{type} = 'invoice';
193 $print_form->{formname} = 'invoice',
194 $print_form->{format} = 'pdf',
195 $print_form->{media} = 'file';
197 $order->flatten_to_form($print_form, format_amounts => 1);
198 $print_form->prepare_for_printing;
200 my $pdf = SL::Helper::CreatePDF->create_pdf(
201 template => 'sales_order',
202 variables => $print_form,
209 =item C<create_pdf %params>
211 Parses a LaTeX template file, creates a PDF for it and returns either
212 its content or its file name. The recognized parameters are the same
213 as the ones for L</create_parsed_file> with C<format> and
214 C<template_type> being pre-set.
216 =item C<create_parsed_file %params>
218 Parses a template file and returns either its content or its file
219 name. The recognized parameters are:
223 =item * C<template> – mandatory. The template file name relative to
224 the users' templates directory. Must be an existing file name,
225 e.g. one retrieved by L</find_template>.
227 =item * C<variables> – optional hash reference containing variables
228 available to the template.
230 =item * C<return> – optional scalar containing either C<content> (the
231 default) or C<file_name>. If it is set to C<file_name> then the file
232 name of the temporary file containing the PDF is returned, and the
233 caller is responsible for deleting it. Otherwise a scalar containing
234 the PDF itself is returned and all temporary files have already been
235 deleted by L</create_pdf>.
237 =item * C<format> – optional, defaults to C<pdf> and determines the
238 output format. Can be set to C<html> for HTML output if
239 C<template_type> is set to C<HTML> as well.
241 =item * C<template_type> – optional, defaults to C<LaTeX> and
242 determines the template's format. Can be set to C<HTML> for HTML
243 output if C<format> is set to C<html> as well.
247 =item C<find_template %params>
249 Searches the user's templates directory for a template file name to
250 use. The file names considered depend on the parameters; they can
251 contain a template base name and suffixes for email, language and
252 printers. As a fallback the name C<default.$extension> is also
255 The return value depends on the context. In scalar context the
256 template file name that matches the given parameters is returned. It's
257 a file name relative to the user's templates directory. If no template
258 file is found then C<undef> is returned.
260 In list context the first element is the same value as in scalar
261 context. Additionally a list of considered template file names is
264 The recognized parameters are:
268 =item * C<name> – mandatory. The template's file name basis
269 without any additional suffix or extension, e.g. C<sales_quotation>.
271 =item * C<extension> – optional file name extension to use without the
272 dot. Defaults to C<tex>.
274 =item * C<email> – optional flag indicating whether or not the
275 template is to be sent via email. If set to true then template file
276 names containing C<_email> are considered as well.
278 =item * C<language> and C<language_id> – optional parameters
279 indicating the language to be used. C<language> can be either a string
280 containing the language code to use or an instance of
281 C<SL::DB::Language>. C<language_id> can contain the ID of the
282 C<SL::DB:Language> instance to load and use. If given template file
283 names containing C<_language_template_code> are considered as well.
285 =item * C<printer> and C<printer_id> – optional parameters indicating
286 the printer to be used. C<printer> can be either a string containing
287 the printer code to use or an instance of
288 C<SL::DB::Printer>. C<printer_id> can contain the ID of the
289 C<SL::DB:Printer> instance to load and use. If given template file
290 names containing C<_printer_template_code> are considered as well.
294 =item C<merge_pdfs %params>
296 Merges two or more PDFs into a single PDF by using the external
297 application ghostscript.
299 The recognized parameters are:
303 =item * C<file_names> – mandatory array reference containing the file
308 Note that this function relies on the presence of the external
309 application ghostscript. The executable to use is configured via
310 kivitendo's configuration file setting C<application.ghostscript>.
320 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>