% \iffalse meta-comment
%
% File: invoice2.dtx Copyright (C) 2017-2018 Simon Dierl
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see .
%
% \fi
%
% \iffalse
%<*driver>
\documentclass[full,lm-default]{l3doc}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage[USenglish]{babel}
\usepackage{csquotes}
\usepackage[useregional,showdow]{datetime2}
\usepackage{enumitem}
\usepackage{eurosym}
\usepackage{invoice2}
\hypersetup{hidelinks}
\begin{document}
\DocInput{\jobname.dtx}
\end{document}
%
% \fi
%
% \title{The \pkg{invoice2} package\\
% Intelligent invoices with \LaTeX{}3}
%
% \author{Simon Dierl
% \texttt{\href{mailto:simon.dierl@cs.tu-dortmund.de}
% {}}\\[.25\baselineskip]
% \url{https://github.com/no-preserve-root/invoice2}}
%
% \date{Version 1.2\\[.25\baselineskip]\DTMDate{2018-01-15}}
%
% \maketitle
%
% \begin{documentation}
%
% While there exists a vast amount of templates, unpublished packages and code
% snippets designed for creating invoices, the only solution available in the
% CTAN is the \pkg{invoice}\footnote{\url{https://www.ctan.org/pkg/invoice}}
% package, which is not actively maintained and lacks
% e.\,g.~internationalization support while requiring use of a project
% structure that does not fit many use cases.
%
% Thus, this package aims to reimplement the functionality provided by
% \pkg{invoice} using \LaTeX3, while using the print-friendly layout provided
% by the \pkg{booktabs}\footnote{\url{https://www.ctan.org/pkg/booktabs}}
% package.
%
% \tableofcontents
%
% \part{User documentation}
%
% \section{Package Configuration}
%
% \pkg{invoice2} offers extensive options for customization. Most of these
% options are not likely to change in the middle of a document; these shold be
% passed as package options. However, for maximum flexibility, the global
% options can be changed at run time or overridden per \cmd{invoice}
% environment.
%
% The options supported by this package are:
% \begin{description}
% \item[vat] Controls the global default for VAT. VAT can be overridden per
% invoice item and is either automatically added or subtracted (see the
% next parameter for details). This is given as a floating point number,
% e.\,g.~.19 for 19\,\%. Default is 0\,\%.
% \item[included-vat] Controls if prices are provided with VAT included or
% excluded. If VAT is included, all prices are gross prices, the VAT is
% subtracted to show the net price. If VAT is excluded, all prices are
% net prices, the VAT is added to show the gross price. Default is
% excluded VAT.
% \item[currency-symbol] The currency symbol to use, e.g. \euro{}.
% Default is \$.
% \item[currency-fraction-digits] The fractional digits to use for the
% currency. For almost all currencies, this is two (100 of the smaller
% unit make 1 of the larger). Default is 2.
% \item[currency-in-header] Controls if the currency symbol should be
% printed in the invoice header instead of printing it after each amount.
% Default is printing after each amount.
% \item[colorize] Enables colorization. While the typographical results may
% be mixed, colorization can help read very long invoices. Default is
% off.
% \item[odd-color] The color to use for odd invoice rows, if colorization is
% enabled. The color must be understood by \pkg{xcolor}. Default is
% white.
% \item[even-color] The color to use for even invoice rows, if colorization
% is enabled. The color must be understood by \pkg{xcolor}. Default is
% light grey (lightgray).
% \item[title-color] The color to use for the title row, if colorization is
% enabled. The color must be understood by \pkg{xcolor}. Default is
% white.
% \item[total-color] The color to use for total rows, if colorization is
% enabled. The color must be understood by \pkg{xcolor}. Default is
% white.
%\end{description}
%
% \section{Localization}
%
% Internationalization for this package is provided by the
% \pkg{translations}\footnote{\url{https://www.ctan.org/pkg/translations}}
% package. \pkg{translations} uses a key-to-translation mapping that can be
% overridden by the user. See the package documentation for further information.
%
% At the moment, localizations for english, german and swiss german are
% provided. See the documentation for the \pkg{translations} package for adding
% new localizations. Please consider contributing your translations to this
% project.
%
% The following keys are defined:
% \begin{description}
% \item[invoice2-thousands-sep] The separator between thousands, e.\,g. the
% space in 1\,000. Default is a small space.
% \item[invoice2-decimal-point] The separator between whole and
% fractional parts, e.\,g.~the dot in 40.00. Default is a dot.
% \item[invoice2-amount] The \enquote{Amount} column title.
% \item[invoice2-item] The \enquote{Item} column title.
% \item[invoice2-vat] The \enquote{VAT} column title.
% \item[invoice2-unit-price] The \enquote{Unit Price} column title.
% \item[invoice2-price] The \enquote{Price} column title.
% \item[invoice2-net-total] The \enquote{Net Total} row label.
% \item[invoice2-vat-total] The \enquote{VAT} row label.
% \item[invoice2-gross-total] The \enquote{Gross Total} row label.
%\end{description}
%
% \begin{function}{\invoiceoptions}
% \begin{syntax}
% \cs{invoiceoptions} \marg{key=value…}
% \end{syntax}
% All of the package options can be changed in the document by using this
% command. The syntax is identical to the package options.
% \end{function}
%
% \section{Typesetting invoices}
%
% An invoice is typeset as a table having between two and five columns. Each row
% will correspond to an item in the invoice. A row \emph{always} has an item
% name and a price. If \emph{any} item in the invoice hat a VAT that is not
% 0\,\%, \emph{every} row will list its VAT. Also, if \emph{any} item has an
% amount that is not one, \emph{every} row will list both price per unit and
% the amount.
%
% If an item hat non-zero VAT, the net and gross totals will also differ. In
% this case, the package will compute the net total, the total VAT and the
% gross total and denote them below the invoice. If all items have 0\,\%-VAT,
% only a gross total will be given.
%
% \begin{function}{\begin{invoice}, \end{invoice}}
% \begin{syntax}
% \cs{begin} \oarg{key=value…} \{invoice\}
% \cs{end} \{invoice\}
% \end{syntax}
% Invoices are enclosed in \cmd{invoice} environments. These environments can
% not be nested. Each environment can override the package settings by means of
% its optional arguments. The overridden arguments only apply to the current
% invoice.
%
% Inside the environment, \emph{only} \cmd{\invoiceitem} and
% \cmd{\invoicesingleitem} commands may be safely used.
% \end{function}
%
% \begin{function}{\invoiceitem, \invoicesingleitem}
% \begin{syntax}
% \cs{invoiceitem} \oarg{VAT} \marg{amount} \marg{item name} \marg{unit price}
% \cs{invoicesingleitem} \oarg{VAT} \marg{item name} \marg{unit price}
% \end{syntax}
% These commands add an item to the current invoice. The VAT argument is
% optional, if not given, VAT will default to the value set in the
% configuration. For singular items, the second form can be used to imply an
% amount of 1.
%
% VAT must be given as a floating point value (see the configuration parameter
% list for details). The amount and the unit price can be an integer or a
% floating point number. Do \emph{not} add a currency symbol or formatting to
% the unit price.
% \end{function}
%
% \section{Examples}
%
% Let us begin with a simple invoice with single items and no VAT. The invoice
% will only have two columns and a gross total. We do, however, change the
% currency symbol to \euro{} (provided by the \pkg{eurosym} package). Since we
% only have single copies, we will use the \cmd{\invoicesingleitem} command.
%
% \begin{verbatim}
% \usepackage{eurosym}
% \begin{invoice}[currency-symbol={\euro{}}]
% \invoicesingleitem{Ignition!}{4087.99}
% \invoicesingleitem{The Art of Computer Programming 1--4}{162.99}
% \invoicesingleitem{The TeXbook}{55.69}
% \end{invoice}
% \end{verbatim}
% \begin{invoice}[currency-symbol={\euro{}}]
% \invoicesingleitem{Ignition!}{4087.99}
% \invoicesingleitem{The Art of Computer Programming 1--4}{162.99}
% \invoicesingleitem{The TeXbook}{55.69}
% \end{invoice}
%
% For some currencies, the symbol ist fairly long. In this case, it is advisable
% to move the currency symbol to the invoice header.
%
% \begin{verbatim}
% \begin{invoice}[currency-symbol={CHF}, currency-in-header]
% \invoicesingleitem{Ignition!}{4087.99}
% \invoicesingleitem{The Art of Computer Programming 1--4}{162.99}
% \invoicesingleitem{The TeXbook}{55.69}
% \end{invoice}
% \end{verbatim}
% \begin{invoice}[currency-symbol={CHF}, currency-in-header]
% \invoicesingleitem{Ignition!}{4087.99}
% \invoicesingleitem{The Art of Computer Programming 1--4}{162.99}
% \invoicesingleitem{The TeXbook}{55.69}
% \end{invoice}
%
% Now, let us apply a VAT of 9\,\%. This will show the VAT column, the item
% price column and the extended total.
%
% \begin{verbatim}
% \usepackage{eurosym}
% \invoiceoptions{vat=.09}
% \begin{invoice}[currency-symbol={\euro{}}]
% \invoicesingleitem{Ignition!}{4087.99}
% \invoicesingleitem{The Art of Computer Programming 1--4}{162.99}
% \invoicesingleitem{The TeXbook}{55.69}
% \end{invoice}
% \end{verbatim}
% \invoiceoptions{vat=.09}
% \begin{invoice}[currency-symbol={\euro{}}]
% \invoicesingleitem{Ignition!}{4087.99}
% \invoicesingleitem{The Art of Computer Programming 1--4}{162.99}
% \invoicesingleitem{The TeXbook}{55.69}
% \end{invoice}
% \invoiceoptions{vat=.0}
%
% Note that if we specify included VAT in the above example, the output is
% different. Additionally, we specify our options as environment options.
%
% \begin{verbatim}
% \usepackage{eurosym}
% \begin{invoice}[vat=.09, included-vat=true, currency-symbol={\euro{}}]
% \invoicesingleitem{Ignition!}{4087.99}
% \invoicesingleitem{The Art of Computer Programming 1--4}{162.99}
% \invoicesingleitem{The TeXbook}{55.69}
% \end{invoice}
% \end{verbatim}
% \begin{invoice}[vat=.09, included-vat=true, currency-symbol={\euro{}}]
% \invoicesingleitem{Ignition!}{4087.99}
% \invoicesingleitem{The Art of Computer Programming 1--4}{162.99}
% \invoicesingleitem{The TeXbook}{55.69}
% \end{invoice}
%
% A more complex example involves amounts and a VAT. We keep the 9\,\% VAT for
% our books, buy duplicate editions of The Art of Computer Programming 1 and 2
% (simulated by buying 1.5 copies) and stock up on more copies of the
% TeXbook. This will enable all columns and an extended total.
%
% \begin{verbatim}
% \usepackage{eurosym}
% \invoiceoptions{vat=.09}
% \begin{invoice}[currency-symbol={\euro{}}]
% \invoicesingleitem{Ignition!}{4087.99}
% \invoiceitem{1.5}{The Art of Computer Programming 1--4}{162.99}
% \invoiceitem{20}{The TeXbook}{55.69}
% \end{invoice}
% \end{verbatim}
% \invoiceoptions{vat=.09}
% \begin{invoice}[currency-symbol={\euro{}}]
% \invoicesingleitem{Ignition!}{4087.99}
% \invoiceitem{1.5}{The Art of Computer Programming 1--4}{162.99}
% \invoiceitem{20}{The TeXbook}{55.69}
% \end{invoice}
% \invoiceoptions{vat=0}
%
% Finally, let us toy with colorization. We wisely deceide to leave most
% parts of the invoice white and only apply an extemely light grey to the even
% rows.
%
% \begin{verbatim}
% \usepackage{eurosym}
% \begin{invoice}[currency-symbol={\euro{}}, colorize,
% even-color={lightgray!50}]
% \invoicesingleitem{Ignition!}{4087.99}
% \invoicesingleitem{The Art of Computer Programming 1--4}{162.99}
% \invoicesingleitem{The TeXbook}{55.69}
% \end{invoice}
% \end{verbatim}
% \begin{invoice}[currency-symbol={\euro{}}, colorize,
% even-color={lightgray!50}]
% \invoicesingleitem{Ignition!}{4087.99}
% \invoicesingleitem{The Art of Computer Programming 1--4}{162.99}
% \invoicesingleitem{The TeXbook}{55.69}
% \end{invoice}
%
% \section{Version History}
%
% \subsection{Version 1.2}
% \changes{1.2}{2018/01/15}{Bugfix release}
% \begin{itemize}[nosep]
% \item Fix option loading for the \pkg{xcolor} package. Thanks to Alfred
% H.\ Gitter for reporting.
% \item Corrected german translation of ``VAT'' to ``USt''. Thanks to Alfred
% H.\ Gitter for reporting.
% \item Clarified that \pkg{eurosym} is required to use the \cmd{euro}
% symbol. Thanks to Alfred H.\ Gitter for the suggestion.
% \item Split the \texttt{README.md} into a Github version and one for CTAN.
% \item Add support for Swiss German. Thanks to \texttt{@foreachthing} for
% the translation.
% \item Permit moving the currency symbol to the header. Thanks to
% \texttt{@foreachthing} for the report.
% \end{itemize}
%
% \subsection{Version 1.1}
% \changes{1.1}{2017/08/16}{Bugfix release}
% \begin{itemize}[nosep]
% \item Spelling fix in \texttt{README.md}. Thanks to Ina Dau for noticing.
% \item Clean up unused \texttt{README} generation in the \texttt{.ins} file.
% \item Report in with the correct motto.
% \item Support non-integer amounts. Thanks to Gijs Hillenius for the
% suggestion.
% \item Print the unit price column if an item has either VAT or amount
% $\neq 1$. Thanks to Gijs Hillenius for the suggestion.
% \end{itemize}
%
% \subsection{Version 1.0}
% \changes{1.0}{2017/07/15}{First public release}
% \begin{itemize}[nosep]
% \item First public release.
% \item Support configuration via package options, \cmd{\invoiceoptions}
% command and environment options.
% \item Localization via \pkg{translations}.
% \end{itemize}
%
% \section{License}
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see \url{http://www.gnu.org/licenses/}.
%
% \end{documentation}
%
% \begin{implementation}
%
% \part{\pkg{invoice2} implementation}
%
% \begin{macrocode}
%<*package>
%<@@=invoicetwo>
% \end{macrocode}
%
% \section{Setup and Initialization}
%
% \begin{macrocode}
\RequirePackage{booktabs}
\RequirePackage{expl3}
\RequirePackage{l3keys2e}
\RequirePackage{longtable}
\RequirePackage{siunitx}
\RequirePackage{translations}
\PassOptionsToPackage{table}{xcolor}
\RequirePackage{xcolor}
\RequirePackage{xparse}
\ProvidesExplPackage{invoice2}{2018/01/15}{1.2}
{Intelligent invoices with LaTeX3}
% \end{macrocode}
%
% Now, load our dictionary files and set fallback translations. We emit the
% dictionaries in section \ref{sec:dictionaries}.
%
% \begin{macrocode}
\LoadDictionaryFor{english}{invoice2}
\LoadDictionaryFor{german}{invoice2}
\LoadDictionaryFor{swissgerman}{invoice2}
\DeclareTranslationFallback{invoice2-thousands-sep}{\,}
\DeclareTranslationFallback{invoice2-decimal-point}{.}
\DeclareTranslationFallback{invoice2-amount}{Amount}
\DeclareTranslationFallback{invoice2-item}{Item}
\DeclareTranslationFallback{invoice2-vat}{VAT}
\DeclareTranslationFallback{invoice2-unit-price}{Unit~Price}
\DeclareTranslationFallback{invoice2-price}{Price}
\DeclareTranslationFallback{invoice2-net-total}{Net~Total}
\DeclareTranslationFallback{invoice2-vat-total}{VAT}
\DeclareTranslationFallback{invoice2-gross-total}{Gross~Total}
% \end{macrocode}
%
% \section{Variables and Constants}
%
% All variables that control invoice typesetting can be set on
% \begin{enumerate}[noitemsep, label=\alph*)]
% \item the package level, as a package option
% \item the package level, using the \cmd{invoiceoptions} command
% \item per \cmd{invoice} environment, via the same syntax
% \item per invoice line, for some options (e.\,g.~VAT).
% \end{enumerate}
%
% \subsection{VAT Computation}
%
% \begin{variable}{\l_@@_vat_fp}
% The default value for VAT. If an invoice has only zero VAT for all entries,
% no VAT is added and the column is not rendered. VAT can be set per line.
%
% \begin{macrocode}
\fp_new:N \l_@@_vat_fp
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_included_vat_bool}
% Controls if VAT is already included into the given prices. If true, the
% total will compute the net total and display it. If false, the total will
% compute the gross total. If the VAT is zero, this does nothing. We will render
% a gross total only.
%
% \begin{macrocode}
\bool_new:N \l_@@_included_vat_bool
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_currency_symbol_tl}
% The currency symbol to use.
%
% \subsection{Price Typesetting}
%
% \begin{macrocode}
\tl_new:N \l_@@_currency_symbol_tl
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_currency_fraction_digits_int}
% The number of fractional digits for the currency. Contrary to popular opinion,
% this does not always equal two.
%
% \begin{macrocode}
\int_new:N \l_@@_currency_fraction_digits_int
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_currency_in_header_bool}
% Controls if the invoice currency symbol should be moved intro the table
% header (``Unit Price (\$)'') instead of printing it after each amount
% (``123.45\ \$''). Can save space for long currencies.
%
% \begin{macrocode}
\bool_new:N \l_@@_currency_in_header_bool
% \end{macrocode}
% \end{variable}
%
% \subsection{Colorization}
%
% \begin{variable}{\l_@@_colorize_bool}
% Controls if the invoice should be colorized at all. We only support
% alternating colorization for even and odd lines and a special color for the
% total line.
%
% \begin{macrocode}
\bool_new:N \l_@@_colorize_bool
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_odd_color_tl}
% The color for odd lines. Only used if colorization is enabled.
%
% \begin{macrocode}
\tl_new:N \l_@@_odd_color_tl
\tl_set:Nn \l_@@_odd_color_tl {white}
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_even_color_tl}
% The color for even lines. Only used if colorization is enabled.
%
% \begin{macrocode}
\tl_new:N \l_@@_even_color_tl
\tl_set:Nn \l_@@_even_color_tl {lightgray}
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_title_color_tl}
% The color for the title line. Only used if colorization is enabled.
%
% \begin{macrocode}
\tl_new:N \l_@@_title_color_tl
\tl_set:Nn \l_@@_title_color_tl {white}
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_total_color_tl}
% The color for the total line. Only used if colorization is enabled.
%
% \begin{macrocode}
\tl_new:N \l_@@_total_color_tl
\tl_set:Nn \l_@@_total_color_tl {white}
% \end{macrocode}
% \end{variable}
%
% \subsection{Internal State Tracking}
%
% \begin{variable}{\l_@@_in_invoice_bool}
% Tracks if we are in an invoice environment. This allows us to crash when
% nesting invoice environments by accident.
%
% \begin{macrocode}
\bool_new:N \l_@@_in_invoice_bool
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_row_number_int}
% Counts the invoice rows. We use this to tell even from odd lines. Starts with
% 1; this must be reset at the beginning of each invoice.
%
% \begin{macrocode}
\int_new:N \g_@@_row_number_int
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_vat_nonzero_bool}
% Tracks if we have already encountered a line with non-zero VAT. If so, we
% will render a VAT column and separate gross and net totals.
%
% \begin{macrocode}
\bool_new:N \l_@@_vat_nonzero_bool
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_amount_nonone_bool}
% Tracks if we have already encountered a line with non-one amount. If so, we
% will render an amount and an unit price column.
%
% \begin{macrocode}
\bool_new:N \l_@@_amount_nonone_bool
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_net_total_fp}
% The running net total.
%
% \begin{macrocode}
\fp_new:N \l_@@_net_total_fp
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_vat_total_fp}
% The running VAT total.
%
% \begin{macrocode}
\fp_new:N \l_@@_vat_total_fp
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_gross_total_fp}
% The running gross total.
%
% \begin{macrocode}
\fp_new:N \l_@@_gross_total_fp
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_tabular_tl}
% The tabular under construction. We create the tabular contents on the fly,
% using a conditional for the VAT column that is expanded only when emitting the
% invoice.
%
% \begin{macrocode}
\tl_new:N \l_@@_tabular_tl
% \end{macrocode}
% \end{variable}
%
% \section{Configuration}
%
% We define a \pkg{l3keys} key list for the package. We will reuse this for all
% configuration, except for item-specific VAT, which will override the global
% VAT setting. We handle this in the corresponding function.
%
% \begin{macrocode}
\keys_define:nn {invoice2} {
vat .fp_set:N = \l_@@_vat_fp,
vat .value_required:n = true,
vat .initial:n = 0,
included-vat .bool_set:N = \l_@@_included_vat_bool,
included-vat .initial:n = false,
currency-symbol .tl_set:N = \l_@@_currency_symbol_tl,
currency-symbol .value_required:n = true,
currency-symbol .initial:n = {\$},
currency-fraction-digits .int_set:N = \l_@@_currency_fraction_digits_int,
currency-fraction-digits .value_required:n = true,
currency-fraction-digits .initial:n = 2,
currency-in-header .bool_set:N = \l_@@_currency_in_header_bool,
currency-in-header .initial:n = false,
colorize .bool_set:N = \l_@@_colorize_bool,
colorize .initial:n = false,
odd-color .initial:n = white,
odd-color .value_required:n = true,
odd-color .tl_set:N = \l_@@_odd_color_tl,
even-color .initial:n = lightgray,
even-color .value_required:n = true,
even-color .tl_set:N = \l_@@_even_color_tl,
title-color .initial:n = white,
title-color .value_required:n = true,
title-color .tl_set:N = \l_@@_title_color_tl,
total-color .initial:n = white,
total-color .value_required:n = true,
total-color .tl_set:N = \l_@@_total_color_tl
}
% \end{macrocode}
%
% \subsection{Package Parameters}
%
% Fortunately, \pkg{l3keys2e} handles the heavy lifting for us.
%
% \begin{macrocode}
\ProcessKeysOptions{invoice2}
% \end{macrocode}
%
% \subsection{\cmd{invoiceoptions} Command}
%
% \begin{macro}{\invoiceoptions}
% We also provide an interface to change the configuration at run time.
%
% \begin{macrocode}
\NewDocumentCommand{\invoiceoptions}{m}{
\keys_set:nn {invoice2} {#1}
}
% \end{macrocode}
% \end{macro}
%
% \section{The \cmd{invoice} Environment}
%
% \subsection{Header Rendering}
%
% \begin{macro}{\@@_print_column_specification:}
% Emits the \cmd{\begin{longtable}}. The amount column is centered or skipped,
% if all amounts are one. The item column is left-justified. The VAT column is
% centered or skipped, if all VATs are zero. The unit price and price columns
% are right-justified; unit price is skipped if amount is.
%
% Since \pkg{longtable} refuses to expand the column specification, we force
% prior expansion of the booleans.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_begin_table:}{
\exp_args:Nx \longtable {
\bool_if:NT \l_@@_amount_nonone_bool { c }
l
\bool_if:NT \l_@@_vat_nonzero_bool { c }
r
\bool_if:nT { \l_@@_amount_nonone_bool || \l_@@_vat_nonzero_bool } { r }
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_column_title:n}
% Emits a formatted column title.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_column_title:n}{
\multicolumn{1}{c}{
\bool_if:NT \l_@@_colorize_bool {
\cellcolor{ \l_@@_title_color_tl }
}
\begin{scriptsize}
\textbf{#1}
\end{scriptsize}}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_amount_title:}
% Emits the \enquote{amount} column title. If all amounts are equal to 1, we
% emit nothing.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_amount_title:}{
\bool_if:NT \l_@@_amount_nonone_bool {
\@@_print_column_title:n {\GetTranslation{invoice2-amount}} &
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_item_title:}
% Emits the \enquote{item} column title.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_item_title:}{
\@@_print_column_title:n {\GetTranslation{invoice2-item}} &
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_vat_title:}
% Emits the \enquote{VAT} column title. If all VATs are zero, we emit nothing.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_vat_title:}{
\bool_if:NT \l_@@_vat_nonzero_bool {
\@@_print_column_title:n {\GetTranslation{invoice2-vat}} &
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_unit_price_title:}
% Emits the \enquote{unit price} column title. If all amounts are equal to 1,
% we emit nothing.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_unit_price_title:}{
\bool_if:nT { \l_@@_amount_nonone_bool || \l_@@_vat_nonzero_bool } {
\@@_print_column_title:n {
\GetTranslation{invoice2-unit-price}
\bool_if:NT \l_@@_currency_in_header_bool {
\ (\tl_use:N \l_@@_currency_symbol_tl)
}
} &
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_price_title:}
% Emits the \enquote{price} column title.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_price_title:}{
\@@_print_column_title:n {\GetTranslation{invoice2-price}
\bool_if:NT \l_@@_currency_in_header_bool {
\ (\tl_use:N \l_@@_currency_symbol_tl)
}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_header:}
% Emits the invoice header. If all amounts are equal to 1, we skip the amount
% column and the unit price column. If all VATs are 0, we skip the VAT column.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_header:}{
\@@_print_begin_table:
\toprule
\@@_print_amount_title:
\@@_print_item_title:
\@@_print_vat_title:
\@@_print_unit_price_title:
\@@_print_price_title:
\\
\midrule
}
% \end{macrocode}
% \end{macro}
%
% \subsection{Content Rendering}
%
% \begin{macro}{\@@_print_real_value:n}
% Emits a currency value, formatted with the current settings. The value must
% be a floating point number or variable.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_real_value:n}{
\num[round-integer-to-decimal,
group-minimum-digits=4,
group-separator={\GetTranslation{invoice2-thousands-sep}},
output-decimal-marker={\GetTranslation{invoice2-decimal-point}}]{
#1
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_currency_value:n, \@@_print_currency_value:N}
% Emits a currency value, formatted with the current settings. The value must
% be a floating point number or variable.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_currency_value:n}{
\num[round-precision={\int_use:N \l_@@_currency_fraction_digits_int},
round-mode=places,
round-integer-to-decimal,
group-minimum-digits=4,
group-separator={\GetTranslation{invoice2-thousands-sep}},
output-decimal-marker={\GetTranslation{invoice2-decimal-point}}]{
#1
}
\bool_if:NF \l_@@_currency_in_header_bool {
\, \tl_use:N \l_@@_currency_symbol_tl
}
}
\cs_new:Nn {\@@_print_currency_value:N}{
\@@_print_currency_value:n {\fp_use:N #1}
}
% \end{macrocode}
% \end{macro}
%
%\begin{macro}{\@@_print_percentage:n}
% Emits a percentage, formatted with the current settings. The value must be a
% floating point number.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_percentage:n}{
\num[round-integer-to-decimal,
group-minimum-digits=4,
group-separator={\GetTranslation{invoice2-thousands-sep}},
output-decimal-marker={\GetTranslation{invoice2-decimal-point}}]{
\fp_eval:n {#1 * 100}
}
\, \%
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_update_trackers:nn}
% Update the VAT-not-zero and amount-not-zero trackers for the given VAT and
% amount values.
%
% \begin{macrocode}
\cs_new:Nn {\@@_update_trackers:nn}{
\fp_compare:nT {#1 != 1}{
\bool_set_true:N \l_@@_amount_nonone_bool
}
\fp_compare:nT {#2 != 0}{
\bool_set_true:N \l_@@_vat_nonzero_bool
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_update_totals:nnn}
% Update the totals for the given amount, VAT and price per unit values. We
% increase the net total by $\tilde{n}$, the VAT total by $\tilde{v}$ and the
% gross total by $\tilde{g}$. For unit price $p$, amount $a$, VAT $v$ and
% non-included VATs, this is computed as
% \begin{align*}
% \tilde{n} &= a \cdot p \\
% \tilde{v} &= v \cdot \tilde{n} = a \cdot v \cdot p \\
% \tilde{g} &= \tilde{n} + \tilde{v} = a \cdot (1 + v) \cdot p, \\
% \end{align*}
% for included VATs, as
% \begin{align*}
% \tilde{g} &= a \cdot p \\
% \tilde{n} &= \frac{\tilde{g}}{1 + v} = \frac{a \cdot p}{1 + v} \\
% \tilde{v} &= \tilde{g} - \tilde{n} = \frac{a \cdot v \cdot p}{1 + v} \\
% \end{align*}
%
% \begin{macrocode}
\cs_new:Nn {\@@_update_totals:nnn}{
\fp_add:Nn \l_@@_gross_total_fp {
#1 * #3 \bool_if:NF \l_@@_included_vat_bool { * (1 + #2) }
}
\fp_add:Nn \l_@@_vat_total_fp {
#1 * #2 * #3 \bool_if:NT \l_@@_included_vat_bool { / (1 + #2) }
}
\fp_add:Nn \l_@@_net_total_fp {
#1 * #3 \bool_if:NT \l_@@_included_vat_bool { / (1 + #2) }
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_amount:n}
% Print the given amount value or nothing, if all amounts are one.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_amount:n}{
\bool_if:NT \l_@@_amount_nonone_bool {
\@@_print_real_value:n {#1} &
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_item:n}
% Print the given item name.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_item:n}{
#1 &
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_vat:n}
% Print the given VAT or nothing, if all VATs are zero.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_vat:n}{
\bool_if:NT \l_@@_vat_nonzero_bool {
\@@_print_percentage:n {#1} &
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_unit_price:n}
% Print the given unit price or nothing, if all amounts are one. Parameters are
% VAT and price per unit. For unit price $p$, VAT $v$ and non-included VATs,
% this is computed as
% \[\tilde{p} = \frac{p}{1+v},\]
% for included VATs, as
% \[\tilde{p} = p.\]
%
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_unit_price:nn}{
\bool_if:nT { \l_@@_amount_nonone_bool || \l_@@_vat_nonzero_bool } {
\@@_print_currency_value:n {
\fp_eval:n {
#2 \bool_if:NT \l_@@_included_vat_bool { / (1 + #1) }
}
} &
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_price:nnn}
% Print the price $\tilde{p}$ for the current item. Parameters are amount, VAT
% and price per unit. For unit price $p$, amount $a$, VAT $v$ and non-included
% VATs, this is computed as
% \[\tilde{p} = a \cdot (1 + v) \cdot p,\]
% for included VATs, as
% \[\tilde{p} = a \cdot p.\]
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_price:nnn}{
\@@_print_currency_value:n {
\fp_eval:n {
#1 \bool_if:NF \l_@@_included_vat_bool { * (1 + #2) } * #3
}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_colorize_row:nnn}
% Colorize the current row according to even/odd colorization, if color was
% requested in the configuration.
%
% \begin{macrocode}
\cs_new:Nn {\@@_colorize_row:}{
\bool_if:NT \l_@@_colorize_bool {
\int_if_odd:nTF \g_@@_row_number_int {
\rowcolor{ \l_@@_odd_color_tl }
}
{
\rowcolor{ \l_@@_even_color_tl }
}
}
\int_gincr:N \g_@@_row_number_int
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_add_row:nnnn}
% Add a new entry with non-default VAT to the invoice. This will update the
% VAT-not-zero and amount-not-zero trackers. Arguments are expected to be (in
% this order): amount, item name, VAT, unit price.
%
% \begin{macrocode}
\cs_new:Nn {\@@_add_row:nnnn}{
\@@_update_trackers:nn {#1} {#3}
\@@_update_totals:nnn {#1} {#3} {#4}
\tl_put_right:Nn \l_@@_tabular_tl {
\@@_colorize_row:
\@@_print_amount:n {#1}
\@@_print_item:n {#2}
\@@_print_vat:n {#3}
\@@_print_unit_price:nn {#3} {#4}
\@@_print_price:nnn {#1} {#3} {#4} \\
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\invoiceitem, \invoicesingleitem}
% This is the user interface to adding items. We read the VAT from the optional
% argument or the configuration, add an amount of one for single items and
% delegate to our implementation.
%
% \begin{macrocode}
\NewDocumentCommand{\invoiceitem}{ommm}{
\@@_add_row:nnnn {#2} {#3}
{\IfValueTF{#1}{#1}{\fp_use:N \l_@@_vat_fp}}
{#4}
}
\NewDocumentCommand{\invoicesingleitem}{omm}{
\@@_add_row:nnnn {1} {#2}
{\IfValueTF{#1}{#1}{\fp_use:N \l_@@_vat_fp}}
{#3}
}
% \end{macrocode}
% \end{macro}
%
% \subsection{Footer Rendering}
%
% \begin{macro}{\@@_print_multicolumn_count:}
% Emits the column count to group in the final lines. This is the amount of
% columns minus one.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_multicolumn_count:}{
\int_eval:n {
1
\bool_if:NT \l_@@_vat_nonzero_bool {+1}
\bool_if:NT \l_@@_amount_nonone_bool {+1}
\bool_if:nT { \l_@@_amount_nonone_bool || \l_@@_vat_nonzero_bool } {+1}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_footer_item:n}
% Emits a formatted footer item. We also handle colorization of the next cell
% here.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_footer_item:n}{
\multicolumn{\@@_print_multicolumn_count:}{r}{
\bool_if:NT \l_@@_colorize_bool {
\cellcolor{ \l_@@_total_color_tl }
}
\textbf{#1}
} & \bool_if:NT \l_@@_colorize_bool {
\cellcolor{ \l_@@_total_color_tl }
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_net_item:}
% Emits the \enquote{net total} item.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_net_item:}{
\bool_if:NT \l_@@_vat_nonzero_bool {
\@@_print_footer_item:n {
\GetTranslation{invoice2-net-total}
\bool_if:NT \l_@@_currency_in_header_bool {
\ (\tl_use:N \l_@@_currency_symbol_tl)
}
}
\@@_print_currency_value:N \l_@@_net_total_fp \\
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_vat_item:}
% Emits the \enquote{VAT total} item.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_vat_item:}{
\bool_if:NT \l_@@_vat_nonzero_bool {
\@@_print_footer_item:n {\GetTranslation{invoice2-vat-total}}
\@@_print_currency_value:N \l_@@_vat_total_fp \\
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_gross_item:}
% Emits the \enquote{gross total} item.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_gross_item:}{
\@@_print_footer_item:n {
\GetTranslation{invoice2-gross-total}
\bool_if:NT \l_@@_currency_in_header_bool {
\ (\tl_use:N \l_@@_currency_symbol_tl)
}
}
\@@_print_currency_value:N \l_@@_gross_total_fp \\
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print_footer:}
% Emits the invoice footer. If all VATs are 0, we skip the net and VAT rows.
%
% \begin{macrocode}
\cs_new:Nn {\@@_print_footer:}{
\midrule
\@@_print_net_item:
\@@_print_vat_item:
\@@_print_gross_item:
\bottomrule
\endlongtable
}
% \end{macrocode}
% \end{macro}
%
% \subsection{The Environment itself}
%
% \begin{macro}{\@@_begin_invoice:n}
% Begins a new invoice environment. We check for nested environments and set up
% configuration overrides.
%
% \begin{macrocode}
\cs_new:Nn {\@@_begin_invoice:n}{
\bool_if:NT \l_@@_in_invoice_bool {
\msg_error:nn {invoice2} {nested-invoice}
}
\bool_set_true:N \l_@@_in_invoice_bool
\int_gset:Nn \g_@@_row_number_int {1}
\keys_set:nn {invoice2} {#1}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_end_invoice:}
% End an invoice enviroenment. Here, we can emit the \cmd{longtable} environment
% since we possess all required information.
%
% \begin{macrocode}
\cs_new:Nn {\@@_end_invoice:}{
\@@_print_header:
\tl_use:N \l_@@_tabular_tl
\@@_print_footer:
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\begin{invoice}, \end{invoice}}
% The user interface is the \cmd{invoice} environment.
%
% \begin{macrocode}
\NewDocumentEnvironment{invoice}{o}{
\IfValueTF{#1}{\@@_begin_invoice:n {#1}}{\@@_begin_invoice:n {}}
}
{
\@@_end_invoice:
}
% \end{macrocode}
% \end{macro}
%
% \section{Messages and Errors}
%
% \begin{macrocode}
\msg_new:nnnn {invoice2} {nested-invoice}
{\msg_error_text:n {invoice2}:~%
Nested~invoice~environments~are~not~supported.}
{Invoices~can~not~contain~invoices.\\%
Please~check~your~environment~delimiters.}
%
% \end{macrocode}
%
% \section{Dictionary Files}
% \label{sec:dictionaries}
%
% \subsection{English Dictionary}
%
% \begin{macrocode}
%<*dictEnglish>
\ProvideDictionaryFor{English}{invoice2}
\ProvideDictTranslation{invoice2-thousands-sep}{\,}
\ProvideDictTranslation{invoice2-decimal-point}{.}
\ProvideDictTranslation{invoice2-amount}{Amount}
\ProvideDictTranslation{invoice2-item}{Item}
\ProvideDictTranslation{invoice2-vat}{VAT}
\ProvideDictTranslation{invoice2-unit-price}{Unit~Price}
\ProvideDictTranslation{invoice2-price}{Price}
\ProvideDictTranslation{invoice2-net-total}{Net~Total}
\ProvideDictTranslation{invoice2-vat-total}{VAT}
\ProvideDictTranslation{invoice2-gross-total}{Gross~Total}
%
% \end{macrocode}
%
% \subsection{German Dictionary}
%
% \begin{macrocode}
%<*dictGerman>
\ProvideDictionaryFor{German}{invoice2}
\ProvideDictTranslation{invoice2-thousands-sep}{\,}
\ProvideDictTranslation{invoice2-decimal-point}{,}
\ProvideDictTranslation{invoice2-amount}{Anzahl}
\ProvideDictTranslation{invoice2-item}{Posten}
\ProvideDictTranslation{invoice2-vat}{USt}
\ProvideDictTranslation{invoice2-unit-price}{St\"uckpreis}
\ProvideDictTranslation{invoice2-price}{Preis}
\ProvideDictTranslation{invoice2-net-total}{Nettobetrag}
\ProvideDictTranslation{invoice2-vat-total}{USt}
\ProvideDictTranslation{invoice2-gross-total}{Gesamtbetrag}
%
% \end{macrocode}
%
% \subsection{Swiss German Dictionary}
%
% \begin{macrocode}
%<*dictSwissGerman>
\ProvideDictionaryFor{Swiss German}{invoice2}
\ProvideDictTranslation{invoice2-thousands-sep}{'}
\ProvideDictTranslation{invoice2-decimal-point}{.}
%
% \end{macrocode}
% \end{implementation}
%
% \PrintChanges
% \PrintIndex
%