About
Shop
LaTeX
Software
Books
Gallery
News
Contact
Blog
Settings
Latest news 2019-11-04: The giveaway of two signed copies of “Quack, quack, quack. Give my hat back!” has closed and the winning entrants have been selected. Thank you to everyone who took part.


4.3 Building Your Own Invoice using longtable and datatool

It may be that the layouts produced by the available classes or packages don't suit your requirements or perhaps you want to use isodoc but the \itable layout doesn't have enough columns for your needs. Since invoices typically involve aligning data in rows and columns, you can just use the tabular environment described in Volume 1 if it can fit within a single page. If the tabulated data exceeds a page, then you need to use a multi-paged tabular-like environment, such as the longtable environment provided by the longtable package [11].

The syntax for longtable is similar to tabular:

\begin{longtable}[horizontal alignment]{column specs}

Unlike tabular the optional argument specifies the horizontal alignment instead of the vertical alignment since longtable isn't intended for in-line positioning. The horizontal alignment may be one of l (left), c (centre) or r (right). The default is c.

The ⟨column specs⟩ are the same as for tabular and the rows and columns are separated in the same way using \\ and &. For example:

\begin{longtable}{lr}
Video & 8.99\\
CD & 9.11\\
DVD & 15.00\\
Total & 33.10
\end{longtable}

produces:

The resulting output is a table with 2 columns (the first left justified and the second right justified) and 4 rows:

Video 8.99
CD 9.11
DVD 15.00
Total 33.10
End of Image.


However, unlike tabular, you can also specify a caption as well as header and footer information. This is done at the start of the longtable environment:

\begin{longtable}{column specs}
\caption{first page caption}
\label{table label}\\
code for first page header row
\endfirsthead
\caption{continuation caption}
code for the header row
\endhead
code for last page footer row
\endlastfoot
code for the footer row
\endfoot
contents
\end{longtable}
You may omit any of the header, footer or caption information. The document will need at least two LaTeX runs to ensure the longtable environment correctly aligns the columns. The header and footer code will typically need to include & and \\ as per the column alignment specifications. You can use the starred version of \caption to suppress the numbering for example:

\caption*{Products (continued)}

Example 24. Multi-Paged Tabulated Material

Recall from Example 4 that datatool's \DTLdisplaylongdb command could be used to display the contents of a large database over multiple pages. This command internally uses the longtable environment. We could instead explicitly use that environment to display the data from the sample country-codes.csv file or countries SQL table:

\begin{longtable}{cl}
 \bfseries Country Code & \bfseries Country Name\\
 \endhead
 \multicolumn{2}{r}{\emph{Continued on next page}}
 \endfoot
 \endlastfoot
 \DTLforeach*{countries}{\Code=code,\Name=name}{\Code & \Name\\}%
\end{longtable}

This sets the same header for all the pages and sets the footer to the text “Continued on next page”. Since this isn't required for the final page, the last footer is set to empty. This produces a seven page table (without a caption). The beginning of the table looks like:

The resulting output is a table with 2 columns (the first centred and the second left justified):

Country Code Country Name
ad Andorra
ae United Arab Emirates
af Afghanistan
ag Antigua and Barbuda
ai Anguilla
End of Image.


The end of the first page looks like:

The resulting output is a table with 2 columns (the first centred and the second left justified):

bw Botswana
by Belarus
bz Belize
ca Canada
Continued on next page
End of Image.


The final page of the table is shown in Figure 4.3. You can download or view this example document.

Figure 4.3: Final Page of longtable Displaying Countries
The resulting output is a table with 2 columns (the first centred and the second left justified):

Country Code Country Name
vg Virgin Islands, British
vi Virgin Islands, USA
vn Viet Nam
vu Vanuatu
wf Wallis and Futuna
ws Samoa
ye Yemen
yt Mayotte
za South Africa
zm Zambia
zw Zimbabwe

End of Image.


Remember that you can use the booktabs package [24] if you want horizontal rules and you can use \DTLiflastrow to suppress the final \\ which would otherwise create unnecessary extra vertical space at the end of the table. For example:

\begin{longtable}{cl}
 \bfseries Country Code & \bfseries Country Name\\
 \midrule
 \endhead
 \bottomrule
 \multicolumn{2}{r}{\emph{Continued on next page}}
 \endfoot
 \bottomrule
 \endlastfoot
 \DTLforeach*{countries}{\Code=code,\Name=name}%
 {\Code & \Name\DTLiflastrow{}{\\}}%
\end{longtable}

Alternatively you can use \DTLiffirstrow:

\begin{longtable}{cl}
 \bfseries Country Code & \bfseries Country Name\\
 \midrule
 \endhead
 \bottomrule
 \multicolumn{2}{r}{\emph{Continued on next page}}
 \endfoot
 \bottomrule
 \endlastfoot
 \DTLforeach*{countries}{\Code=code,\Name=name}%
 {\DTLiffirstrow{}{\\}\Code & \Name}%
\end{longtable}

As with tabular, the column specifiers may include p{width} for a column with multilined cells. Recall from Volume 1 that the array package [58] can be used to insert a declaration before each cell in a given column via:

>{declaration}

directly before the column specifier. This means that if you have a column for the description of an invoiced item, you can have ragged line wrapping, which looks better than the default fully-justified paragraphs in a narrow column context.

Example

Suppose my invoice needs four columns: the item description, the quantity ordered, the unit price and the quantity times price. The last three columns can just use the r specifier, but the first column may need a paragraph cell in the event of a long description:

\begin{longtable}{>{\raggedright}p{0.3\linewidth}rrr}
\bfseries Item & \bfseries Quantity &
\bfseries Unit Price (\pounds) &
\bfseries Price (\pounds)\\
\midrule
\endhead
``\,`Duck and Goose': an allegory for modern times?'' (hardback) &
1 & 59.99 & 59.99\\
``My Friend is a Duck'' (paperback) & 20 & 14.99 & 299.80\\
``Annotated Notes on the `Duck and Goose' Chronicles'' (ebook) &
1 & 8.99 & 8.99\\
``The Adventures of Duck and Goose'' (hardback) & 1 & 18.99 & 18.99\\
\midrule
\multicolumn{3}{r}{\bfseries Sub-Total} & 368.78\\
\multicolumn{3}{r}{\bfseries Postage and Packaging} & 20.00\\
\multicolumn{3}{r}{\bfseries Promotional Discount} & $-2.50$\\
\midrule
\multicolumn{3}{r}{\bfseries Total} & 386.28
\end{longtable}

This produces:

The resulting output is a table with 4 columns (the first left justified and the others right justified):

Item Quantity Unit Price (£) Price (£)
“ ‘Duck and Goose’: and allegory for modern times?” (hardback) 1 59.99 59.99
“My Friend is a Duck” (paperback) 20 14.99 299.80
“Annotated Notes on the ‘Duck and Goose’ Chronicles” (hardback) 1 8.99 8.99
“The Adventures of Duck and Goose” (hardback) 1 18.99 18.99
Sub-Total 387.77
Postage and Packaging 20.00
Promotional Discount -2.50
Total 405.27

End of Image.


Exercise 14. Custom Invoice

Adapt Exercise 12 so that it uses longtable instead of \itable, and make it have separate columns for the quantity and unit price (as in the example above). In addition, let's now suppose the book prices exclude VAT. The physical books are zero-rated, but the ebooks are standard-rated at 20%. Add an extra column that indicates the VAT rating and add a row for the VAT after the subtotal. You can download or view a solution.

For the More Adventurous

As with the more adventurous part of Exercise 12, fetch the information from the sample CSV files or SQL database. You can download or view a solution for the CSV files or download or view a solution for the SQL data.


This book is also available as A4 PDF or 12.8cm x 9.6cm PDF or paperback (ISBN 978-1-909440-07-4).

© 2015 Dickimaw Books. "Dickimaw", "Dickimaw Books" and the Dickimaw parrot logo are trademarks. The Dickimaw parrot was painted by Magdalene Pritchett.

Terms of Use Privacy Policy Cookies Site Map FAQs