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;
 
  62   (undef, undef, $form->{template_meta}{tmpfile}) = File::Spec->splitpath($tmpfile);
 
  64   my $parser  = SL::Template::create(
 
  65     type      => ($params{template_type} || 'LaTeX'),
 
  66     source    => $form->{IN},
 
  68     myconfig  => \%::myconfig,
 
  70     variable_content_types => $params{variable_content_types},
 
  73   my $result = $parser->parse($temp_fh);
 
  80     die $parser->get_error;
 
  83   # SL::Template:** modify $form->{tmpfile} by removing its
 
  84   # $form->{userspath} prefix. They also store the final file's actual
 
  85   # file name in $form->{tmpfile} – but it is now relative to
 
  86   # $form->{userspath}. Other modules return the full file name…
 
  87   my ($volume, $directory, $file_name) = File::Spec->splitpath($form->{tmpfile});
 
  88   my $full_file_name                   = File::Spec->catfile($tmpdir, $file_name);
 
  89   if (($params{return} || 'content') eq 'file_name') {
 
  90     my $new_name = File::Spec->catfile($tmpdir, 'keep-' . $form->{tmpfile});
 
  91     rename $full_file_name, $new_name;
 
  98   my $content = File::Slurp::read_file($full_file_name);
 
 106   my ($class, %params) = @_;
 
 108   return scalar(File::Slurp::read_file($params{file_names}->[0])) if scalar(@{ $params{file_names} }) < 2;
 
 110   my ($temp_fh, $temp_name) = File::Temp::tempfile(
 
 111     'kivitendo-printXXXXXX',
 
 113     DIR    => $::lx_office_conf{paths}->{userspath},
 
 114     UNLINK => ($::lx_office_conf{debug} && $::lx_office_conf{debug}->{keep_temp_files})? 0 : 1,
 
 118   my $input_names = join ' ', String::ShellQuote::shell_quote(@{ $params{file_names} });
 
 119   my $exe         = $::lx_office_conf{applications}->{ghostscript} || 'gs';
 
 120   my $output      = `$exe -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=${temp_name} ${input_names} 2>&1`;
 
 122   die "Executing gs failed: $ERRNO" if !defined $output;
 
 123   die $output                       if $? != 0;
 
 125   return scalar File::Slurp::read_file($temp_name);
 
 129   my ($class, %params) = @_;
 
 131   $params{name} or croak "Missing parameter 'name'";
 
 133   my $path                 = $::instance_conf->get_templates;
 
 134   my $extension            = $params{extension} || "tex";
 
 135   my ($printer, $language) = ('', '');
 
 137   if ($params{printer} || $params{printer_id}) {
 
 138     if ($params{printer} && !ref $params{printer}) {
 
 139       $printer = '_' . $params{printer};
 
 141       $printer = $params{printer} || SL::DB::Printer->new(id => $params{printer_id})->load;
 
 142       $printer = $printer->template_code ? '_' . $printer->template_code : '';
 
 146   if ($params{language} || $params{language_id}) {
 
 147     if ($params{language} && !ref $params{language}) {
 
 148       $language = '_' . $params{language};
 
 150       $language = $params{language} || SL::DB::Language->new(id => $params{language_id})->load;
 
 151       $language = $language->template_code ? '_' . $language->template_code : '';
 
 155   my @template_files = (
 
 156     $params{name} . "${language}${printer}",
 
 157     $params{name} . "${language}",
 
 162   if ($params{email}) {
 
 163     unshift @template_files, (
 
 164       $params{name} . "_email${language}${printer}",
 
 165       $params{name} . "_email${language}",
 
 169   @template_files = map { "${_}.${extension}" } uniq grep { $_ } @template_files;
 
 171   my $template = first { -f ($path . "/$_") } @template_files;
 
 173   return wantarray ? ($template, @template_files) : $template;
 
 185 SL::Helper::CreatePDF - A helper for creating PDFs from template files
 
 189   # Retrieve a sales order from the database and create a PDF for
 
 191   my $order               = SL::DB::Order->new(id => …)->load;
 
 192   my $print_form          = Form->new('');
 
 193   $print_form->{type}     = 'invoice';
 
 194   $print_form->{formname} = 'invoice',
 
 195   $print_form->{format}   = 'pdf',
 
 196   $print_form->{media}    = 'file';
 
 198   $order->flatten_to_form($print_form, format_amounts => 1);
 
 199   $print_form->prepare_for_printing;
 
 201   my $pdf = SL::Helper::CreatePDF->create_pdf(
 
 202     template  => 'sales_order',
 
 203     variables => $print_form,
 
 210 =item C<create_pdf %params>
 
 212 Parses a LaTeX template file, creates a PDF for it and returns either
 
 213 its content or its file name. The recognized parameters are the same
 
 214 as the ones for L</create_parsed_file> with C<format> and
 
 215 C<template_type> being pre-set.
 
 217 =item C<create_parsed_file %params>
 
 219 Parses a template file and returns either its content or its file
 
 220 name. The recognized parameters are:
 
 224 =item * C<template> – mandatory. The template file name relative to
 
 225 the users' templates directory. Must be an existing file name,
 
 226 e.g. one retrieved by L</find_template>.
 
 228 =item * C<variables> – optional hash reference containing variables
 
 229 available to the template.
 
 231 =item * C<return> – optional scalar containing either C<content> (the
 
 232 default) or C<file_name>. If it is set to C<file_name> then the file
 
 233 name of the temporary file containing the PDF is returned, and the
 
 234 caller is responsible for deleting it. Otherwise a scalar containing
 
 235 the PDF itself is returned and all temporary files have already been
 
 236 deleted by L</create_pdf>.
 
 238 =item * C<format> – optional, defaults to C<pdf> and determines the
 
 239 output format. Can be set to C<html> for HTML output if
 
 240 C<template_type> is set to C<HTML> as well.
 
 242 =item * C<template_type> – optional, defaults to C<LaTeX> and
 
 243 determines the template's format. Can be set to C<HTML> for HTML
 
 244 output if C<format> is set to C<html> as well.
 
 248 =item C<find_template %params>
 
 250 Searches the user's templates directory for a template file name to
 
 251 use. The file names considered depend on the parameters; they can
 
 252 contain a template base name and suffixes for email, language and
 
 253 printers. As a fallback the name C<default.$extension> is also
 
 256 The return value depends on the context. In scalar context the
 
 257 template file name that matches the given parameters is returned. It's
 
 258 a file name relative to the user's templates directory. If no template
 
 259 file is found then C<undef> is returned.
 
 261 In list context the first element is the same value as in scalar
 
 262 context. Additionally a list of considered template file names is
 
 265 The recognized parameters are:
 
 269 =item * C<name> – mandatory. The template's file name basis
 
 270 without any additional suffix or extension, e.g. C<sales_quotation>.
 
 272 =item * C<extension> – optional file name extension to use without the
 
 273 dot. Defaults to C<tex>.
 
 275 =item * C<email> – optional flag indicating whether or not the
 
 276 template is to be sent via email. If set to true then template file
 
 277 names containing C<_email> are considered as well.
 
 279 =item * C<language> and C<language_id> – optional parameters
 
 280 indicating the language to be used. C<language> can be either a string
 
 281 containing the language code to use or an instance of
 
 282 C<SL::DB::Language>. C<language_id> can contain the ID of the
 
 283 C<SL::DB:Language> instance to load and use. If given template file
 
 284 names containing C<_language_template_code> are considered as well.
 
 286 =item * C<printer> and C<printer_id> – optional parameters indicating
 
 287 the printer to be used. C<printer> can be either a string containing
 
 288 the printer code to use or an instance of
 
 289 C<SL::DB::Printer>. C<printer_id> can contain the ID of the
 
 290 C<SL::DB:Printer> instance to load and use. If given template file
 
 291 names containing C<_printer_template_code> are considered as well.
 
 295 =item C<merge_pdfs %params>
 
 297 Merges two or more PDFs into a single PDF by using the external
 
 298 application ghostscript.
 
 300 The recognized parameters are:
 
 304 =item * C<file_names> – mandatory array reference containing the file
 
 309 Note that this function relies on the presence of the external
 
 310 application ghostscript. The executable to use is configured via
 
 311 kivitendo's configuration file setting C<application.ghostscript>.
 
 321 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>