% % Copyright (C) 2024 Marei Peischl % --------------------------------------------------------- % % This file may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in: % % http://www.latex-project.org/lppl.txt % % and version 1.3c or later is part of all distributions of LaTeX % version 2008-05-04 or later. % \ProvidesExplPackage{zugferd-invoice}{2024-12-08}{0.9c}{Invoice wrapper example package for the factur-x to create ZUGFerD invoices} \keys_define:nn {zugferd/invoice}{ default-vat .tl_set:N = \defaultVAT, default-vat .initial:n = 19, format .code:n = \PassOptionsToPackage{format=#1}{zugferd}, format .initial:n = xrechnung3.0, } \ProcessKeyOptions[zugferd/invoice] \msg_new:nnnn {ptxcd/zugferd} {not-for-production} { This~package~is~intented~to~be~an~example~for~a~possible~implementation~to~use~the~zugferd~package~for~invoicing.\\ As~this~integrates~a~lot~with~the~visual~structure~of~your~invoice~this~should~not~be~used~directly~but~may~be~an~example~for~your~own~package. }{See~zugferd~documentation~for~instructions~concerning~the~interfaces~used~in~this~file.} \msg_warning:nn {ptxcd/zugferd} {not-for-production} \RequirePackage{scrletter} \RequirePackage{ragged2e} \RequirePackage{zugferd} \RequirePackage{babel} % e.g. use comma as output decimal marker if german \addto\extrasgerman{\sisetup{locale=DE}} \addto\extrasngerman{\sisetup{locale=DE}}% for backwards compatibility \RequirePackage{xltabular} \RequirePackage{booktabs} \newcounter{invoiceitem} \seq_new:N \g__ptxcd_VAT_rates_seq % InitVAT accepts 2 Arguments % Percentage + Tax Type Code the latter one is set to S as a default \NewDocumentCommand{\InitVAT}{mO{S}}{ \seq_gput_right:Nn \g__ptxcd_VAT_rates_seq {#1} \fp_new:c {g__ptxcd_invoice_sum_vat#1_fp} \fp_new:c {g__ptxcd_invoice_base_vat#1_fp} \cs_new:cn {__ptxcd_invoice_type_code#1:} {#2} } %Initialize VAT rates for (5),7,(16) and 19 % VAT %\InitVAT{16} \InitVAT{19} %\InitVAT{5} \InitVAT{7} % Tax initialisation with a different Code than S in this example Syntax would be % \InitVAT{0}[AE] \newcommand*{\SetDefaultVAT}[1]{\def\defaultVAT{#1}} \seq_new:N \l__ptxcd_invoice_items_seq % Auxiliary macro to allow setting the Invoice items at a different position as they are printed later \NewDocumentCommand{\AddInvoiceItem}{D<>{}O{\defaultVAT}mmm}{ \seq_put_right:Nn \l__ptxcd_invoice_items_seq { {#2}{#3}{#4}{#5}{#1} } } \newcolumntype{P}{r<{\PrintTableCurrency}} \fp_new:N \g__ptxcd_invoice_sum_fp \fp_new:N \g__ptxcd_invoice_total_fp \fp_new:N \g__ptxcd_tax_total_fp \fp_new:N \g__ptxcd_invoice_item_fp \fp_new:N \g__ptxcd_invoice_item_vat_fp \fp_new:N \g__ptxcd_invoice_sum_vat_fp \newcommand*{\PrintInvoiceTabular}{ \bool_gset_true:N \g_ptxcd_first_run_bool \begin{ZUGFeRD} \sisetup{round-precision=2,round-mode=places,round-pad=false,table-number-alignment=right,minimum-decimal-digits=2,mode=text} \begin{xltabular}{\linewidth}{@{}rS[round-precision=1,table-format=2.1]>{\RaggedRight}XPP@{}} \toprule[\lightrulewidth] \noalign{\global\let\PrintTableCurrency\relax}% \small\emph{Pos.}&\small\emph{Std.}&\small\emph{Beschreibung}&\small\emph{Einzelpreis}&\small\emph{Gesamtpreis}\\\midrule[\heavyrulewidth] \noalign{\global\let\PrintTableCurrency\TableCurrency}% \endhead \bottomrule[\lightrulewidth]\multicolumn{5}{@{}p{\textwidth}@{}}{\strut\hspace*{\fill}\footnotesize Fortsetzung auf der nächsten Seite}\endfoot \bottomrule\endlastfoot % Only write xml for the first run of the tabular. \fp_compare:nNnF {\g__ptxcd_invoice_sum_fp} = {\c_zero_dim} { \fp_gzero:N \g__ptxcd_invoice_sum_fp \zugferd_disable_XML_interfaces: } \seq_map_inline:Nn \g__ptxcd_VAT_rates_seq { \fp_gzero:c {g__ptxcd_invoice_sum_vat##1_fp} \fp_gzero:c {g__ptxcd_invoice_base_vat##1_fp} } \fp_gzero:N \g__ptxcd_invoice_sum_fp \seq_map_inline:Nn \l__ptxcd_invoice_items_seq { \PrintInvoiceItem##1 } \tabularnewline \noalign{\skip_vertical:n {-\ht\strutbox-\dp\strutbox}}%offset for extra empty row of mapping \midrule[\heavyrulewidth] \PrintInvoiceTotal \end{xltabular} \end{ZUGFeRD} } \newcommand*{\PrintInvoiceTotal}{ \zugferd_startInvoiceSums: \fp_gset:Nn \g__ptxcd_invoice_total_fp { \g__ptxcd_invoice_sum_fp} \fp_gzero:N \g__ptxcd_tax_total_fp \PrintInvoiceSum{netto}{\fp_use:N \g__ptxcd_invoice_sum_fp} \seq_map_inline:Nn \g__ptxcd_VAT_rates_seq { \fp_compare:nNnF {\fp_use:c {g__ptxcd_invoice_sum_vat##1_fp}} = {0} { \zugferd_write_TaxEntry:ennn {\use:c {__ptxcd_invoice_type_code##1:}} {##1} {\fp_use:c {g__ptxcd_invoice_base_vat##1_fp}} {\fp_use:c {g__ptxcd_invoice_sum_vat##1_fp}} \fp_gadd:Nn \g__ptxcd_tax_total_fp {\fp_use:c {g__ptxcd_invoice_sum_vat##1_fp}} \PrintVatSum[{\fp_use:c {g__ptxcd_invoice_base_vat##1_fp}}]{##1 }{\fp_use:c {g__ptxcd_invoice_sum_vat##1_fp}} } } \PrintInvoiceSum{brutto}{\fp_eval:n {\g__ptxcd_tax_total_fp + \g__ptxcd_invoice_total_fp }} % TODO add support for allowance, chargeTotal, and prepaid \zugferd_write_Summation:nnnnnnnn {\fp_use:N \g__ptxcd_invoice_sum_fp}% LineTotalAmount {0} %ChargeTotalAmount {0} %AllowanceTotalAmount {\fp_use:N \g__ptxcd_invoice_sum_fp} %TaxBasisTotalAmount {\fp_use:N \g__ptxcd_tax_total_fp} %TaxTotalAmount {\fp_eval:n {\g__ptxcd_tax_total_fp + \g__ptxcd_invoice_total_fp }} %GrandTotalAmount {0} % TotalPrepaidAmount {\fp_eval:n {\g__ptxcd_tax_total_fp + \g__ptxcd_invoice_total_fp }} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount \zugferd_stopInvoiceSums: } %Ausgabe der einzelnen Rechnungspositionen \newcommand*{\PrintInvoiceItem}[5]{% \stepcounter{invoiceitem}% \theinvoiceitem%Positionsnummer \zugferd_fp_gset_rounded:Nn \g__ptxcd_invoice_item_vat_fp {#2 * (#1/100) * #4} \zugferd_fp_gset_rounded:Nn \g__ptxcd_invoice_item_fp {#2 * #4} \fp_gadd:cn {g__ptxcd_invoice_base_vat#1_fp} {\g__ptxcd_invoice_item_fp} \fp_gadd:cn {g__ptxcd_invoice_sum_vat#1_fp} {\g__ptxcd_invoice_item_vat_fp} \fp_gadd:Nn \g__ptxcd_invoice_sum_fp {\g__ptxcd_invoice_item_fp} % optionen position nummer name einzel-preis anzahl gesamtpreis \zugferd_write_Item:ennnnnn {tax/rate=#1, tax/category=\use:c {__ptxcd_invoice_type_code#1:},#5} {\theinvoiceitem} {} {#3} {#4} {#2} {\fp_use:N \g__ptxcd_invoice_item_fp} % Anzahl \space(\printVAT{#1}~MwSt.)% Beschreibung mit Angabe der MwSt, in Klammern &\num{#4}%\num[round-mode=places,output-decimal-marker={,},round-pad = false]{#4}\tl_show:n {#4}%Einzelpreis &\exp_args:Nx \num{\fp_use:N \g__ptxcd_invoice_item_fp} \tabularnewline } \newcommand*{\PrintInvoiceSum}[2]{ \PrintSum{\csname invoicesum#1name\endcsname}{#2} } \newcommand*{\PrintVatSum}[3][]{ \PrintSum{\invoicesumvatname[#1]{#2}}{#3} } \newcommand*{\invoicesumvatname}[2][]{MwSt.~\printVAT{#2}\tl_if_empty:nF {#1} {\space(\num[round-precision=2]{#1}\TableCurrency)}} \renewcommand*{\theinvoiceitem}{\int_compare:nNnT {\value{invoiceitem}}<{10}{0}\arabic{invoiceitem}} \newcommand*{\PrintSum}[2]{ &&\multicolumn{1}{r}{#1\invoicesumseparator}&\multicolumn{1}{l}{}&\exp_args:Nx \num {#2}\tabularnewline } \ExplSyntaxOff \newcommand*{\invoicesumnettoname}{Summe (Netto)} \newcommand*{\invoicesumbruttoname}{Summe (Brutto)} \newcommand*{\invoicesumseparator}{:\space} \newcommand*{\TableCurrency}{\,€} \newcommand*{\printVAT}[1]{\num[round-mode=none]{#1}\,\%} \newcommand*{\PrintPositionenVAT}[5]{% \stepcounter{invoiceitem}% \theinvoiceitem\space(\printVAT{#3})\tabularnewline } \endinput