stray closing /TABLE in the no-ticket case
[freeside.git] / conf / invoice_latex
1 %% file: Standard Multipage.tex\r
2 %% Purpose: Multipage bill template for e-Bills\r
3 %% \r
4 %% Created by Mark Asplen-Taylor\r
5 %% Asplen Management Ltd\r
6 %% www.asplen.co.uk\r
7 %%\r
8 %% Modified for Freeside by Kristian Hoffman\r
9 %%\r
10 %% Changes\r
11 %%      0.1     4/12/00 Created\r
12 %%      0.2     18/10/01        More fields added\r
13 %%      1.0     16/11/01        RELEASED\r
14 %%      1.2     16/10/02        Invoice number added\r
15 %%      1.3     2/12/02 Logo graphic added\r
16 %%      1.4     7/2/03  Multipage headers/footers added\r
17 %%      n/a     forked for Freeside; checked into CVS\r
18 %%\r
19 \r
20 \documentclass[letterpaper]{article}\r
21 \r
22 \usepackage{fancyhdr,lastpage,ifthen,array,longtable,afterpage,caption,multirow,bigstrut}\r
23 \usepackage[breakwords]{truncate} % to avoid overflowing boxes\r
24 \usepackage{graphicx}                   % required for logo graphic\r
25 \usepackage[utf8]{inputenc}             % multilanguage support\r
26 \usepackage[T1]{fontenc}\r
27 [@-- if ( length($watermark) ) {\r
28   $OUT .= '\r
29 \usepackage{background}\r
30 \backgroundsetup{\r
31   placement=center,\r
32   opacity=0.25,\r
33   color=black,\r
34   angle=0,\r
35   contents=' . $watermark . '\r
36 }';\r
37 }\r
38 '';\r
39 --@]\r
40 \r
41 \addtolength{\voffset}{-0.0cm}          % top margin to top of header\r
42 \addtolength{\hoffset}{-0.6cm}          % left margin on page\r
43 \addtolength{\topmargin}{[@-- defined($topmargin) ? $topmargin : '-1.00cm' --@]}\r
44 \setlength{\headheight}{2.0cm}          % height of header\r
45 \setlength{\headsep}{[@-- defined($headsep) ? $headsep : '1.0cm' --@]}\r
46 \setlength{\footskip}{1.0cm}            % bottom of footer from bottom of text\r
47 \r
48 %\addtolength{\textwidth}{2.1in}        % width of text\r
49 \setlength{\textwidth}{19.5cm}\r
50 \setlength{\textheight}{[@-- defined($textheight) ? $textheight : '19.5cm' --@]}\r
51 \setlength{\oddsidemargin}{-0.9cm}      % odd page left margin\r
52 \setlength{\evensidemargin}{-0.9cm}     % even page left margin\r
53 \r
54 \LTchunksize=40\r
55 \r
56 \renewcommand{\headrulewidth}{0pt}\r
57 \renewcommand{\footrulewidth}{1pt}\r
58 \r
59 \renewcommand{\footrule}{\r
60 [@--\r
61   $coupon ? '\ifthenelse{\equal{\thepage}{1}}' : '';\r
62 --@]\r
63   {\r
64   }\r
65   {\r
66     \vbox to 0pt{\rule{\headwidth}{\footrulewidth}\vss}\r
67   }\r
68 }\r
69 \r
70 \newcommand{\extracouponspace}{[@-- defined($extracouponspace) ? $extracouponspace : '2.7in' --@]}\r
71 \r
72 % Adjust the inset of the mailing address\r
73 \newcommand{\addressinset}[1][]{\hspace{1.0cm}}\r
74 \r
75 % Adjust the inset of the return address and logo\r
76 \newcommand{\returninset}[1][]{\hspace{-0.25cm}}\r
77 \r
78 % New command for address lines i.e. skip them if blank\r
79 \newcommand{\addressline}[1]{\ifthenelse{\equal{#1}{}}{}{#1\\}}\r
80 \r
81 % Inserts dollar symbol\r
82 \newcommand{\dollar}[1][]{\symbol{36}}\r
83 \r
84 % Remove plain style header/footer\r
85 \fancypagestyle{plain}{\r
86   \fancyhead{}\r
87 }\r
88 \fancyhf{}\r
89 \r
90 % Define fancy header/footer for first and subsequent pages\r
91 \fancyfoot[C]{\r
92   \ifthenelse{\equal{\thepage}{1}}\r
93   { % First page\r
94 [@--\r
95   if ($coupon) {\r
96     $OUT .= '\vspace{-\extracouponspace}';\r
97     $OUT .= '\rule[0.5em]{\textwidth}{\footrulewidth}\\\\';\r
98     $OUT .= $coupon;\r
99     $OUT .= '\vspace{'.\r
100       (defined($couponfootsep) ? $couponfootsep : '0.2in') .\r
101       '}';\r
102   }\r
103   '';\r
104 --@] [@-- $smallerfooter ? '\scriptsize{' : '\small{' --@]\r
105 [@-- $footer --@]\r
106     }[@-- $coupon ? '\vspace{\extracouponspace}' : '' --@]\r
107   }\r
108   { % ... pages\r
109     [@-- $smallerfooter ? '\scriptsize{' : '\small{' --@]\r
110 [@-- $smallfooter --@]\r
111     }\r
112   }\r
113 }\r
114 \r
115 \fancyfoot[R]{\r
116   \ifthenelse{\equal{\thepage}{1}}\r
117   { % First page\r
118   }\r
119   { % ... pages\r
120     \small{\thepage~[@-- emt('of') --@]~\pageref{LastPage}}\r
121   }\r
122 }\r
123 \r
124 \fancyhead[L]{\r
125   \ifthenelse{\equal{\thepage}{1}}\r
126   { % First page\r
127     \returninset\r
128     \makebox{\r
129       \begin{tabular}{ll}\r
130         \begin{minipage}[b]{5.5cm}\r
131 [@-- $returnaddress --@]\r
132         \end{minipage} &\r
133         \includegraphics{[@-- $logo_file --@]}\\\r
134       \end{tabular}\r
135     }\r
136   }\r
137   { % ... pages\r
138     %\includegraphics{[@-- $logo_file --@]}     % Uncomment if you want the logo on all pages.\r
139   }\r
140 }\r
141 \r
142 \fancyhead[R]{\r
143   \ifthenelse{\equal{\thepage}{1}}\r
144   { % First page\r
145     \begin{tabular}{ccc}\r
146     [@-- join(' & ', ( $no_date   ? '' : emt('Invoice date') ),\r
147                      ( $no_number ? '' : emt('Invoice #')    ),\r
148                      emt('Customer #')\r
149              )\r
150     --@]\\\r
151     \vspace{0.2cm}\r
152     \textbf{[@-- $date --@]} & \textbf{[@-- $invnum --@]} & \textbf{[@-- $custnum --@]} \\\hline\r
153     \rule{0pt}{5ex} &~~ \huge{\textsc{[@-- emt($notice_name) --@]}} & \\\r
154     \vspace{-0.2cm}\r
155      & & \\\hline\r
156     \end{tabular}\r
157   }\r
158   { % ... pages\r
159     \small{\r
160       \begin{tabular}{lll}\r
161       [@-- join(' & ', emt('Invoice date'), emt('Invoice #'), emt('Customer #') ) --@]\\\r
162       \textbf{[@-- $date --@]} & \textbf{[@-- $invnum --@]} & \textbf{[@-- $custnum --@]}\\\r
163       \end{tabular}\r
164     }\r
165   }\r
166 }\r
167 \r
168 \pagestyle{fancy}\r
169 \r
170 \r
171 %% Font options are:\r
172 %%      bch     Bitsream Charter\r
173 %%      put     Utopia\r
174 %%      phv     Adobe Helvetica\r
175 %%      pnc     New Century Schoolbook\r
176 %%      ptm     Times\r
177 %%      pcr     Courier\r
178 \r
179 \renewcommand{\familydefault}{phv}\r
180 \r
181 \r
182 % Commands for freeside table header...\r
183 \r
184 \newcommand{\FSdescriptionlength} { [@-- $unitprices ? '8.2cm' : '12.8cm' --@] }\r
185 \newcommand{\FSdescriptioncolumncount} { [@-- $unitprices ? '4' : '6' --@] }\r
186 \newcommand{\FSunitcolumns}{ [@-- \r
187   $unitprices\r
188   ? '\makebox[2.5cm][r]{\textbf{~~' . emt('Unit Price') . '}} &' .\r
189     '\makebox[1.4cm]{\textbf{~' . emt('Quantity') . '}} & ' \r
190   : '' --@] }\r
191 \r
192 \newcommand{\FShead}{\r
193   \hline\r
194   \rule{0pt}{2.5ex}\r
195   \makebox[1.4cm]{} &\r
196   \multicolumn{\FSdescriptioncolumncount}{l}{\r
197     \truncate{\FSdescriptionlength}{\textbf{[@-- emt('Description') --@]}}\r
198   } &\r
199   \FSunitcolumns\r
200   \makebox[1.6cm][r]{\textbf{[@-- emt('Amount') --@]}} \\\r
201   \hline\r
202 }\r
203 \r
204 \newcommand{\FSusagehead}{\r
205   \hline\r
206   \rule{0pt}{2.5ex}\r
207   \makebox[1.4cm]{} &\r
208   \multicolumn{4}{l}{\r
209     \truncate{\FSdescriptionlength}{\textbf{[@-- emt('Description') --@]}}\r
210   } &\r
211   \textbf{~~[@-- emt('Calls') --@]} &\r
212   \textbf{~~[@-- emt('Duration') --@]} &\r
213   \textbf{~~[@-- emt('Amount') --@]} \\\r
214   \hline\r
215 }\r
216 \r
217 % ...description...\r
218 \newcommand{\FSdesc}[5]{\r
219   \multicolumn{1}{c}{\rule{0pt}{2.5ex}\textbf{#1}} &\r
220   \multicolumn{[@-- $unitprices ? '4' : '6' --@]}{l}{\r
221     \truncate{\FSdescriptionlength}{\textbf{#2}}\r
222   } &\r
223 [@-- $unitprices ? '  \multicolumn{1}{r}{\textbf{#3}} &'."\n".\r
224                    '  \multicolumn{1}{r}{\textbf{#4}} &'."\n"\r
225                  : ''\r
226 --@]\r
227   \multicolumn{1}{r}{\textbf{#5}}\\\r
228 }\r
229 % ...extended description...\r
230 \newcommand{\FSextdesc}[1]{\r
231   \multicolumn{1}{l}{\rule{0pt}{1.0ex}} &\r
232   \multicolumn{6}{l}{\r
233     \truncate{12.8cm}{\small{~~~#1}}\r
234   } \\\r
235 }\r
236 % ...call detail (multiple columns already)...\r
237 \newcommand{\FScalldetail}[1]{\r
238   \multicolumn{1}{l}{\rule{0pt}{1.0ex}} &\r
239   ~~~#1\r
240   \\\r
241 }\r
242 }\r
243 % ...and total line items (which use the full 12.8cm length, ignoring\r
244 % unitprice/quantity\r
245 \newcommand{\FStotaldesc}[2]{\r
246   & \multicolumn{6}{l}{\r
247     \truncate{12.8cm}{#1}\r
248   } & #2\\\r
249 }\r
250 \r
251 % ...usage class summary\r
252 \newcommand{\FSusagedesc}[4]{\r
253   \multicolumn{1}{c}{\rule{0pt}{2.5ex}} &\r
254   \multicolumn{4}{l}{\textbf{#1}} &\r
255   \multicolumn{1}{r}{\textbf{#2}} &\r
256   \multicolumn{1}{r}{\textbf{#3}} &\r
257   \multicolumn{1}{r}{\textbf{#4}}\r
258   \\\r
259 }\r
260 \r
261 \begin{document}\r
262 %       Headers and footers defined for the first page\r
263 \addressinset \rule{0.5cm}{0cm} \r
264 \makebox{\r
265 \begin{minipage}[t]{7.0cm}\r
266 \vspace{[@-- defined($addresssep) ? $addresssep : '0.25cm' --@]}\r
267 \textbf{[@-- $payname --@]}\\\r
268 \addressline{[@-- $company --@]}\r
269 \addressline{[@-- $address1 --@]}\r
270 \addressline{[@-- $address2 --@]}\r
271 \addressline{[@-- $city --@], [@-- $state --@]~~[@-- $zip --@]}\r
272 \addressline{[@-- $country --@]}\r
273 \end{minipage}}\r
274 \hfill\r
275 \makebox{\r
276 \begin{minipage}[t]{6.4cm}\r
277 [@--\r
278   if ($ship_enable) {\r
279     $OUT .= '\textbf{' . emt('Service Address') . '}\\\\';\r
280     $OUT .= "\\addressline{$ship_company}";\r
281     $OUT .= "\\addressline{$ship_address1}";\r
282     $OUT .= "\\addressline{$ship_address2}";\r
283     $OUT .= "\\addressline{$ship_city, $ship_state~~$ship_zip}";\r
284     $OUT .= "\\addressline{$ship_country}";\r
285     $OUT .= '~\\\\';\r
286   }else{\r
287     $OUT .= '';\r
288   }\r
289 --@]\r
290 \begin{flushright}\r
291 [@-- $terms ? emt('Terms') . ': ' . emt($terms) : '' --@]\\\r
292 [@-- $po_line --@]\\\r
293 \end{flushright}\r
294 \end{minipage}}\r
295 \vspace{1.5cm}\r
296 %\r
297 [@-- $summary --@]\r
298 %\r
299 \section*{}\r
300 [@--\r
301   foreach my $section ( grep { !$summary || $_->{description} ne $finance_section } @sections ) {\r
302     if ($section->{'pretotal'} && !$summary) {\r
303       $OUT .= '\begin{flushright}';\r
304       $OUT .= '\large\textsc{'. $section->{'pretotal'}. '}\\\\';\r
305       $OUT .= '\\end{flushright}';\r
306     }\r
307     $OUT .= '\pagebreak' if $section->{'post_total'};\r
308     unless ($section->{'summarized'} ) {\r
309       $OUT .= '\captionsetup{singlelinecheck=false,justification=raggedright,font={Large,sc,bf}}';\r
310       $OUT .= '\ifthenelse{\equal{\thepage}{1}}{\setlength{\LTextracouponspace}{\extracouponspace}}{\setlength{\LTextracouponspace}{0pt}}'\r
311         if $coupon;\r
312       $OUT .= '\begin{longtable}{cllllllr}';\r
313       $OUT .= '\caption*{ ';\r
314       if ($section->{'location'}) {\r
315         $OUT .= $section->{'location'}{'label_prefix'}. ': '\r
316           if length($section->{'location'}{'label_prefix'});\r
317         $OUT .= $section->{'location'}{'address1'};\r
318         $OUT .= ', ' . $section->{'location'}{'address2'}\r
319           if length($section->{'location'}{'address2'});\r
320         $OUT .= ', ' .\r
321                 $section->{'location'}{'city'} . ', ' .\r
322                 $section->{'location'}{'state'} . '~' .\r
323                 $section->{'location'}{'zip'};\r
324       } elsif ( $section->{'description'} ) {\r
325         $OUT .= ($section->{'description'});\r
326       } else {\r
327         $OUT .= emt('Charges');\r
328       }\r
329       $OUT .= '}\\\\';\r
330       if ($section->{header_generator}) {\r
331         $OUT .= &{$section->{header_generator}}();\r
332       } elsif ( $section->{usage_section} ) {\r
333         $OUT .= '\FSusagehead';\r
334       } else {\r
335         $OUT .= '\FShead';\r
336       }\r
337       $OUT .= '\endfirsthead';\r
338       $OUT .= '\multicolumn{7}{r}{\rule{0pt}{2.5ex}'.emt('Continued from previous page').'}\\\\';\r
339       if ($section->{header_generator}) {\r
340         $OUT .= &{$section->{header_generator}}();\r
341       } elsif ( $section->{usage_section} ) {\r
342         $OUT .= '\FSusagehead';\r
343       } else {\r
344         $OUT .= '\FShead';\r
345       }\r
346       $OUT .= '\endhead';\r
347       $OUT .= '\multicolumn{7}{r}{\rule{0pt}{2.5ex}'.emt('Continued on next page...').'}\\\\';\r
348       $OUT .= '\endfoot';\r
349       $OUT .= '\hline';\r
350 \r
351       if (scalar(@sections) > 1 and !$section->{no_subtotal}) {\r
352         if ($section->{total_generator}) {\r
353           $OUT .= &{$section->{total_generator}}($section);\r
354         } else {\r
355           $OUT .= '\FStotaldesc{' . $section->{'description'} . ' Total}' .\r
356                   '{' . $section->{'subtotal'} . '}' . "\n";\r
357         }\r
358       }\r
359 \r
360       #if ($section == $sections[$#sections]) {\r
361         foreach my $line (grep {$_->{section}->{description} eq $section->{description}} @total_items) {\r
362           if ($section->{total_line_generator}) {\r
363             $OUT .= &{$section->{total_line_generator}}($line);\r
364           } else {\r
365             $OUT .= '\FStotaldesc{' . $line->{'total_item'} . '}' .\r
366                     '{' . $line->{'total_amount'} . '}' . "\n";\r
367           }\r
368         }\r
369       #}\r
370 \r
371       $OUT .= '\hline';\r
372       $OUT .= '\endlastfoot';\r
373 \r
374       my $lastref = 0;\r
375       foreach my $line (\r
376         grep { ( scalar( @sections ) > 1 \r
377                ? $section->{'description'} eq $_->{'section'}->{'description'}\r
378                : 1\r
379              ) }\r
380         @detail_items )\r
381       {\r
382         my $ext_description = $line->{'ext_description'};\r
383   \r
384         # Don't break-up small packages.\r
385         my $rowbreak = @$ext_description < 5 ? '*' : '';\r
386   \r
387         $OUT .= "\\hline\n" if (($line->{'ref'} || 0) ne $lastref);\r
388         if ($section->{description_generator}) {\r
389           $OUT .= &{$section->{description_generator}}($line);\r
390         } elsif ($section->{usage_section}) {\r
391           my $minutes = sprintf('%d', $line->{'duration'} / 60);\r
392           my $seconds = $line->{'duration'} % 60;\r
393           $OUT .= '\FSusagedesc\r
394             {' . $line->{'description'} . '}\r
395             {' . $line->{'quantity'} . '}\r
396             {' . $minutes . 'm ' . $seconds . 's' . '}\r
397             {' . $line->{'amount'} . '}';\r
398         } else {\r
399           $OUT .= '\FSdesc'.\r
400                   '{}'.\r
401                   '{' . $line->{'description'} . '}' ;\r
402           if ( $unitprices and length($line->{'unit_amount'}) ) {\r
403             # then show the unit amount and quantity\r
404             $OUT .= \r
405                 '{\\dollar' . $line->{'unit_amount'} . '}'.\r
406                 '{'         . $line->{'quantity'}    . '}';\r
407           } else {\r
408             # leave those columns blank\r
409             $OUT .= '{}{}';\r
410           }\r
411           $OUT .= '{\\dollar' . $line->{'amount'} . "}${rowbreak}\n";\r
412         }\r
413         $lastref = $line->{'ref'} || 0;\r
414 \r
415         foreach my $ext_desc (@$ext_description) {\r
416           if ($section->{extended_description_generator}) {\r
417             $OUT .= &{$section->{extended_description_generator}}($ext_desc);\r
418           } elsif ( $ext_desc !~ /[^\\]&/ ) {\r
419             $OUT .= '\FSextdesc{' . $ext_desc . "}$rowbreak\n";\r
420           } else { # call detail\r
421             $OUT .= '\FScalldetail{' . $ext_desc . "}$rowbreak\n";\r
422           }\r
423         }\r
424 \r
425       }\r
426 \r
427       $OUT .= '\end{longtable}';\r
428     }\r
429     if ($section->{'posttotal'}) {\r
430       $OUT .= '\begin{flushright}';\r
431       $OUT .= '\normalfont\large\bfseries\textsc{'. $section->{'posttotal'}. '}\\\\';\r
432       $OUT .= '\\end{flushright}';\r
433     }\r
434   }\r
435 \r
436 --@]\r
437 \vfill\r
438 \begin{minipage}[t]{\textwidth}\r
439   [@-- length($summary)\r
440          ? ''\r
441         : ( $smallernotes\r
442               ? '\scriptsize{ '.$notes.' }'\r
443               : $notes\r
444           )\r
445   --@]\r
446   [@-- $coupon ? '\ifthenelse{\equal{\thepage}{1}}{\rule{0pt}{\extracouponspace}}{}' : '' --@]\r
447 \end{minipage}\r
448 \end{document}\r