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