From d33015393db77e9bc8e0deeb1a39500b3b5a49eb Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 14 Apr 2005 09:41:41 +0000 Subject: [PATCH] move invoice_latex templating to Text::Template, with special sauce^W^Wbackwards-compatibility for old templates --- FS/FS/cust_bill.pm | 310 ++++++++++++++++++++++++++++++++---------------- conf/invoice_latex | 75 ++++++------ conf/invoice_latex.diff | 138 +++++++++++++++++++++ 3 files changed, 389 insertions(+), 134 deletions(-) create mode 100644 conf/invoice_latex.diff diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 10b4928cb..4c37e68b2 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -4,7 +4,7 @@ use strict; use vars qw( @ISA $conf $money_char ); use vars qw( $invoice_lines @buf ); #yuck use Date::Format; -use Text::Template; +use Text::Template 1.20; use File::Temp 0.14; use String::ShellQuote; use FS::UID qw( datasrc ); @@ -418,16 +418,17 @@ sub send { my @print_text = $self->print_text('', $template); my @invoicing_list = $self->cust_main->invoicing_list; - if ( grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list or !@invoicing_list ) { #email + if ( grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list or !@invoicing_list ) { + #email #better to notify this person than silence @invoicing_list = ($invoice_from) unless @invoicing_list; my $error = send_email( $self->generate_email( - 'from' => $invoice_from, - 'to' => [ grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list ], - 'print_text' => [ @print_text ], + 'from' => $invoice_from, + 'to' => [ grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list ], + 'print_text' => [ @print_text ], ) ); die "can't email invoice: $error\n" if $error; @@ -454,9 +455,8 @@ sub send { } if ( grep { $_ eq 'FAX' } @invoicing_list ) { #fax - unless ($conf->exists('invoice_latex')) { - die 'FAX invoice destination not supported with plain text invoices.' - } + die 'FAX invoice destination not supported with plain text invoices.' + unless $conf->exists('invoice_latex'); my $dialstring = $self->cust_main->getfield('fax'); #Check $dialstring? my $error = send_fax(docdata => $lpr_data, dialstring => $dialstring); @@ -1102,9 +1102,27 @@ sub print_latex { my $templatefile = 'invoice_latex'; my $suffix = length($template) ? "_$template" : ''; $templatefile .= $suffix; - my @invoice_template = $conf->config($templatefile) + my @invoice_template = map "$_\n", $conf->config($templatefile) or die "cannot load config file $templatefile"; + my($format, $text_template); + if ( grep { /^%%Detail/ } @invoice_template ) { + #change this to a die when the old code is removed + warn "old-style invoice template $templatefile; ". + "patch with conf/invoice_latex.diff\n"; + $format = 'old'; + } else { + $format = 'Text::Template'; + $text_template = new Text::Template( + TYPE => 'ARRAY', + SOURCE => \@invoice_template, + DELIMITERS => [ '[@--', '--@]' ], + ); + + $text_template->compile() + or die 'While compiling ' . $templatefile . ': ' . $Text::Template::ERROR; + } + my %invoice_data = ( 'invnum' => $self->invnum, 'date' => time2str('%b %o, %Y', $self->_date), @@ -1143,110 +1161,198 @@ sub print_latex { ? _latex_escape("Purchase Order #". $cust_main->payinfo) : '~'; - my @line_item = (); - my @total_item = (); my @filled_in = (); - while ( @invoice_template ) { - my $line = shift @invoice_template; - - if ( $line =~ /^%%Detail\s*$/ ) { - - while ( ( my $line_item_line = shift @invoice_template ) - !~ /^%%EndDetail\s*$/ ) { - push @line_item, $line_item_line; - } - foreach my $line_item ( $self->_items ) { - #foreach my $line_item ( $self->_items_pkg ) { - $invoice_data{'ref'} = $line_item->{'pkgnum'}; - $invoice_data{'description'} = _latex_escape($line_item->{'description'}); - if ( exists $line_item->{'ext_description'} ) { - $invoice_data{'description'} .= - "\\tabularnewline\n~~". - join("\\tabularnewline\n~~", map { _latex_escape($_) } @{$line_item->{'ext_description'}} ); + if ( $format eq 'old' ) { + + my @line_item = (); + my @total_item = (); + while ( @invoice_template ) { + my $line = shift @invoice_template; + + if ( $line =~ /^%%Detail\s*$/ ) { + + while ( ( my $line_item_line = shift @invoice_template ) + !~ /^%%EndDetail\s*$/ ) { + push @line_item, $line_item_line; } - $invoice_data{'amount'} = $line_item->{'amount'}; - $invoice_data{'product_code'} = $line_item->{'pkgpart'} || 'N/A'; - push @filled_in, - map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } @line_item; - } - - } elsif ( $line =~ /^%%TotalDetails\s*$/ ) { - - while ( ( my $total_item_line = shift @invoice_template ) - !~ /^%%EndTotalDetails\s*$/ ) { - push @total_item, $total_item_line; - } - - my @total_fill = (); - - my $taxtotal = 0; - foreach my $tax ( $self->_items_tax ) { - $invoice_data{'total_item'} = _latex_escape($tax->{'description'}); - $taxtotal += ( $invoice_data{'total_amount'} = $tax->{'amount'} ); + foreach my $line_item ( $self->_items ) { + #foreach my $line_item ( $self->_items_pkg ) { + $invoice_data{'ref'} = $line_item->{'pkgnum'}; + $invoice_data{'description'} = + _latex_escape($line_item->{'description'}); + if ( exists $line_item->{'ext_description'} ) { + $invoice_data{'description'} .= + "\\tabularnewline\n~~". + join( "\\tabularnewline\n~~", + map _latex_escape($_), @{$line_item->{'ext_description'}} + ); + } + $invoice_data{'amount'} = $line_item->{'amount'}; + $invoice_data{'product_code'} = $line_item->{'pkgpart'} || 'N/A'; + push @filled_in, + map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } @line_item; + } + + } elsif ( $line =~ /^%%TotalDetails\s*$/ ) { + + while ( ( my $total_item_line = shift @invoice_template ) + !~ /^%%EndTotalDetails\s*$/ ) { + push @total_item, $total_item_line; + } + + my @total_fill = (); + + my $taxtotal = 0; + foreach my $tax ( $self->_items_tax ) { + $invoice_data{'total_item'} = _latex_escape($tax->{'description'}); + $taxtotal += ( $invoice_data{'total_amount'} = $tax->{'amount'} ); + push @total_fill, + map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } + @total_item; + } + + if ( $taxtotal ) { + $invoice_data{'total_item'} = 'Sub-total'; + $invoice_data{'total_amount'} = + '\dollar '. sprintf('%.2f', $self->charged - $taxtotal ); + unshift @total_fill, + map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } + @total_item; + } + + $invoice_data{'total_item'} = '\textbf{Total}'; + $invoice_data{'total_amount'} = + '\textbf{\dollar '. sprintf('%.2f', $self->charged + $pr_total ). '}'; push @total_fill, map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } @total_item; - } - - if ( $taxtotal ) { - $invoice_data{'total_item'} = 'Sub-total'; + + #foreach my $thing ( sort { $a->_date <=> $b->_date } $self->_items_credits, $self->_items_payments + + # credits + foreach my $credit ( $self->_items_credits ) { + $invoice_data{'total_item'} = _latex_escape($credit->{'description'}); + #$credittotal + $invoice_data{'total_amount'} = '-\dollar '. $credit->{'amount'}; + push @total_fill, + map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } + @total_item; + } + + # payments + foreach my $payment ( $self->_items_payments ) { + $invoice_data{'total_item'} = _latex_escape($payment->{'description'}); + #$paymenttotal + $invoice_data{'total_amount'} = '-\dollar '. $payment->{'amount'}; + push @total_fill, + map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } + @total_item; + } + + $invoice_data{'total_item'} = '\textbf{'. $self->balance_due_msg. '}'; $invoice_data{'total_amount'} = - '\dollar '. sprintf('%.2f', $self->charged - $taxtotal ); - unshift @total_fill, + '\textbf{\dollar '. sprintf('%.2f', $self->owed + $pr_total ). '}'; + push @total_fill, map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } @total_item; + + push @filled_in, @total_fill; + + } else { + #$line =~ s/\$(\w+)/$invoice_data{$1}/eg; + $line =~ s/\$(\w+)/exists($invoice_data{$1}) ? $invoice_data{$1} : nounder($1)/eg; + push @filled_in, $line; } + + } - $invoice_data{'total_item'} = '\textbf{Total}'; - $invoice_data{'total_amount'} = - '\textbf{\dollar '. sprintf('%.2f', $self->charged + $pr_total ). '}'; - push @total_fill, - map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } - @total_item; - - #foreach my $thing ( sort { $a->_date <=> $b->_date } $self->_items_credits, $self->_items_payments - - # credits - foreach my $credit ( $self->_items_credits ) { - $invoice_data{'total_item'} = _latex_escape($credit->{'description'}); - #$credittotal - $invoice_data{'total_amount'} = '-\dollar '. $credit->{'amount'}; - push @total_fill, - map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } - @total_item; - } + sub nounder { + my $var = $1; + $var =~ s/_/\-/g; + $var; + } - # payments - foreach my $payment ( $self->_items_payments ) { - $invoice_data{'total_item'} = _latex_escape($payment->{'description'}); - #$paymenttotal - $invoice_data{'total_amount'} = '-\dollar '. $payment->{'amount'}; - push @total_fill, - map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } - @total_item; + } elsif ( $format eq 'Text::Template' ) { + + my @detail_items = (); + my @total_items = (); + + $invoice_data{'detail_items'} = \@detail_items; + $invoice_data{'total_items'} = \@total_items; + + foreach my $line_item ( $self->_items ) { + my $detail = { + ext_description => [], + }; + $detail->{'ref'} = $line_item->{'pkgnum'}; + $detail->{'quantity'} = 1; + $detail->{'description'} = _latex_escape($line_item->{'description'}); + if ( exists $line_item->{'ext_description'} ) { + @{$detail->{'ext_description'}} = map { + _latex_escape($_); + } @{$line_item->{'ext_description'}}; } - - $invoice_data{'total_item'} = '\textbf{'. $self->balance_due_msg. '}'; - $invoice_data{'total_amount'} = + $detail->{'amount'} = $line_item->{'amount'}; + $detail->{'product_code'} = $line_item->{'pkgpart'} || 'N/A'; + + push @detail_items, $detail; + } + + + my $taxtotal = 0; + foreach my $tax ( $self->_items_tax ) { + my $total = {}; + $total->{'total_item'} = _latex_escape($tax->{'description'}); + $taxtotal += ( $invoice_data{'total_amount'} = $tax->{'amount'} ); + push @total_items, $total; + } + + if ( $taxtotal ) { + my $total = {}; + $total->{'total_item'} = 'Sub-total'; + $total->{'total_amount'} = + '\dollar '. sprintf('%.2f', $self->charged - $taxtotal ); + unshift @total_items, $total; + } + + { + my $total = {}; + $total->{'total_item'} = '\textbf{Total}'; + $total->{'total_amount'} = + '\textbf{\dollar '. sprintf('%.2f', $self->charged + $pr_total ). '}'; + push @total_items, $total; + } + + #foreach my $thing ( sort { $a->_date <=> $b->_date } $self->_items_credits, $self->_items_payments + + # credits + foreach my $credit ( $self->_items_credits ) { + my $total; + $total->{'total_item'} = _latex_escape($credit->{'description'}); + #$credittotal + $total->{'total_amount'} = '-\dollar '. $credit->{'amount'}; + push @total_items, $total; + } + + # payments + foreach my $payment ( $self->_items_payments ) { + my $total = {}; + $total->{'total_item'} = _latex_escape($payment->{'description'}); + #$paymenttotal + $total->{'total_amount'} = '-\dollar '. $payment->{'amount'}; + push @total_items, $total; + } + + { + my $total; + $total->{'total_item'} = '\textbf{'. $self->balance_due_msg. '}'; + $total->{'total_amount'} = '\textbf{\dollar '. sprintf('%.2f', $self->owed + $pr_total ). '}'; - push @total_fill, - map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } - @total_item; - - push @filled_in, @total_fill; - - } else { - #$line =~ s/\$(\w+)/$invoice_data{$1}/eg; - $line =~ s/\$(\w+)/exists($invoice_data{$1}) ? $invoice_data{$1} : nounder($1)/eg; - push @filled_in, $line; + push @total_items, $total; } - } - - sub nounder { - my $var = $1; - $var =~ s/_/\-/g; - $var; + } else { + die "guru meditation #54"; } my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc; @@ -1255,7 +1361,13 @@ sub print_latex { SUFFIX => '.tex', UNLINK => 0, ) or die "can't open temp file: $!\n"; - print $fh join("\n", @filled_in ), "\n"; + if ( $format eq 'old' ) { + print $fh join('', @filled_in ); + } elsif ( $format eq 'Text::Template' ) { + $text_template->fill_in(OUTPUT => $fh, HASH => \%invoice_data); + } else { + die "guru meditation #32"; + } close $fh; $fh->filename =~ /^(.*).tex$/ or die "unparsable filename: ". $fh->filename; diff --git a/conf/invoice_latex b/conf/invoice_latex index 195f8fbb2..e7f6d08d6 100644 --- a/conf/invoice_latex +++ b/conf/invoice_latex @@ -5,7 +5,7 @@ %% Asplen Management Ltd %% www.asplen.co.uk %% -%% Modified for Freeside by Ivan Kohler +%% Modified for Freeside by Ivan Kohler and Kristian Hoffman %% %% Changes %% 0.1 4/12/00 Created @@ -61,7 +61,7 @@ %% Headers and footers defined for the first page \fancyfoot[CO,CE]{\small{ \begin{tabular}{c} -$footer +[@-- $footer --@] \end{tabular}}} % %% The LH Heading comprising logo @@ -76,7 +76,7 @@ $footer \begin{tabular}{rcl} Invoice date & & Invoice number \\ \vspace{0.2cm} -\textbf{$date} & & \textbf{$invnum} \\\hline +\textbf{[@-- $date --@]} & & \textbf{[@-- $invnum --@]} \\\hline \rule{0pt}{5ex} &~~ \huge{\textsc{Invoice}}& \\ \vspace{-0.2cm} & & \\\hline @@ -85,71 +85,76 @@ Invoice date & & Invoice number \\ %% Header & footer changes for subsequent pages % \afterpage{ \fancyfoot[RO,RE]{\small{\thepage\ of \pageref{LastPage}}} } -\afterpage{ \fancyfoot[CO,CE]{\small{$smallfooter}} } +\afterpage{ \fancyfoot[CO,CE]{\small{[@-- $smallfooter --@]}} } \afterpage{ \fancyhead[LO,LE]{\small{}} } \afterpage{ \fancyhead[RO,RE]{\small{ \begin{tabular}{ll} Invoice date & Invoice number\\ -\textbf{$date} & \textbf{$invnum}\\ +\textbf{[@-- $date --@]} & \textbf{[@-- $invnum --@]}\\ \end{tabular}}} } % % \makebox{ \begin{minipage}[t]{2.9in} \vspace{0.20in} -\textbf{$payname}\\ -\addressline{$company} -\addressline{$address1} -\addressline{$address2} -\addressline{$city, $state $zip} -\addressline{$country} +\textbf{[@-- $payname --@]}\\ +\addressline{[@-- $company --@]} +\addressline{[@-- $address1 --@]} +\addressline{[@-- $address2 --@]} +\addressline{[@-- $city --@], [@-- $state --@] [@-- $zip --@]} +\addressline{[@-- $country --@]} \end{minipage}} \hfill \makebox{ \begin{minipage}[t]{2.5in} \begin{flushright} -Terms: $terms\\ -$po_line\\ +Terms: [@-- $terms --@]\\ +[@-- $po_line --@]\\ \end{flushright} \end{minipage}} \vspace{0.5cm} % \section*{\textsc{Charges}} -\begin{longtable}{|c|l|c|r|r|} +\begin{longtable}{|c|l|r|} \hline \rule{0pt}{2.5ex} \makebox[1.4cm]{\textbf{Ref}} & -\makebox[7.9cm][l]{\textbf{Description}} & -\makebox[1.3cm][c]{\textbf{Quantity}} & -\makebox[2.5cm][r]{\textbf{Unit Price}} & -\makebox[2.5cm][r]{\textbf{Amount}} \\ +\makebox[13cm][l]{\textbf{Description}} & +\makebox[2cm][r]{\textbf{Amount}} \\ \hline \endfirsthead -\multicolumn{5}{r}{\rule{0pt}{2.5ex}Continued from previous page}\\ +\multicolumn{3}{r}{\rule{0pt}{2.5ex}Continued from previous page}\\ \hline \rule{0pt}{2.5ex} \makebox[1.4cm]{\textbf{Ref}} & -\makebox[7.9cm][l]{\textbf{Description}} & -\makebox[1.3cm][c]{\textbf{Quantity}} & -\makebox[2.5cm][r]{\textbf{Unit Price}} & -\makebox[2.5cm][r]{\textbf{Amount}} \\ +\makebox[13cm][l]{\textbf{Description}} & +\makebox[2cm][r]{\textbf{Amount}} \\ \hline \endhead -\multicolumn{5}{r}{\rule{0pt}{2.5ex}/cont...}\\ +\multicolumn{3}{r}{\rule{0pt}{2.5ex}/cont...}\\ \endfoot -%%TotalDetails - & \multicolumn{3}{l}{$total_item} & $total_amount\\ -%%EndTotalDetails +[@-- + + foreach my $line (@total_items) { + $OUT .= ' & \multicolumn{1}{l}{' . $line->{'total_item'} . '} & ' . + $line->{'total_amount'} . '\\\\' . "\n"; + } + +--@] \hline \endlastfoot -%%Detail -\rule{0pt}{2.5ex}$ref & -\begin{tabular}{l} -$description\tabularnewline -\end{tabular} -& $quantity & \dollar $amount & \dollar $amount\\\hline -%%EndDetail +[@-- + + foreach my $line (@detail_items) { + $OUT .= '\rule{0pt}{2.5ex}' . $line->{'ref'} . ' &' . "\n". + '\begin{tabular}{l}' . "\n". + $line->{'description'} . '\tabularnewline' . "\n". + '\end{tabular}' . "\n". + '& \dollar ' . $line->{'amount'} . '\\\\\\hline' . "\n"; + } + +--@] \end{longtable} \vfill -$notes +[@-- $notes --@] \end{document} diff --git a/conf/invoice_latex.diff b/conf/invoice_latex.diff new file mode 100644 index 000000000..b66a522f0 --- /dev/null +++ b/conf/invoice_latex.diff @@ -0,0 +1,138 @@ +--- invoice_latex.old 2005-04-14 01:52:02.000000000 -0700 ++++ invoice_latex 2005-04-14 02:33:26.000000000 -0700 +@@ -5,7 +5,7 @@ + %% Asplen Management Ltd + %% www.asplen.co.uk + %% +-%% Modified for Freeside by Ivan Kohler ++%% Modified for Freeside by Ivan Kohler and Kristian Hoffman + %% + %% Changes + %% 0.1 4/12/00 Created +@@ -61,7 +61,7 @@ + %% Headers and footers defined for the first page + \fancyfoot[CO,CE]{\small{ + \begin{tabular}{c} +-$footer ++[@-- $footer --@] + \end{tabular}}} + % + %% The LH Heading comprising logo +@@ -76,7 +76,7 @@ + \begin{tabular}{rcl} + Invoice date & & Invoice number \\ + \vspace{0.2cm} +-\textbf{$date} & & \textbf{$invnum} \\\hline ++\textbf{[@-- $date --@]} & & \textbf{[@-- $invnum --@]} \\\hline + \rule{0pt}{5ex} &~~ \huge{\textsc{Invoice}}& \\ + \vspace{-0.2cm} + & & \\\hline +@@ -85,71 +85,76 @@ + %% Header & footer changes for subsequent pages + % + \afterpage{ \fancyfoot[RO,RE]{\small{\thepage\ of \pageref{LastPage}}} } +-\afterpage{ \fancyfoot[CO,CE]{\small{$smallfooter}} } ++\afterpage{ \fancyfoot[CO,CE]{\small{[@-- $smallfooter --@]}} } + \afterpage{ \fancyhead[LO,LE]{\small{}} } + \afterpage{ \fancyhead[RO,RE]{\small{ + \begin{tabular}{ll} + Invoice date & Invoice number\\ +-\textbf{$date} & \textbf{$invnum}\\ ++\textbf{[@-- $date --@]} & \textbf{[@-- $invnum --@]}\\ + \end{tabular}}} } + % + % + \makebox{ + \begin{minipage}[t]{2.9in} + \vspace{0.20in} +-\textbf{$payname}\\ +-\addressline{$company} +-\addressline{$address1} +-\addressline{$address2} +-\addressline{$city, $state $zip} +-\addressline{$country} ++\textbf{[@-- $payname --@]}\\ ++\addressline{[@-- $company --@]} ++\addressline{[@-- $address1 --@]} ++\addressline{[@-- $address2 --@]} ++\addressline{[@-- $city --@], [@-- $state --@] [@-- $zip --@]} ++\addressline{[@-- $country --@]} + \end{minipage}} + \hfill + \makebox{ + \begin{minipage}[t]{2.5in} + \begin{flushright} +-Terms: $terms\\ +-$po_line\\ ++Terms: [@-- $terms --@]\\ ++[@-- $po_line --@]\\ + \end{flushright} + \end{minipage}} + \vspace{0.5cm} + % + \section*{\textsc{Charges}} +-\begin{longtable}{|c|l|c|r|r|} ++\begin{longtable}{|c|l|r|} + \hline + \rule{0pt}{2.5ex} + \makebox[1.4cm]{\textbf{Ref}} & +-\makebox[7.9cm][l]{\textbf{Description}} & +-\makebox[1.3cm][c]{\textbf{Quantity}} & +-\makebox[2.5cm][r]{\textbf{Unit Price}} & +-\makebox[2.5cm][r]{\textbf{Amount}} \\ ++\makebox[13cm][l]{\textbf{Description}} & ++\makebox[2cm][r]{\textbf{Amount}} \\ + \hline + \endfirsthead +-\multicolumn{5}{r}{\rule{0pt}{2.5ex}Continued from previous page}\\ ++\multicolumn{3}{r}{\rule{0pt}{2.5ex}Continued from previous page}\\ + \hline + \rule{0pt}{2.5ex} + \makebox[1.4cm]{\textbf{Ref}} & +-\makebox[7.9cm][l]{\textbf{Description}} & +-\makebox[1.3cm][c]{\textbf{Quantity}} & +-\makebox[2.5cm][r]{\textbf{Unit Price}} & +-\makebox[2.5cm][r]{\textbf{Amount}} \\ ++\makebox[13cm][l]{\textbf{Description}} & ++\makebox[2cm][r]{\textbf{Amount}} \\ + \hline + \endhead +-\multicolumn{5}{r}{\rule{0pt}{2.5ex}/cont...}\\ ++\multicolumn{3}{r}{\rule{0pt}{2.5ex}/cont...}\\ + \endfoot +-%%TotalDetails +- & \multicolumn{3}{l}{$total_item} & $total_amount\\ +-%%EndTotalDetails ++[@-- ++ ++ foreach my $line (@total_items) { ++ $OUT .= ' & \multicolumn{1}{l}{' . $line->{'total_item'} . '} & ' . ++ $line->{'total_amount'} . '\\\\' . "\n"; ++ } ++ ++--@] + \hline + \endlastfoot +-%%Detail +-\rule{0pt}{2.5ex}$ref & +-\begin{tabular}{l} +-$description\tabularnewline +-\end{tabular} +-& $quantity & \dollar $amount & \dollar $amount\\\hline +-%%EndDetail ++[@-- ++ ++ foreach my $line (@detail_items) { ++ $OUT .= '\rule{0pt}{2.5ex}' . $line->{'ref'} . ' &' . "\n". ++ '\begin{tabular}{l}' . "\n". ++ $line->{'description'} . '\tabularnewline' . "\n". ++ '\end{tabular}' . "\n". ++ '& \dollar ' . $line->{'amount'} . '\\\\\\hline' . "\n"; ++ } ++ ++--@] + \end{longtable} + \vfill +-$notes ++[@-- $notes --@] + \end{document} -- 2.11.0