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,
71 my $result = $parser->parse($temp_fh);
78 die $parser->get_error;
81 # SL::Template:** modify $form->{tmpfile} by removing its
82 # $form->{userspath} prefix. They also store the final file's actual
83 # file name in $form->{tmpfile} – but it is now relative to
84 # $form->{userspath}. Other modules return the full file name…
85 my ($volume, $directory, $file_name) = File::Spec->splitpath($form->{tmpfile});
86 my $full_file_name = File::Spec->catfile($tmpdir, $file_name);
87 if (($params{return} || 'content') eq 'file_name') {
88 my $new_name = File::Spec->catfile($tmpdir, 'keep-' . $form->{tmpfile});
89 rename $full_file_name, $new_name;
96 my $content = File::Slurp::read_file($full_file_name);
104 my ($class, %params) = @_;
106 return scalar(File::Slurp::read_file($params{file_names}->[0])) if scalar(@{ $params{file_names} }) < 2;
108 my ($temp_fh, $temp_name) = File::Temp::tempfile(
109 'kivitendo-printXXXXXX',
111 DIR => $::lx_office_conf{paths}->{userspath},
112 UNLINK => ($::lx_office_conf{debug} && $::lx_office_conf{debug}->{keep_temp_files})? 0 : 1,
116 my $input_names = join ' ', String::ShellQuote::shell_quote(@{ $params{file_names} });
117 my $exe = $::lx_office_conf{applications}->{ghostscript} || 'gs';
118 my $output = `$exe -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=${temp_name} ${input_names} 2>&1`;
120 die "Executing gs failed: $ERRNO" if !defined $output;
121 die $output if $? != 0;
123 return scalar File::Slurp::read_file($temp_name);
127 my ($class, %params) = @_;
129 $params{name} or croak "Missing parameter 'name'";
131 my $path = $::instance_conf->get_templates;
132 my $extension = $params{extension} || "tex";
133 my ($printer, $language) = ('', '');
135 if ($params{printer} || $params{printer_id}) {
136 if ($params{printer} && !ref $params{printer}) {
137 $printer = '_' . $params{printer};
139 $printer = $params{printer} || SL::DB::Printer->new(id => $params{printer_id})->load;
140 $printer = $printer->template_code ? '_' . $printer->template_code : '';
144 if ($params{language} || $params{language_id}) {
145 if ($params{language} && !ref $params{language}) {
146 $language = '_' . $params{language};
148 $language = $params{language} || SL::DB::Language->new(id => $params{language_id})->load;
149 $language = $language->template_code ? '_' . $language->template_code : '';
153 my @template_files = (
154 $params{name} . "${language}${printer}",
155 $params{name} . "${language}",
160 if ($params{email}) {
161 unshift @template_files, (
162 $params{name} . "_email${language}${printer}",
163 $params{name} . "_email${language}",
167 @template_files = map { "${_}.${extension}" } uniq grep { $_ } @template_files;
169 my $template = first { -f ($path . "/$_") } @template_files;
171 return wantarray ? ($template, @template_files) : $template;
183 SL::Helper::CreatePDF - A helper for creating PDFs from template files
187 # Retrieve a sales order from the database and create a PDF for
189 my $order = SL::DB::Order->new(id => …)->load;
190 my $print_form = Form->new('');
191 $print_form->{type} = 'invoice';
192 $print_form->{formname} = 'invoice',
193 $print_form->{format} = 'pdf',
194 $print_form->{media} = 'file';
196 $order->flatten_to_form($print_form, format_amounts => 1);
197 $print_form->prepare_for_printing;
199 my $pdf = SL::Helper::CreatePDF->create_pdf(
200 template => 'sales_order',
201 variables => $print_form,
208 =item C<create_pdf %params>
210 Parses a LaTeX template file, creates a PDF for it and returns either
211 its content or its file name. The recognized parameters are the same
212 as the ones for L</create_parsed_file> with C<format> and
213 C<template_type> being pre-set.
215 =item C<create_parsed_file %params>
217 Parses a template file and returns either its content or its file
218 name. The recognized parameters are:
222 =item * C<template> – mandatory. The template file name relative to
223 the users' templates directory. Must be an existing file name,
224 e.g. one retrieved by L</find_template>.
226 =item * C<variables> – optional hash reference containing variables
227 available to the template.
229 =item * C<return> – optional scalar containing either C<content> (the
230 default) or C<file_name>. If it is set to C<file_name> then the file
231 name of the temporary file containing the PDF is returned, and the
232 caller is responsible for deleting it. Otherwise a scalar containing
233 the PDF itself is returned and all temporary files have already been
234 deleted by L</create_pdf>.
236 =item * C<format> – optional, defaults to C<pdf> and determines the
237 output format. Can be set to C<html> for HTML output if
238 C<template_type> is set to C<HTML> as well.
240 =item * C<template_type> – optional, defaults to C<LaTeX> and
241 determines the template's format. Can be set to C<HTML> for HTML
242 output if C<format> is set to C<html> as well.
246 =item C<find_template %params>
248 Searches the user's templates directory for a template file name to
249 use. The file names considered depend on the parameters; they can
250 contain a template base name and suffixes for email, language and
251 printers. As a fallback the name C<default.$extension> is also
254 The return value depends on the context. In scalar context the
255 template file name that matches the given parameters is returned. It's
256 a file name relative to the user's templates directory. If no template
257 file is found then C<undef> is returned.
259 In list context the first element is the same value as in scalar
260 context. Additionally a list of considered template file names is
263 The recognized parameters are:
267 =item * C<name> – mandatory. The template's file name basis
268 without any additional suffix or extension, e.g. C<sales_quotation>.
270 =item * C<extension> – optional file name extension to use without the
271 dot. Defaults to C<tex>.
273 =item * C<email> – optional flag indicating whether or not the
274 template is to be sent via email. If set to true then template file
275 names containing C<_email> are considered as well.
277 =item * C<language> and C<language_id> – optional parameters
278 indicating the language to be used. C<language> can be either a string
279 containing the language code to use or an instance of
280 C<SL::DB::Language>. C<language_id> can contain the ID of the
281 C<SL::DB:Language> instance to load and use. If given template file
282 names containing C<_language_template_code> are considered as well.
284 =item * C<printer> and C<printer_id> – optional parameters indicating
285 the printer to be used. C<printer> can be either a string containing
286 the printer code to use or an instance of
287 C<SL::DB::Printer>. C<printer_id> can contain the ID of the
288 C<SL::DB:Printer> instance to load and use. If given template file
289 names containing C<_printer_template_code> are considered as well.
293 =item C<merge_pdfs %params>
295 Merges two or more PDFs into a single PDF by using the external
296 application ghostscript.
298 The recognized parameters are:
302 =item * C<file_names> – mandatory array reference containing the file
307 Note that this function relies on the presence of the external
308 application ghostscript. The executable to use is configured via
309 kivitendo's configuration file setting C<application.ghostscript>.
319 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>