26

Some invoices need print a large list of items. In this case, and in my country, invoices must print the subtotal of the previous page for each break page, and add to the last subtotal the accumulated of amount of each items printed in the page.

For example, imagine the following table broken in two pages.

\begin{longtable}{cc}
Item 1 & 100 \$ \\
Item 2 & 100 \$ \\
Item 3 & 100 \$ \\
Item 4 & 100 \$ \\
Item 5 & 100 \$ \\
\end{longtable}

The invoice must show for each page with the subtotal before and the sum of amounts later:

Page 1:

Item 1 & 100 \$ \\
Item 2 & 100 \$ \\
Item 3 & 100 \$ \\
Subtotal: 300 \$.

Page 2:

Transport: 300 \$.
Item 4 & 100 \$ \\
Item 5 & 100 \$ \\
Transport + Subtotal: 500 \$.

I tried to accumulate the amount using fp in each line of the table, but it doesnt work. Print 0 for transport and transport + subtotal.

Example in ShareLatex with the problem

Thanks for any ideas!

  • I've been asking this question for years (http://tex.stackexchange.com/a/128541/4736) and always got the answer that subtotals are really difficult. Probably one had to write a new package Lua-Longtable or LaTeX3-Longtable. One thing is to calculate the subtotal after inserting the second last line of the tabular on the page, another thing is to catch errors, e.g. letters in the column. I'd be very interested in such a package, but that is a challenge! – Keks Dose Jan 31 '14 at 16:28
  • 1
    What are the $ characters meant to do? Is this a typo for &? Or...? – cfr Jan 31 '14 at 23:59
  • @KeksDose Well, you can try. However, I think it's a bit more difficult than how it looks :) – yo' Feb 02 '14 at 17:54
  • Starting point, maybe: http://tex.stackexchange.com/questions/3851/how-can-i-automatically-calculate-sums-in-a-latex-table http://mirrors.ctan.org/macros/latex/contrib/spreadtab/spreadtab_doc_en.pdf – Attila Kosa Jan 31 '14 at 20:03
  • @cfr as they're \$ surely they're meant to produce a literal $ sign in the output - some currencies use that symbol at the end of the amount, unlike USD. – Chris H Apr 24 '14 at 10:04
  • @ChrisH You are surely right now the question has been edited. When I wrote that comment, the $ signs were not preceded by backslashes ;). – cfr Apr 24 '14 at 13:19
  • @cfr - I wondered what had happened, but didn't think to check the edit history. – Chris H Apr 24 '14 at 13:26

2 Answers2

15

This has a few limitations but it re-calculates the foot box each page...

enter image description here

\documentclass{article}

\usepackage{longtable}

\usepackage[textheight=9\baselineskip]{geometry}
\newcount\zzz
\def\foo{}
\def\zz#1{#1%
\global\advance\zzz#1\relax
\marks1 {\the\zzz}%
}
\marks1{0}

\makeatletter
\def\LT@output{%
  \ifnum\outputpenalty <-\@Mi
    \ifnum\outputpenalty > -\LT@end@pen
      \LT@err{floats and marginpars not allowed in a longtable}\@ehc
    \else
\LT@bchunk
page total: & 
\edef\tmp{\topmarks1 }%
\the\numexpr\botmarks1  \ifx\tmp\@empty\else - \topmarks1 \fi\relax\\
total:&\botmarks1
\LT@echunk
\setbox\LT@foot\box\z@
\LT@get@widths
      \setbox\z@\vbox{\unvbox\@cclv}%
      \ifdim \ht\LT@lastfoot>\ht\LT@foot
        \dimen@\pagegoal
        \advance\dimen@-\ht\LT@lastfoot
        \ifdim\dimen@<\ht\z@
          \setbox\@cclv\vbox{\unvbox\z@\copy\LT@foot\vss}%
          \@makecol
          \@outputpage
          \setbox\z@\vbox{\box\LT@head}%
        \fi
      \fi
      \global\@colroom\@colht
      \global\vsize\@colht
      %\vbox
        {\unvbox\z@\nobreak\box\ifvoid\LT@lastfoot\LT@foot\else\LT@lastfoot\fi}%
    \fi
  \else
\global\advance\c@LT@chunks\@M
\LT@bchunk
\edef\tmp{\topmarks1 }%
page total: &
\edef\tmp{\topmarks1 }%
\the\numexpr\botmarks1 \ifx\tmp\@empty\else - \topmarks1 \fi\relax\\
running total:&\botmarks1
\LT@echunk
\setbox\LT@foot\box\z@
\LT@get@widths
\global\advance\c@LT@chunks-\@M
    \setbox\@cclv\vbox{\unvbox\@cclv\copy\LT@foot\vss}%
    \@makecol
    \@outputpage
      \global\vsize\@colroom
    \copy\LT@head\nobreak
  \fi}
\makeatother

\begin{document}

\begin{longtable}{l|l}
xxxxxx&yyyyyy\\
xxxxzzzzzzzzzzzzzxx&yyyyyyy\endfoot% not typeste but needs to be bigger than the foot that is used.
a & \zz{1}\\
b & \zz{2}\\
c & \zz{5}\\
d & \zz{7}\\
e & \zz{1}\\
f & \zz{9}\\
g & \zz{2}\\
h & \zz{3}\\
i & \zz{1}\\
j & \zz{6}\\
k & \zz{8}\\
l & \zz{3}\\
m & \zz{2}\\
n & \zz{1}\\
o & \zz{4}\\
p & \zz{8}\\
q & \zz{3}
\end{longtable}

\end{document}
David Carlisle
  • 757,742
  • 1
    Well, there's the request for having the transport in the head, too. Then, the bounty is yours (and you can catch up with egreg!) – yo' Feb 02 '14 at 17:59
  • @DavidCarlisle, thanks a lot. Your solution is really elegant. I had to write a package for the Argentina invoices, and it don't use longtable because I didn't know I could overwrite the longtable's macros. About the counters to compute subtotals, it's only for integers numbers. Can Lengths be used for compute and show real numbers? – Cristian S. Rocha Feb 16 '14 at 14:58
  • 1
    @CristianS.Rocha yes yu could use lengths, or one of the floating point arithmentic packages. – David Carlisle Feb 16 '14 at 16:30
  • Thanks for this precious snippet. I'm trying to adapt it for a table with more columns and I'm experiencing a weird behavior on the 2nd or 3rd page. I have put a MWE here. Mind your having a look? I can also open a new question if this is better, but it may improve the snippet here. – vanto Dec 14 '17 at 10:09
  • 1
    Is it possible to change the head too with the running total from previous page? – Peter Miehle Jun 18 '18 at 07:43
3

On the trace of what David Carlisle provided, here's the same example but with a second column using floating point numbers (I used lengths for that):

\documentclass{article}

\usepackage{longtable}

\usepackage[textheight=9\baselineskip]{geometry}
\newcount\zzz
\def\foo{}
\def\zz#1{#1%
\global\advance\zzz#1\relax
\marks1 {\the\zzz}%
}
\marks1{0}

\newlength\yyy
\setlength{\yyy}{0pt}
\def\yy#1{#1
\global\addtolength{\yyy}{#1pt}\relax
\marks2 {\the\yyy}
}
\marks2{0}

\makeatletter
    \def\LT@output{%
            \global\advance\c@LT@chunks\@M
            \LT@bchunk
            \edef\tmp{\topmarks1 }%
            page total: &
            \edef\tmp{\topmarks1 }%
            \the\numexpr\botmarks1 \ifx\tmp\@empty\else - \topmarks1 \fi\relax&
            \edef\tmp{\topmarks2 }%
            \strip@pt\dimexpr\botmarks2 \ifx\tmp\@empty\else - \topmarks2 \fi\relax\\
            running total:&\botmarks1&\strip@pt\dimexpr\botmarks2
            \LT@echunk
            \setbox\LT@foot\box\z@
            \LT@get@widths
            \global\advance\c@LT@chunks-\@M
                \setbox\@cclv\vbox{\unvbox\@cclv\copy\LT@foot\vss}%
                \@makecol
                \@outputpage
                \global\vsize\@colroom
             \copy\LT@head\nobreak
        }
\makeatother

\begin{document}

\begin{longtable}{l|l|l}
xxxxxx&yyyyyy&yyyyyy\\
xxxxzzzzzzzzzzzzzxx&yyyyyyy&yyyyyy\endfoot% not typeste but needs to be bigger than the foot that is used.
a & \zz{1} & \yy{5.3}\\
b & \zz{2} & \yy{6}\\
c & \zz{5} & \yy{7.1}\\
d & \zz{7} & \yy{4.5}\\
e & \zz{1} & \yy{9.15}\\
f & \zz{9} & \yy{15}\\
g & \zz{2} & \yy{2}\\
h & \zz{3} & \yy{8}\\
i & \zz{1} & \yy{1}\\
j & \zz{6} & \yy{6}\\
k & \zz{8} & \yy{8}\\
l & \zz{3} & \yy{3.2}\\
m & \zz{2} & \yy{2.67}\\
n & \zz{1} & \yy{1.1}\\
o & \zz{4} & \yy{4}\\
p & \zz{8} & \yy{8.05}\\
q & \zz{3} & \yy{3}
\end{longtable}

\end{document}
risoldi
  • 269
  • 2
  • 6