├── .github └── workflows │ └── l3build.yaml ├── .gitignore ├── .gitlab-ci.yml ├── .tl_packages ├── DEMO-rechnung-zugferd.tex ├── DEPENDS.txt ├── INSTALL.md ├── README.md ├── build.lua ├── config-pdf.lua ├── support ├── validate_zugferd.sh └── zugferd-test.ltx ├── testfiles-pdf ├── minimal-pdf-15.pdftex.tpf ├── minimal-pdf-15.pvt ├── minimal-pdf-15.tpf ├── minimal-pdf-17.pdftex.tpf ├── minimal-pdf-17.pvt ├── minimal-pdf-17.tpf ├── minimal-pdf-20-a4f.pdftex.tpf ├── minimal-pdf-20-a4f.pvt └── minimal-pdf-20-a4f.tpf ├── testfiles ├── BillingSpecifiedPeriod.lvt ├── BillingSpecifiedPeriod.tlg ├── ae.lvt ├── ae.tlg ├── disabled.lvt ├── disabled.tlg ├── document-reference.lvt ├── document-reference.tlg ├── eea.lvt ├── eea.tlg ├── escape-xml.lvt ├── escape-xml.tlg ├── extended-address.lvt ├── extended-address.tlg ├── lostchars.lvt ├── lostchars.tlg ├── minimal-xml.lvt ├── minimal-xml.tlg ├── mixed-vat.lvt ├── mixed-vat.tlg ├── zugferd-basic-exemption.lvt ├── zugferd-basic-exemption.tlg ├── zugferd-basic.lvt ├── zugferd-basic.tlg ├── zugferd-minimum-drop.lvt ├── zugferd-minimum-drop.tlg ├── zugferd-minimum.lvt └── zugferd-minimum.tlg ├── zugferd-invoice.sty ├── zugferd.dtx └── zugferd.ins /.github/workflows/l3build.yaml: -------------------------------------------------------------------------------- 1 | name: Build CTAN 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | name: check 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | - name: Install TeX Live 19 | uses: zauguin/install-texlive@v3 20 | with: 21 | package_file: .tl_packages 22 | # download validate_zugferd.sh to support/ so it's not done multiple times later 23 | - run: cd support && bash validate_zugferd.sh && cd - 24 | - run: l3build check 25 | - run: bash support/validate_zugferd.sh build/doc/DEMO*.pdf 26 | - name: Upload build artifats 27 | uses: actions/upload-artifact@v4 28 | with: 29 | name: zugferd-ctan 30 | path: "build/distrib/ctan/zugferd/" 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/linux,windows,latex,osx,vim,emacs 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=linux,windows,latex,osx,vim,emacs 3 | 4 | ### Emacs ### 5 | # -*- mode: gitignore; -*- 6 | *~ 7 | \#*\# 8 | /.emacs.desktop 9 | /.emacs.desktop.lock 10 | *.elc 11 | auto-save-list 12 | tramp 13 | .\#* 14 | 15 | # Org-mode 16 | .org-id-locations 17 | *_archive 18 | ltximg/** 19 | 20 | # flymake-mode 21 | *_flymake.* 22 | 23 | # eshell files 24 | /eshell/history 25 | /eshell/lastdir 26 | 27 | # elpa packages 28 | /elpa/ 29 | 30 | # reftex files 31 | *.rel 32 | 33 | # AUCTeX auto folder 34 | /auto/ 35 | 36 | # cask packages 37 | .cask/ 38 | dist/ 39 | 40 | # Flycheck 41 | flycheck_*.el 42 | 43 | # server auth directory 44 | /server/ 45 | 46 | # projectiles files 47 | .projectile 48 | 49 | # directory configuration 50 | .dir-locals.el 51 | 52 | # network security 53 | /network-security.data 54 | 55 | 56 | ### LaTeX ### 57 | ## Core latex/pdflatex auxiliary files: 58 | *.aux 59 | *.lof 60 | *.log 61 | *.lot 62 | *.fls 63 | *.out 64 | *.toc 65 | *.fmt 66 | *.fot 67 | *.cb 68 | *.cb2 69 | .*.lb 70 | 71 | ## Intermediate documents: 72 | *.dvi 73 | *.xdv 74 | *-converted-to.* 75 | # these rules might exclude image files for figures etc. 76 | # *.ps 77 | # *.eps 78 | # *.pdf 79 | 80 | ## Generated if empty string is given at "Please type another file name for output:" 81 | .pdf 82 | 83 | ## Bibliography auxiliary files (bibtex/biblatex/biber): 84 | *.bbl 85 | *.bcf 86 | *.blg 87 | *-blx.aux 88 | *-blx.bib 89 | *.run.xml 90 | 91 | ## Build tool auxiliary files: 92 | *.fdb_latexmk 93 | *.synctex 94 | *.synctex(busy) 95 | *.synctex.gz 96 | *.synctex.gz(busy) 97 | *.pdfsync 98 | 99 | ## Build tool directories for auxiliary files 100 | # latexrun 101 | latex.out/ 102 | 103 | ## Auxiliary and intermediate files from other packages: 104 | # algorithms 105 | *.alg 106 | *.loa 107 | 108 | # achemso 109 | acs-*.bib 110 | 111 | # amsthm 112 | *.thm 113 | 114 | # beamer 115 | *.nav 116 | *.pre 117 | *.snm 118 | *.vrb 119 | 120 | # changes 121 | *.soc 122 | 123 | # comment 124 | *.cut 125 | 126 | # cprotect 127 | *.cpt 128 | 129 | # elsarticle (documentclass of Elsevier journals) 130 | *.spl 131 | 132 | # endnotes 133 | *.ent 134 | 135 | # fixme 136 | *.lox 137 | 138 | # feynmf/feynmp 139 | *.mf 140 | *.mp 141 | *.t[1-9] 142 | *.t[1-9][0-9] 143 | *.tfm 144 | 145 | #(r)(e)ledmac/(r)(e)ledpar 146 | *.end 147 | *.?end 148 | *.[1-9] 149 | *.[1-9][0-9] 150 | *.[1-9][0-9][0-9] 151 | *.[1-9]R 152 | *.[1-9][0-9]R 153 | *.[1-9][0-9][0-9]R 154 | *.eledsec[1-9] 155 | *.eledsec[1-9]R 156 | *.eledsec[1-9][0-9] 157 | *.eledsec[1-9][0-9]R 158 | *.eledsec[1-9][0-9][0-9] 159 | *.eledsec[1-9][0-9][0-9]R 160 | 161 | # glossaries 162 | *.acn 163 | *.acr 164 | *.glg 165 | *.glo 166 | *.gls 167 | *.glsdefs 168 | *.lzo 169 | *.lzs 170 | 171 | # uncomment this for glossaries-extra (will ignore makeindex's style files!) 172 | # *.ist 173 | 174 | # gnuplottex 175 | *-gnuplottex-* 176 | 177 | # gregoriotex 178 | *.gaux 179 | *.gtex 180 | 181 | # htlatex 182 | *.4ct 183 | *.4tc 184 | *.idv 185 | *.lg 186 | *.trc 187 | *.xref 188 | 189 | # hyperref 190 | *.brf 191 | 192 | # knitr 193 | *-concordance.tex 194 | # TODO Comment the next line if you want to keep your tikz graphics files 195 | *.tikz 196 | *-tikzDictionary 197 | 198 | # listings 199 | *.lol 200 | 201 | # luatexja-ruby 202 | *.ltjruby 203 | 204 | # makeidx 205 | *.idx 206 | *.ilg 207 | *.ind 208 | 209 | # minitoc 210 | *.maf 211 | *.mlf 212 | *.mlt 213 | *.mtc 214 | *.mtc[0-9]* 215 | *.slf[0-9]* 216 | *.slt[0-9]* 217 | *.stc[0-9]* 218 | 219 | # minted 220 | _minted* 221 | *.pyg 222 | 223 | # morewrites 224 | *.mw 225 | 226 | # nomencl 227 | *.nlg 228 | *.nlo 229 | *.nls 230 | 231 | # pax 232 | *.pax 233 | 234 | # pdfpcnotes 235 | *.pdfpc 236 | 237 | # sagetex 238 | *.sagetex.sage 239 | *.sagetex.py 240 | *.sagetex.scmd 241 | 242 | # scrwfile 243 | *.wrt 244 | 245 | # sympy 246 | *.sout 247 | *.sympy 248 | sympy-plots-for-*.tex/ 249 | 250 | # pdfcomment 251 | *.upa 252 | *.upb 253 | 254 | # pythontex 255 | *.pytxcode 256 | pythontex-files-*/ 257 | 258 | # tcolorbox 259 | *.listing 260 | 261 | # thmtools 262 | *.loe 263 | 264 | # TikZ & PGF 265 | *.dpth 266 | *.md5 267 | *.auxlock 268 | 269 | # todonotes 270 | *.tdo 271 | 272 | # vhistory 273 | *.hst 274 | *.ver 275 | 276 | # easy-todo 277 | *.lod 278 | 279 | # xcolor 280 | *.xcp 281 | 282 | # xmpincl 283 | *.xmpi 284 | 285 | # xindy 286 | *.xdy 287 | 288 | # xypic precompiled matrices and outlines 289 | *.xyc 290 | *.xyd 291 | 292 | # endfloat 293 | *.ttt 294 | *.fff 295 | 296 | # Latexian 297 | TSWLatexianTemp* 298 | 299 | ## Editors: 300 | # WinEdt 301 | *.bak 302 | *.sav 303 | 304 | # Texpad 305 | .texpadtmp 306 | 307 | # LyX 308 | *.lyx~ 309 | 310 | # Kile 311 | *.backup 312 | 313 | # gummi 314 | .*.swp 315 | 316 | # KBibTeX 317 | *~[0-9]* 318 | 319 | # TeXnicCenter 320 | *.tps 321 | 322 | # auto folder when using emacs and auctex 323 | ./auto/* 324 | *.el 325 | 326 | # expex forward references with \gathertags 327 | *-tags.tex 328 | 329 | # standalone packages 330 | *.sta 331 | 332 | # Makeindex log files 333 | *.lpz 334 | 335 | # REVTeX puts footnotes in the bibliography by default, unless the nofootinbib 336 | # option is specified. Footnotes are the stored in a file with suffix Notes.bib. 337 | # Uncomment the next line to have this generated file ignored. 338 | #*Notes.bib 339 | 340 | ### LaTeX Patch ### 341 | # LIPIcs / OASIcs 342 | *.vtc 343 | 344 | # glossaries 345 | *.glstex 346 | 347 | ### Linux ### 348 | 349 | # temporary files which can be created if a process still has a handle open of a deleted file 350 | .fuse_hidden* 351 | 352 | # KDE directory preferences 353 | .directory 354 | 355 | # Linux trash folder which might appear on any partition or disk 356 | .Trash-* 357 | 358 | # .nfs files are created when an open file is removed but is still being accessed 359 | .nfs* 360 | 361 | ### OSX ### 362 | # General 363 | .DS_Store 364 | .AppleDouble 365 | .LSOverride 366 | 367 | # Icon must end with two \r 368 | Icon 369 | 370 | 371 | # Thumbnails 372 | ._* 373 | 374 | # Files that might appear in the root of a volume 375 | .DocumentRevisions-V100 376 | .fseventsd 377 | .Spotlight-V100 378 | .TemporaryItems 379 | .Trashes 380 | .VolumeIcon.icns 381 | .com.apple.timemachine.donotpresent 382 | 383 | # Directories potentially created on remote AFP share 384 | .AppleDB 385 | .AppleDesktop 386 | Network Trash Folder 387 | Temporary Items 388 | .apdisk 389 | 390 | ### Vim ### 391 | # Swap 392 | [._]*.s[a-v][a-z] 393 | !*.svg # comment out if you don't need vector files 394 | [._]*.sw[a-p] 395 | [._]s[a-rt-v][a-z] 396 | [._]ss[a-gi-z] 397 | [._]sw[a-p] 398 | 399 | # Session 400 | Session.vim 401 | Sessionx.vim 402 | 403 | # Temporary 404 | .netrwhist 405 | # Auto-generated tag files 406 | tags 407 | # Persistent undo 408 | [._]*.un~ 409 | 410 | ### Windows ### 411 | # Windows thumbnail cache files 412 | Thumbs.db 413 | Thumbs.db:encryptable 414 | ehthumbs.db 415 | ehthumbs_vista.db 416 | 417 | # Dump file 418 | *.stackdump 419 | 420 | # Folder config file 421 | [Dd]esktop.ini 422 | 423 | # Recycle Bin used on file shares 424 | $RECYCLE.BIN/ 425 | 426 | # Windows Installer files 427 | *.cab 428 | *.msi 429 | *.msix 430 | *.msm 431 | *.msp 432 | 433 | # Windows shortcuts 434 | *.lnk 435 | 436 | # End of https://www.toptal.com/developers/gitignore/api/linux,windows,latex,osx,vim,emacs 437 | *.xml 438 | *.csv 439 | *.b*-SAVE-ERROR 440 | *.out.ps 441 | *.hd 442 | zugferd.sty 443 | zugferd.pdf 444 | build/ 445 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | default: 2 | image: registry.gitlab.com/islandoftex/images/texlive:latest 3 | before_script: 4 | # install additional requirements for the validation procedure 5 | - apt-get update && apt-get install -y zip unzip default-jre wget && rm -rf /var/lib/apt/lists/* 6 | # download validate_zugferd.sh to support/ so it's not done multiple times later 7 | - cd support && bash validate_zugferd.sh && cd - 8 | after_script: 9 | # testfiles have already been validated, but DEMO did not 10 | - bash support/validate_zugferd.sh build/doc/DEMO*.pdf 11 | 12 | check: 13 | stage: test 14 | script: 15 | - l3build check 16 | - bash support/validate_zugferd.sh build/doc/DEMO*.pdf 17 | 18 | build_ctan: 19 | stage: deploy 20 | script: 21 | - l3build ctan 22 | artifacts: 23 | paths: 24 | - ./*.pdf 25 | - ./*.zip 26 | -------------------------------------------------------------------------------- /.tl_packages: -------------------------------------------------------------------------------- 1 | # Proudly generated by the Island of TeX's DEPendency Printer https://gitlab.com/islandoftex/texmf/depp 2 | accsupp# dtx 3 | alphalph# dtx 4 | amsfonts# dtx 5 | amsmath# DEMO dtx 6 | babel# DEMO 7 | babel-german# DEMO 8 | biber 9 | biblatex# dtx 10 | bigintcalc# dtx 11 | bitset# dtx 12 | bookmark# dtx 13 | booktabs# DEMO dtx 14 | catchfile# dtx 15 | cm# DEMO dtx 16 | cm-super# testfiles-pdf 17 | colorprofiles# DEMO dtx 18 | colortbl# dtx 19 | csquotes# dtx 20 | ec# testfiles-pdf 21 | enumitem# dtx 22 | etexcmds# dtx 23 | etoolbox# DEMO dtx 24 | fancyvrb# dtx 25 | firstaid# dtx 26 | float# dtx 27 | framed# dtx 28 | fvextra# dtx 29 | gettitlestring# dtx 30 | graphics# DEMO dtx 31 | graphics-cfg# DEMO dtx 32 | graphics-def# DEMO dtx 33 | hologo# dtx 34 | hycolor# dtx 35 | hypdoc# dtx 36 | hyperref# dtx 37 | hyphen-german# DEMO 38 | ifplatform# dtx 39 | iftex# DEMO dtx 40 | infwarerr# DEMO dtx 41 | intcalc# dtx 42 | knuth-lib# dtx 43 | koma-script# DEMO 44 | kvdefinekeys# dtx 45 | kvoptions# dtx 46 | kvsetkeys# dtx 47 | l3backend# DEMO dtx 48 | l3build 49 | l3kernel# dtx 50 | l3packages# dtx 51 | latex# DEMO dtx 52 | latex-bin 53 | latex-fonts# DEMO dtx 54 | latex-lab# DEMO dtx 55 | lineno# dtx 56 | lm# DEMO dtx 57 | logreq# dtx 58 | ltablex# DEMO 59 | ltxcmds# DEMO dtx 60 | luatex 61 | makeindex 62 | minted# dtx 63 | mptopdf# testfiles-pdf 64 | pdfescape# dtx 65 | pdfmanagement-testphase# DEMO dtx 66 | pdftexcmds# DEMO dtx 67 | psnfss# dtx 68 | ragged2e# DEMO 69 | refcount# dtx 70 | rerunfilecheck# dtx 71 | siunitx# DEMO dtx 72 | stringenc# dtx 73 | symbol# dtx 74 | tagpdf# DEMO dtx 75 | tools# DEMO dtx 76 | translations# DEMO dtx 77 | underscore# dtx 78 | uniquecounter# dtx 79 | upquote# dtx 80 | url# dtx 81 | xetex 82 | xltabular# DEMO 83 | xstring# dtx 84 | zapfding# dtx 85 | -------------------------------------------------------------------------------- /DEMO-rechnung-zugferd.tex: -------------------------------------------------------------------------------- 1 | % !TeX Program=lualatex 2 | % 3 | % Demo file for the LaTeX-ZUGFeRD project 4 | % This file corresponds to version 0.9d (2025-01-02) 5 | % 6 | % Copyright (C) 2024 Marei Peischl 7 | % --------------------------------------------------------- 8 | % 9 | % This file may be distributed and/or modified under the 10 | % conditions of the LaTeX Project Public License, either version 1.3c 11 | % of this license or (at your option) any later version. 12 | % The latest version of this license is in: 13 | % 14 | % http://www.latex-project.org/lppl.txt 15 | % 16 | % and version 1.3c or later is part of all distributions of LaTeX 17 | % version 2008-05-04 or later. 18 | % 19 | \DocumentMetadata{ 20 | pdfstandard=a-3b, 21 | lang=de, 22 | } 23 | \documentclass[parskip=half-,german]{scrartcl} 24 | 25 | \usepackage[ 26 | format=xrechnung3.0% 3.0 is the default anyway, but you can select the format to avoid automatic changes. 27 | ]{zugferd-invoice} 28 | 29 | \setkomavar{invoice}{2024:1337} 30 | \setkomavar{date}{2024-01-04} 31 | \setkomavar{title}{Rechnung} 32 | 33 | \newkomafont{invoicetotal}{\bfseries} 34 | 35 | \SetZUGFeRDData{ 36 | % document-type = commercial-invoice, % commented as this setting matches the initial value 37 | id=komavar, 38 | % date=auto, % commented as this setting matches the initial value 39 | % delivery-date = auto, % commented as this setting matches the initial value 40 | subject=komavar, 41 | fromaddress=komavar, 42 | % tax/category=S, % commented as this setting matches the initial value 43 | % tax/rate=19, % commented as this setting matches the initial value 44 | unit=hour, 45 | seller/name = {peiTeX (Marei Peischl)}, 46 | seller/postcode = {20253}, 47 | seller/city ={Hamburg}, 48 | seller/country = DE, 49 | seller/address = {Address 1}, 50 | seller/vatid = {DE123456789}, 51 | seller/contact= {Marei\\+4900000000\\marei@peitex.de}, 52 | seller/email = {kontakt@peitex.de}, 53 | buyer/reference = {buyer-reference}, %oder Leitweg-ID 54 | buyer/name = {Käufer Name}, 55 | buyer/postcode = {20253}, 56 | buyer/city ={Hamburg}, 57 | buyer/country = DE, 58 | buyer/address = {Address 1\\Address 2}, 59 | buyer/vatid = {DE123456789}, 60 | buyer/email = {invoice@example.org}, 61 | currency=€, 62 | payment-terms={Zahlbar innerhalb von 14 Tagen},% either this one or the due-date below is required 63 | due-date={20240118}, 64 | payment-means / type = 58, % SEPA Übereisung, 65 | payment-means / iban = DE68430609671013251700, 66 | payment-means / account-holder = Marei Peischl, 67 | payment-means / bic =GENODEM1GLS 68 | } 69 | 70 | 71 | 72 | \begin{document} 73 | 74 | 75 | \begin{letter}{Firma\\Vorname Nachname\\Rechnungsadresse\\PLZ Ort} 76 | 77 | \opening{Guten Tag,} 78 | 79 | hiermit stelle ich Ihnen meine Arbeit im Rahmen des Projektes XX in Rechnung. Die Leistung wurde im Januar 2024 erbracht. 80 | 81 | \AddInvoiceItem{3}{Weiterentwicklung/funktionale Erweiterung}{90} 82 | \AddInvoiceItem[7]{3}{Support}{90} 83 | \AddInvoiceItem{2}{Support an Feiertagen/Wochenende}{180} 84 | \AddInvoiceItem{3.25}{Rundungstest}{95.38} 85 | 86 | \PrintInvoiceTabular 87 | 88 | Ich bitte Sie oben genannte Betrag binnen 30 Tagen auf unten genanntes Konto zu überweisen. 89 | 90 | %Falls gewünscht 91 | \closing{Happy \TeX{}ing} 92 | 93 | 94 | \end{letter} 95 | 96 | \end{document} 97 | -------------------------------------------------------------------------------- /DEPENDS.txt: -------------------------------------------------------------------------------- 1 | # Proudly generated by the Island of TeX's DEPendency Printer https://gitlab.com/islandoftex/texmf/depp 2 | soft babel# only zugferd-invoice.sty 3 | soft booktabs# only zugferd-invoice.sty 4 | soft koma-script# only zugferd-invoice.sty 5 | soft ragged2e# only zugferd-invoice.sty 6 | siunitx 7 | soft xltabular# only zugferd-invoice.sty 8 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Recommended setup 4 | 5 | As this package is now released via CTAN, it's hightly recommended to use the TeX Live Manager (or the MikTeX console) for installation. 6 | 7 | ## Minimal portable TeX Live via DEPP 8 | 9 | Additionally, for it's possible to use the Island of TeX's DEPP project to create a minimal portable TeX Live installation only including the dependencies for this kind of documents. 10 | This repository includes a `DEPENDS.txt` for this purpose. 11 | 12 | Please be aware that the soft dependencies are those required to typeset the demo file. 13 | In case you want to use a minimal setup for this the file `.tl_packages` contains all soft dependencies with a comment informing about the reason. 14 | 15 | ## Local user level installation using l3build 16 | 17 | Additionally to the CTAN release this package includes an `l3build` installation script inside the package repository. 18 | Details on usage can be found in the [l3build documentation](http://texdoc.net/serve/l3build)/0). 19 | 20 | To get started one can run 21 | 22 | ```shell 23 | l3build doc 24 | ``` 25 | 26 | within the repositories root directory. 27 | This will build the Demo project as well as the current status of the documentation within the subdirectory `build/doc`. 28 | 29 | To Install the package within you `$TEXMFHOME` there is also the `install` action 30 | 31 | ```shell 32 | l3build install 33 | ``` 34 | 35 | This will install the `zugferd.sty` as well as the `zugferd-invoice.sty` and afterwards the TeX compiler will be able to find and use them. 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZUGFeRD - Create ZUGFeRD and other kinds of E-invoices using LaTeX 2 | 3 | Copyright (C) 2023–2025 by Marei Peischl (peiTeX) 4 | 5 | zugferd version 0.9d (2025-01-02) 6 | 7 | *************************************************************************** 8 | 9 | This material is subject to the LaTeX Project Public License version 1.3c 10 | or later. See for details. 11 | 12 | *************************************************************************** 13 | 14 | ## Abstract 15 | 16 | This package provides an interface to make your LaTeX-based invoicing compatible to e-invoicing standards, such as they exist in the EU. 17 | 18 | The package includes a demo implementation, which can be used by template developers to create their own company specific variant. The included example file shows how to use it. This package is built so it also creates the XML file which will be directly attached to the PDF. 19 | 20 | There also exist interfaces to attach an XML file generated differently. Please have a look at the documentation. 21 | 22 | This package does not provide any validation. Please be aware of you have to use valid input data for a valid ZUGFeRD output. The documentation suggests some options. 23 | 24 | ## Version History 25 | 26 | * 0.9d (2025-01-02) 27 | - extend documentation 28 | - fix purchase-order-reference 29 | * 0.9c (2024-12-08) 30 | - extend address interface 31 | - add document reference fields 32 | - fix bug adding the PDF attachment entry twice 33 | * 0.9b (2024-11-17) 34 | - Rename embedded xml-file if xrechnung is used 35 | - Fix bug leaving an unescaped `\n` in the output 36 | - Added additional testfiles 37 | * 0.9a (2024-11-07) 38 | - Add support for MINIMUM profile 39 | - Bugfix in demo package concerning rounding of non integer units. 40 | * 0.9 (2024-10-23) 41 | - Improve validation in testing of the development status. 42 | - Add support for BillingSpecifiedPeriod 43 | - Add additional user interfaces to simplify development for templates 44 | * 0.8a (2024-09-17) Patch to switch to the newly public interface of l3pdfmeta 45 | * 0.8 (2024-09-11) First version on CTAN 46 | -------------------------------------------------------------------------------- /build.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env texlua 2 | 3 | --[[ 4 | Build script for the LaTeX-ZUGFeRD project 5 | Copyright (C) 2024 Marei Peischl 6 | 7 | This file is part of the build system of the zugferd package. 8 | 9 | It may be distributed and/or modified under the conditions of the 10 | LaTeX Project Public License (LPPL), either version 1.3c of this 11 | license or (at your option) any later version. The latest version 12 | of this license is in the file 13 | 14 | https://www.latex-project.org/lppl.txt 15 | ]] 16 | 17 | module="zugferd" 18 | 19 | -- allow to tag the build.lua file 20 | if options["target"] == "tag" then 21 | excludefiles={"*~"} 22 | end 23 | 24 | packageversion = "0.9d" 25 | packagedate = "2025-01-02" 26 | 27 | sourcefiles={"*.dtx","*.ins", "*.sty"} 28 | demofiles={"*.tex"} 29 | 30 | -- demofiles should be typeset for testing but not for the ctan upload 31 | if options["target"] ~= "ctan" then 32 | typesetdemofiles={"*.tex"} 33 | end 34 | 35 | typesetexe="lualatex" 36 | typesetopts="" 37 | 38 | supportdir="support" 39 | checksuppfiles={"validate_zugferd.sh","Mustang-CLI.jar","zugferd-test.ltx"} 40 | 41 | checkconfigs = {"build"} 42 | -- checkconfigs = {"build", "config-pdf"} -- pdf config is only checked on release 43 | 44 | ctanreadme="README_CTAN.md" 45 | 46 | tagfiles = {"*.dtx","*.sty", "*.md", "*.tex","*.lua"} 47 | function update_tag(file, content, tagname, tagdate) 48 | local versionpattern = "%d+.%d+%-?%w*" 49 | local datepattern = "%d%d%d%d%-%d%d%-%d%d" 50 | if string.match(file, "%.md$") or string.match(file, "%.tex$") then 51 | content = string.gsub(content, 52 | "([Vv]ersion%s)"..versionpattern.."%s%("..datepattern.."%)", 53 | "%1"..tagname.." ("..tagdate..")") 54 | elseif file == "build.lua" then 55 | content = string.gsub(content,"(packageversion%s*=%s*\")"..versionpattern, "%1"..tagname) 56 | content = string.gsub(content,"(packagedate%s*=%s*\")"..datepattern, "%1"..tagdate) 57 | else 58 | content = string.gsub(content, 59 | "(\\Provides%a-{[^\n]-}%[)"..datepattern.."%s-v"..versionpattern, 60 | "%1"..tagdate.." v"..tagname) 61 | content = string.gsub(content, 62 | "(\\ProvidesExpl%a-{[^\n]-}){[^\n]-}{[^\n]-}", 63 | "%1{".. tagdate.."}{"..tagname .. "}") 64 | content = string.gsub(content, 65 | "(\\usepackage{"..module.."}%[)"..datepattern.."%]", 66 | "%1"..tagdate.."]") 67 | content = string.gsub(content,"\\changes{v"..tagname.."}{"..datepattern, "\\changes{v"..tagname.."}{"..tagdate) 68 | content = string.gsub(content,"\\changes{v?0*%.0*}{"..datepattern, "\\changes{v"..tagname.."}{"..tagdate) 69 | content = string.gsub(content,"\\changes{version}{date", "\\changes{v"..tagname.."}{"..tagdate) 70 | end 71 | content = string.gsub (content, 72 | "(Copyright %(C%) 202%d%–)%d%d%d%d", 73 | "%1"..os.date("%Y")) 74 | return content 75 | end 76 | 77 | github_base_url="https://github.com/TeXhackse/LaTeX-ZUGFeRD" 78 | gitlab_base_url="https://gitlab.com/islandoftex/texmf/"..module 79 | 80 | ctanpkg=module 81 | uploadconfig = { 82 | author = "Marei Peischl", 83 | uploader = "Marei Peischl", 84 | description="This package provides interfaces to allow creating ZUGFeRD or Faktur-X invoices with LaTeX including the XML file. It can be used to modify personal invoicing templates to fulfil the requirements for digital invoicing without further modification of the invoicing processes.", 85 | pkg = ctanpkg, 86 | version = packageversion .. " " .. packagedate, 87 | license = "lppl1.3c", 88 | summary = "ZUGFeRD and Faktur-X invoicing using LaTeX", 89 | ctanPath = "/macros/latex/contrib/" .. ctanpkg, 90 | repository = {gitlab_base_url..".git",github_base_url..".git"}, 91 | bugtracker = {gitlab_base_url.."/issues",github_base_url.."/issues"}, 92 | support = {gitlab_base_url.."/issues",github_base_url.."/issues"}, 93 | announcement_file = "ctan.ann", 94 | update = true, 95 | topic = "invoice", 96 | note_file = "ctan.note" 97 | } 98 | 99 | function runtest_tasks ( name , run ) 100 | if run == checkruns and options["target"] == "save" and name ~= "lostchars" then 101 | return "./validate_zugferd.sh " .. name 102 | else 103 | return "" 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /config-pdf.lua: -------------------------------------------------------------------------------- 1 | stdengine="luatex" 2 | checkengines={"pdftex", "luatex"} 3 | checkruns=2 4 | testfiledir = "testfiles-pdf" 5 | -------------------------------------------------------------------------------- /support/validate_zugferd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mustang_version="2.15.0" 4 | mustang_jar="Mustang-CLI.jar" 5 | 6 | # add scriptdir as a variable to also check support/ for the jar as it's the case on CI pipeline runs 7 | scriptdir=$(realpath "$0") 8 | scriptdir="${scriptdir%/*}" 9 | 10 | if [ ! -f "$mustang_jar" ]; then 11 | if [ -f "$scriptdir/$mustang_jar" ]; then 12 | mustang_jar="$scriptdir/$mustang_jar" 13 | else 14 | wget -O "$mustang_jar" "https://github.com/ZUGFeRD/mustangproject/releases/download/core-$mustang_version/Mustang-CLI-$mustang_version.jar" 15 | fi 16 | fi 17 | 18 | validate_zugferd () { 19 | for f in "$@" 20 | do 21 | if [[ -f "$f" ]]; then 22 | java -Xmx1G -Dfile.encoding=UTF-8 -jar "$mustang_jar" --no-notices --action validate --source "$f" 23 | fi 24 | done 25 | } 26 | 27 | for file in "$@" 28 | do 29 | # search corresponding xml or pdf file 30 | for variant in "$file" "$file.pdf" "$file.xmpl" "${file}_zugferd.xml"; do 31 | validate_zugferd "$variant" 32 | done 33 | done 34 | -------------------------------------------------------------------------------- /support/zugferd-test.ltx: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | 3 | \documentclass{article} 4 | 5 | \usepackage{zugferd} 6 | 7 | \SetZUGFeRDData{ 8 | id=1337, 9 | unit=hour, 10 | tax/category=S, 11 | seller/name = {peiTeX (Marei Peischl)}, 12 | seller/postcode = {20253}, 13 | seller/city ={Hamburg}, 14 | seller/country = DE, 15 | seller/address = {Address 1}, 16 | seller/vatid = {DE123456789}, 17 | seller/contact= {Marei\\+4900000000\\marei@peitex.de}, 18 | seller/email = {kontakt@peitex.de}, 19 | buyer/reference = {buyer-reference}, 20 | buyer/name = {Buyer Name}, 21 | buyer/postcode = {20253}, 22 | buyer/city ={Hamburg}, 23 | buyer/country = DE, 24 | buyer/vatid = {DE123456789}, 25 | buyer/email = {invoice@example.org}, 26 | due-date={20240118}, 27 | payment-means / type = 1, 28 | delivery-date=auto 29 | } 30 | 31 | \ExplSyntaxOn 32 | \pdfdict_put:nnn { l_pdffile/Params } 33 | {ModDate} { (D:20241114194206Z) } 34 | \ExplSyntaxOff 35 | 36 | \providecommand{\TestContent}{test} 37 | 38 | \begin{document}% 39 | \TestContent 40 | \csname ZUGFeRDTestBeforeXML\endcsname 41 | \ExplSyntaxOn 42 | \begin{ZUGFeRD} 43 | \zugferd_write_Item:nnnnnn {1} {} {Plushie ~ \TeX\ lion} {31.89} {2} {63.78}%special requied for space in expl3-mode 44 | \zugferd_startInvoiceSums: 45 | \zugferd_write_TaxEntry:nnnn {S} {19} {63.78} {12.12} 46 | \zugferd_write_Summation:nnnnnnnn 47 | {63.78}% LineTotalAmount 48 | {0} %ChargeTotalAmount 49 | {0} %AllowanceTotalAmount 50 | {63.78} %TaxBasisTotalAmount 51 | {12.12} %TaxTotalAmount 52 | {75.90} %GrandTotalAmount 53 | {0} % TotalPrepaidAmount 54 | {75.90} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 55 | \zugferd_stopInvoiceSums: 56 | \end{ZUGFeRD} 57 | \ExplSyntaxOff% 58 | \csname ZUGFeRDTestAfterXML\endcsname 59 | \end{document}% 60 | -------------------------------------------------------------------------------- /testfiles-pdf/minimal-pdf-15.pdftex.tpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeXhackse/LaTeX-ZUGFeRD/c6bdb5391ebdb28257274ef1c6f0ea153e0c1c05/testfiles-pdf/minimal-pdf-15.pdftex.tpf -------------------------------------------------------------------------------- /testfiles-pdf/minimal-pdf-15.pvt: -------------------------------------------------------------------------------- 1 | \DocumentMetadata{ 2 | pdfstandard=a-3b, 3 | pdfversion=1.5, 4 | lang=de, 5 | } 6 | 7 | \input{zugferd-test.ltx} 8 | -------------------------------------------------------------------------------- /testfiles-pdf/minimal-pdf-15.tpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeXhackse/LaTeX-ZUGFeRD/c6bdb5391ebdb28257274ef1c6f0ea153e0c1c05/testfiles-pdf/minimal-pdf-15.tpf -------------------------------------------------------------------------------- /testfiles-pdf/minimal-pdf-17.pdftex.tpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeXhackse/LaTeX-ZUGFeRD/c6bdb5391ebdb28257274ef1c6f0ea153e0c1c05/testfiles-pdf/minimal-pdf-17.pdftex.tpf -------------------------------------------------------------------------------- /testfiles-pdf/minimal-pdf-17.pvt: -------------------------------------------------------------------------------- 1 | \DocumentMetadata{ 2 | pdfstandard=a-3b, 3 | pdfversion=1.7, 4 | lang=de, 5 | } 6 | 7 | \input{zugferd-test.ltx} 8 | -------------------------------------------------------------------------------- /testfiles-pdf/minimal-pdf-17.tpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeXhackse/LaTeX-ZUGFeRD/c6bdb5391ebdb28257274ef1c6f0ea153e0c1c05/testfiles-pdf/minimal-pdf-17.tpf -------------------------------------------------------------------------------- /testfiles-pdf/minimal-pdf-20-a4f.pdftex.tpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeXhackse/LaTeX-ZUGFeRD/c6bdb5391ebdb28257274ef1c6f0ea153e0c1c05/testfiles-pdf/minimal-pdf-20-a4f.pdftex.tpf -------------------------------------------------------------------------------- /testfiles-pdf/minimal-pdf-20-a4f.pvt: -------------------------------------------------------------------------------- 1 | % The standard does not support PDF 2.0 (Status 2024-11-17) 2 | % This test file does only exists for testing purpose 3 | \DocumentMetadata{ 4 | pdfstandard=a-4f, 5 | pdfversion=2.0, 6 | lang=de, 7 | } 8 | 9 | \errorstopmode 10 | \input{zugferd-test.ltx} 11 | -------------------------------------------------------------------------------- /testfiles-pdf/minimal-pdf-20-a4f.tpf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeXhackse/LaTeX-ZUGFeRD/c6bdb5391ebdb28257274ef1c6f0ea153e0c1c05/testfiles-pdf/minimal-pdf-20-a4f.tpf -------------------------------------------------------------------------------- /testfiles/BillingSpecifiedPeriod.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | 4 | \usepackage[zugferd=false]{zugferd} 5 | 6 | \SetZUGFeRDData{ 7 | id=1337, 8 | unit=hour, 9 | tax/category=S, 10 | seller/name = {peiTeX (Marei Peischl)}, 11 | seller/postcode = {20253}, 12 | seller/city ={Hamburg}, 13 | seller/country = DE, 14 | seller/address = {Address 1}, 15 | seller/vatid = {DE123456789}, 16 | seller/contact= {Marei\\+4900000000\\marei@peitex.de}, 17 | seller/email = {kontakt@peitex.de}, 18 | buyer/reference = {buyer-reference}, 19 | buyer/name = {Buyer Name}, 20 | buyer/postcode = {20253}, 21 | buyer/city ={Hamburg}, 22 | buyer/country = DE, 23 | buyer/vatid = {DE123456789}, 24 | buyer/email = {invoice@example.org}, 25 | due-date={20240118}, 26 | payment-means / type = 1, 27 | delivery-date=auto 28 | } 29 | 30 | \begin{document} 31 | \ExplSyntaxOn 32 | \begin{ZUGFeRD} 33 | \keys_set:nn {zugferd/item}{start-date=20240101,end-date=20240501} 34 | \zugferd_write_Item:nnnnnn {1} {} {Plushie ~ \TeX\ lion} {31.89} {2} {63.78}%special required for space in expl3-mode 35 | \zugferd_startInvoiceSums: 36 | \zugferd_write_TaxEntry:nnnn {S} {19} {63.78} {12.12} 37 | \zugferd_write_Summation:nnnnnnnn 38 | {63.78}% LineTotalAmount 39 | {0} %ChargeTotalAmount 40 | {0} %AllowanceTotalAmount 41 | {63.78} %TaxBasisTotalAmount 42 | {12.12} %TaxTotalAmount 43 | {75.90} %GrandTotalAmount 44 | {0} % TotalPrepaidAmount 45 | {75.90} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 46 | \zugferd_stopInvoiceSums: 47 | \end{ZUGFeRD} 48 | \endlinechar=10 49 | \char_set_catcode:nn {10}{12}% 50 | \START% 51 | \SHOWFILE{\jobname _zugferd.xml}% 52 | \END% 53 | \ExplSyntaxOff% 54 | \end{document}% 55 | -------------------------------------------------------------------------------- /testfiles/BillingSpecifiedPeriod.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | -------- BillingSpecifiedPeriod_zugferd.xml (start) --------- 4 | (BillingSpecifiedPeriod_zugferd.xml) 5 | 6 | 7 | 8 | urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 9 | 10 | 11 | urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 12 | 13 | 14 | 15 | 1337 16 | 380 17 | 18 | 20160520 19 | 20 | 21 | 22 | 23 | 24 | 1 25 | 26 | 27 | Plushie TeX lion 28 | 29 | 30 | 31 | 31.89 32 | 33 | 34 | 35 | 2 36 | 37 | 38 | 39 | VAT 40 | S 41 | 19 42 | 43 | 44 | 45 | 20240101 46 | 47 | 48 | 20240501 49 | 50 | 51 | 52 | 63.78 53 | 54 | 55 | 56 | 57 | buyer-reference 58 | 59 | peiTeX (Marei Peischl) 60 | 61 | Marei 62 | 63 | +4900000000 64 | 65 | 66 | marei@peitex.de 67 | 68 | 69 | 20253 70 | Address 1 71 | Hamburg 72 | DE 73 | 74 | 75 | kontakt@peitex.de 76 | 77 | 78 | DE123456789 79 | 80 | 81 | 82 | Buyer Name 83 | 84 | 20253 85 | Hamburg 86 | DE 87 | 88 | 89 | invoice@example.org 90 | 91 | 92 | DE123456789 93 | 94 | 95 | 96 | 97 | 98 | 99 | 20160520 100 | 101 | 102 | 103 | 104 | EUR 105 | 106 | 1 107 | Instrument not defined 108 | 109 | 110 | 12.12 111 | VAT 112 | 63.78 113 | S 114 | 19 115 | 116 | 117 | 118 | 20240118 119 | 120 | 121 | 122 | 63.78 123 | 0.00 124 | 0.00 125 | 63.78 126 | 12.12 127 | 75.90 128 | 0.00 129 | 75.90 130 | 131 | 132 | 133 | 134 | -------- BillingSpecifiedPeriod_zugferd.xml (end) ----------- 135 | -------------------------------------------------------------------------------- /testfiles/ae.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | 4 | \usepackage[zugferd=false]{zugferd} 5 | 6 | \SetZUGFeRDData{ 7 | id=1337, 8 | unit=hour, 9 | tax/category=S, 10 | seller/name = {peiTeX (Marei Peischl)}, 11 | seller/postcode = {20253}, 12 | seller/city ={Hamburg}, 13 | seller/country = DE, 14 | seller/address = {Address 1}, 15 | seller/vatid = {DE123456789}, 16 | seller/contact= {Marei\\+4900000000\\marei@peitex.de}, 17 | seller/email = {kontakt@peitex.de}, 18 | buyer/reference = {buyer-reference}, 19 | buyer/name = {Buyer Name}, 20 | buyer/postcode = {20253}, 21 | buyer/city ={Hamburg}, 22 | buyer/country = DE, 23 | buyer/vatid = {DE123456789}, 24 | buyer/email = {invoice@example.org}, 25 | due-date={20240118}, 26 | payment-means / type = 1, 27 | delivery-date=auto, 28 | shipto/name = {ShipTo Name}, 29 | shipto/postcode = {Postcode}, 30 | shipto/city ={City}, 31 | shipto/country = AT, 32 | } 33 | 34 | \begin{document} 35 | \ExplSyntaxOn 36 | \begin{ZUGFeRD} 37 | \keys_set:nn {zugferd}{tax/rate=0, tax/category=AE} 38 | \zugferd_write_Item:nnnnnn {2} {0} {reduced VAT item} {90} {3} {270} 39 | \zugferd_startInvoiceSums: 40 | \zugferd_write_TaxEntry:nnnn {AE} {0} {270} {0} 41 | \zugferd_write_Summation:nnnnnnnn 42 | {270}% LineTotalAmount 43 | {0} %ChargeTotalAmount 44 | {0} %AllowanceTotalAmount 45 | {270} %TaxBasisTotalAmount 46 | {0} %TaxTotalAmount 47 | {270} %GrandTotalAmount 48 | {0} % TotalPrepaidAmount 49 | {270} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 50 | \zugferd_stopInvoiceSums: 51 | \end{ZUGFeRD} 52 | \endlinechar=10 53 | \char_set_catcode:nn {10}{12}% 54 | \START% 55 | \SHOWFILE{\jobname _zugferd.xml}% 56 | \END% 57 | \ExplSyntaxOff% 58 | \end{document}% 59 | -------------------------------------------------------------------------------- /testfiles/ae.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | -------- ae_zugferd.xml (start) --------- 4 | (ae_zugferd.xml) 5 | 6 | 7 | 8 | urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 9 | 10 | 11 | urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 12 | 13 | 14 | 15 | 1337 16 | 380 17 | 18 | 20160520 19 | 20 | 21 | 22 | 23 | 24 | 2 25 | 26 | 27 | 0 28 | reducedVATitem 29 | 30 | 31 | 32 | 90 33 | 34 | 35 | 36 | 3 37 | 38 | 39 | 40 | VAT 41 | AE 42 | 0 43 | 44 | 45 | 270 46 | 47 | 48 | 49 | 50 | buyer-reference 51 | 52 | peiTeX (Marei Peischl) 53 | 54 | Marei 55 | 56 | +4900000000 57 | 58 | 59 | marei@peitex.de 60 | 61 | 62 | 20253 63 | Address 1 64 | Hamburg 65 | DE 66 | 67 | 68 | kontakt@peitex.de 69 | 70 | 71 | DE123456789 72 | 73 | 74 | 75 | Buyer Name 76 | 77 | 20253 78 | Hamburg 79 | DE 80 | 81 | 82 | invoice@example.org 83 | 84 | 85 | DE123456789 86 | 87 | 88 | 89 | 90 | 91 | ShipTo Name 92 | 93 | Postcode 94 | City 95 | AT 96 | 97 | 98 | 99 | 100 | 20160520 101 | 102 | 103 | 104 | 105 | EUR 106 | 107 | 1 108 | Instrument not defined 109 | 110 | 111 | 0.00 112 | VAT 113 | Reverse Charge 114 | 270.00 115 | AE 116 | vatex-eu-ae 117 | 0 118 | 119 | 120 | 121 | 20240118 122 | 123 | 124 | 125 | 270.00 126 | 0.00 127 | 0.00 128 | 270.00 129 | 0.00 130 | 270.00 131 | 0.00 132 | 270.00 133 | 134 | 135 | 136 | 137 | -------- ae_zugferd.xml (end) ----------- 138 | -------------------------------------------------------------------------------- /testfiles/disabled.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | \usepackage[zugferd=false, write-xml=false]{zugferd} 4 | 5 | \SetZUGFeRDData{ 6 | id=1337, 7 | unit=hour, 8 | tax/category=S, 9 | seller/name = {peiTeX (Marei Peischl)}, 10 | seller/postcode = {20253}, 11 | seller/city ={Hamburg}, 12 | seller/country = DE, 13 | seller/address = {Address 1}, 14 | seller/vatid = {DE123456789}, 15 | seller/contact= {Marei\\+4900000000\\marei@peitex.de}, 16 | seller/email = {kontakt@peitex.de}, 17 | buyer/reference = {buyer-reference}, 18 | buyer/name = {Buyer Name}, 19 | buyer/postcode = {20253}, 20 | buyer/city ={Hamburg}, 21 | buyer/country = DE, 22 | buyer/vatid = {DE123456789}, 23 | buyer/email = {invoice@example.org}, 24 | due-date={20240118}, 25 | payment-means / type = 1, 26 | delivery-date=auto 27 | } 28 | 29 | \begin{document} 30 | \ExplSyntaxOn 31 | \begin{ZUGFeRD} 32 | \zugferd_write_Item:nnnnnn {1} {} {Plushie ~ \TeX\ lion} {31.89} {2} {63.78}%special required for space in expl3-mode 33 | \zugferd_startInvoiceSums: 34 | \zugferd_write_TaxEntry:nnnn {S} {19} {63.78} {12.12} 35 | \zugferd_write_Summation:nnnnnnnn 36 | {63.78}% LineTotalAmount 37 | {0} %ChargeTotalAmount 38 | {0} %AllowanceTotalAmount 39 | {63.78} %TaxBasisTotalAmount 40 | {12.12} %TaxTotalAmount 41 | {75.90} %GrandTotalAmount 42 | {0} % TotalPrepaidAmount 43 | {75.90} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 44 | \zugferd_stopInvoiceSums: 45 | \end{ZUGFeRD} 46 | 47 | \START 48 | \SHOWFILE{\jobname _zugferd.xml} 49 | \END 50 | 51 | \end{document} 52 | -------------------------------------------------------------------------------- /testfiles/disabled.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | -------- disabled_zugferd.xml (start) --------- 4 | Not found 5 | -------- disabled_zugferd.xml (end) ----------- 6 | -------------------------------------------------------------------------------- /testfiles/document-reference.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | 4 | \usepackage[zugferd=false]{zugferd} 5 | 6 | \SetZUGFeRDData{ 7 | id=1337, 8 | unit=hour, 9 | tax/category=S, 10 | seller/name = {peiTeX (Marei Peischl)}, 11 | seller/postcode = {20253}, 12 | seller/city ={Hamburg}, 13 | seller/country = DE, 14 | seller/address = {Address 1}, 15 | seller/vatid = {DE123456789}, 16 | seller/contact= {Marei\\+4900000000\\marei@peitex.de}, 17 | seller/email = {kontakt@peitex.de}, 18 | buyer/reference = {buyer-reference}, 19 | buyer/name = {Buyer Name}, 20 | buyer/postcode = {20253}, 21 | buyer/city ={Hamburg}, 22 | buyer/country = DE, 23 | buyer/vatid = {DE123456789}, 24 | buyer/email = {invoice@example.org}, 25 | due-date={20240118}, 26 | payment-means / type = 1, 27 | delivery-date=auto, 28 | contract-reference = {contract-ref}, 29 | purchase-order-reference = {1234567}, 30 | sales-order-reference ={1234576}, 31 | } 32 | 33 | \begin{document} 34 | \ExplSyntaxOn 35 | \begin{ZUGFeRD} 36 | \zugferd_write_Item:nnnnnn {1} {} {Plushie ~ \TeX\ lion} {31.89} {2} {63.78}%special requied for space in expl3-mode 37 | \zugferd_startInvoiceSums: 38 | \zugferd_write_TaxEntry:nnnn {S} {19} {63.78} {12.12} 39 | \zugferd_write_Summation:nnnnnnnn 40 | {63.78}% LineTotalAmount 41 | {0} %ChargeTotalAmount 42 | {0} %AllowanceTotalAmount 43 | {63.78} %TaxBasisTotalAmount 44 | {12.12} %TaxTotalAmount 45 | {75.90} %GrandTotalAmount 46 | {0} % TotalPrepaidAmount 47 | {75.90} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 48 | \zugferd_stopInvoiceSums: 49 | \end{ZUGFeRD} 50 | \endlinechar=10 51 | \char_set_catcode:nn {10}{12}% 52 | \START% 53 | \SHOWFILE{\jobname _zugferd.xml}% 54 | \END% 55 | \ExplSyntaxOff% 56 | \end{document}% 57 | -------------------------------------------------------------------------------- /testfiles/document-reference.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | -------- document-reference_zugferd.xml (start) --------- 4 | (document-reference_zugferd.xml) 5 | 6 | 7 | 8 | urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 9 | 10 | 11 | urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 12 | 13 | 14 | 15 | 1337 16 | 380 17 | 18 | 20160520 19 | 20 | 21 | 22 | 23 | 24 | 1 25 | 26 | 27 | Plushie TeX lion 28 | 29 | 30 | 31 | 31.89 32 | 33 | 34 | 35 | 2 36 | 37 | 38 | 39 | VAT 40 | S 41 | 19 42 | 43 | 44 | 63.78 45 | 46 | 47 | 48 | 49 | buyer-reference 50 | 51 | peiTeX (Marei Peischl) 52 | 53 | Marei 54 | 55 | +4900000000 56 | 57 | 58 | marei@peitex.de 59 | 60 | 61 | 20253 62 | Address 1 63 | Hamburg 64 | DE 65 | 66 | 67 | kontakt@peitex.de 68 | 69 | 70 | DE123456789 71 | 72 | 73 | 74 | Buyer Name 75 | 76 | 20253 77 | Hamburg 78 | DE 79 | 80 | 81 | invoice@example.org 82 | 83 | 84 | DE123456789 85 | 86 | 87 | 88 | 1234576 89 | 90 | 91 | 1234567 92 | 93 | 94 | contract-ref 95 | 96 | 97 | 98 | 99 | 100 | 20160520 101 | 102 | 103 | 104 | 105 | EUR 106 | 107 | 1 108 | Instrument not defined 109 | 110 | 111 | 12.12 112 | VAT 113 | 63.78 114 | S 115 | 19 116 | 117 | 118 | 119 | 20240118 120 | 121 | 122 | 123 | 63.78 124 | 0.00 125 | 0.00 126 | 63.78 127 | 12.12 128 | 75.90 129 | 0.00 130 | 75.90 131 | 132 | 133 | 134 | 135 | -------- document-reference_zugferd.xml (end) ----------- 136 | -------------------------------------------------------------------------------- /testfiles/eea.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | 4 | \usepackage[zugferd=false]{zugferd} 5 | 6 | \SetZUGFeRDData{ 7 | id=1337, 8 | unit=hour, 9 | tax/category=S, 10 | seller/name = {peiTeX (Marei Peischl)}, 11 | seller/postcode = {20253}, 12 | seller/city ={Hamburg}, 13 | seller/country = DE, 14 | seller/address = {Address 1}, 15 | seller/vatid = {DE123456789}, 16 | seller/contact= {Marei\\+4900000000\\marei@peitex.de}, 17 | seller/email = {kontakt@peitex.de}, 18 | buyer/reference = {buyer-reference}, 19 | buyer/name = {Buyer Name}, 20 | buyer/postcode = {20253}, 21 | buyer/city ={Hamburg}, 22 | buyer/country = DE, 23 | buyer/vatid = {DE123456789}, 24 | buyer/email = {invoice@example.org}, 25 | due-date={20240118}, 26 | payment-means / type = 1, 27 | delivery-date=auto, 28 | shipto/name = {ShipTo Name}, 29 | shipto/postcode = {Postcode}, 30 | shipto/city ={City}, 31 | shipto/country = AT, 32 | } 33 | 34 | \begin{document} 35 | \ExplSyntaxOn 36 | \begin{ZUGFeRD} 37 | \zugferd_write_Item:nnnnnnn {tax/rate=0, tax/category=K} {2} {0} {Intra community Item} {90} {3} {270} 38 | \zugferd_write_Item:nnnnnn {1} {} {Plushie ~ \TeX\ lion} {31.89} {2} {63.78}%special required for space in expl3-mode 39 | \zugferd_startInvoiceSums: 40 | \group_begin: 41 | \keys_set:nn {zugferd}{tax/exemption-reason= Intra-Community~Supply} 42 | \zugferd_write_TaxEntry:nnnn {K} {0} {270} {0} 43 | \group_end: 44 | \zugferd_write_TaxEntry:nnnn {S} {19} {63.78} {12.12} 45 | \zugferd_write_Summation:nnnnnnnn 46 | {333.78}% LineTotalAmount 47 | {0} %ChargeTotalAmount 48 | {0} %AllowanceTotalAmount 49 | {333.78} %TaxBasisTotalAmount 50 | {12.12} %TaxTotalAmount 51 | {345.90} %GrandTotalAmount 52 | {0} % TotalPrepaidAmount 53 | {345.90} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 54 | \zugferd_stopInvoiceSums: 55 | \end{ZUGFeRD} 56 | \endlinechar=10 57 | \char_set_catcode:nn {10}{12}% 58 | \START% 59 | \SHOWFILE{\jobname _zugferd.xml}% 60 | \END% 61 | \ExplSyntaxOff% 62 | \end{document}% 63 | -------------------------------------------------------------------------------- /testfiles/eea.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | -------- eea_zugferd.xml (start) --------- 4 | (eea_zugferd.xml) 5 | 6 | 7 | 8 | urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 9 | 10 | 11 | urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 12 | 13 | 14 | 15 | 1337 16 | 380 17 | 18 | 20160520 19 | 20 | 21 | 22 | 23 | 24 | 2 25 | 26 | 27 | 0 28 | IntracommunityItem 29 | 30 | 31 | 32 | 90 33 | 34 | 35 | 36 | 3 37 | 38 | 39 | 40 | VAT 41 | K 42 | 0 43 | 44 | 45 | 270 46 | 47 | 48 | 49 | 50 | 51 | 1 52 | 53 | 54 | Plushie TeX lion 55 | 56 | 57 | 58 | 31.89 59 | 60 | 61 | 62 | 2 63 | 64 | 65 | 66 | VAT 67 | S 68 | 19 69 | 70 | 71 | 63.78 72 | 73 | 74 | 75 | 76 | buyer-reference 77 | 78 | peiTeX (Marei Peischl) 79 | 80 | Marei 81 | 82 | +4900000000 83 | 84 | 85 | marei@peitex.de 86 | 87 | 88 | 20253 89 | Address 1 90 | Hamburg 91 | DE 92 | 93 | 94 | kontakt@peitex.de 95 | 96 | 97 | DE123456789 98 | 99 | 100 | 101 | Buyer Name 102 | 103 | 20253 104 | Hamburg 105 | DE 106 | 107 | 108 | invoice@example.org 109 | 110 | 111 | DE123456789 112 | 113 | 114 | 115 | 116 | 117 | ShipTo Name 118 | 119 | Postcode 120 | City 121 | AT 122 | 123 | 124 | 125 | 126 | 20160520 127 | 128 | 129 | 130 | 131 | EUR 132 | 133 | 1 134 | Instrument not defined 135 | 136 | 137 | 0.00 138 | VAT 139 | Intra-Community Supply 140 | 270.00 141 | K 142 | vatex-eu-ic 143 | 0 144 | 145 | 146 | 12.12 147 | VAT 148 | 63.78 149 | S 150 | 19 151 | 152 | 153 | 154 | 20240118 155 | 156 | 157 | 158 | 333.78 159 | 0.00 160 | 0.00 161 | 333.78 162 | 12.12 163 | 345.90 164 | 0.00 165 | 345.90 166 | 167 | 168 | 169 | 170 | -------- eea_zugferd.xml (end) ----------- 171 | -------------------------------------------------------------------------------- /testfiles/escape-xml.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | 4 | \usepackage[zugferd=false]{zugferd} 5 | 6 | \begin{document} 7 | \ExplSyntaxOn 8 | \zugferd_tl_set_escaped_xml:Nn \l_tmpa_tl {<>"'}% moved before \START to avoid difference with luate 9 | 10 | \START 11 | \tl_analysis_show:N \l_tmpa_tl 12 | \zugferd_tl_set_escaped_xml:Nn \l_tmpa_tl {\&} 13 | \tl_analysis_show:N \l_tmpa_tl 14 | \zugferd_tl_set_escaped_xml:Nn \l_tmpa_tl {&} 15 | \tl_analysis_show:N \l_tmpa_tl 16 | \END 17 | \END% 18 | \ExplSyntaxOff% 19 | \end{document}% 20 | -------------------------------------------------------------------------------- /testfiles/escape-xml.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | The token list \l_tmpa_tl contains the tokens: 4 | > & (the character &) 5 | > l (the character l) 6 | > t (the character t) 7 | > ; (the character ;) 8 | > & (the character &) 9 | > g (the character g) 10 | > t (the character t) 11 | > ; (the character ;) 12 | > & (the character &) 13 | > q (the character q) 14 | > u (the character u) 15 | > o (the character o) 16 | > t (the character t) 17 | > ; (the character ;) 18 | > & (the character &) 19 | > a (the character a) 20 | > p (the character p) 21 | > o (the character o) 22 | > s (the character s) 23 | > ; (the character ;). 24 | } 25 | l. ... ^^I\tl_analysis_show:N \l_tmpa_tl 26 | The token list \l_tmpa_tl contains the tokens: 27 | > \ (the character \) 28 | > & (the character &) 29 | > a (the character a) 30 | > m (the character m) 31 | > p (the character p) 32 | > ; (the character ;). 33 | } 34 | l. ... ^^I\tl_analysis_show:N \l_tmpa_tl 35 | The token list \l_tmpa_tl contains the tokens: 36 | > & (the character &) 37 | > a (the character a) 38 | > m (the character m) 39 | > p (the character p) 40 | > ; (the character ;). 41 | } 42 | l. ... ^^I\tl_analysis_show:N \l_tmpa_tl 43 | -------------------------------------------------------------------------------- /testfiles/extended-address.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | 4 | \usepackage[zugferd=false]{zugferd} 5 | 6 | \SetZUGFeRDData{ 7 | id=1337, 8 | unit=hour, 9 | tax/category=S, 10 | seller/id = {ID},% usually internal ID provided by buyer 11 | seller/name = {peiTeX (Marei Peischl)}, 12 | seller/legal-description = {Additional legal information}, 13 | seller/legal-id = {12345667}, 14 | seller/trading-name = {peiTeX}, 15 | seller/postcode = {20253}, 16 | seller/city ={Hamburg}, 17 | seller/country = DE, 18 | seller/address = {Address Line 1\\Address Line 2\\Address Line 3}, 19 | seller/vatid = {DE123456789}, 20 | seller/contact= {Marei\\+4900000000\\marei@peitex.de}, 21 | seller/email = {kontakt@peitex.de}, 22 | buyer/id = {customer id}, 23 | buyer/legal-id = {123456}, 24 | buyer/reference = {buyer-reference}, 25 | buyer/name = {Buyer Name}, 26 | buyer/postcode = {20253}, 27 | buyer/city ={Hamburg}, 28 | buyer/country = DE, 29 | buyer/vatid = {DE123456789}, 30 | buyer/contact={Loewe\\+4900000000\\loewe@customer.com},% avoid umlauts for testing as \SHOWFILE is annoying… 31 | buyer/email = {invoice@example.org}, 32 | due-date={20240118}, 33 | payment-means / type = 1, 34 | delivery-date=auto 35 | } 36 | \begin{document} 37 | \ExplSyntaxOn 38 | \begin{ZUGFeRD} 39 | \zugferd_write_Item:nnnnnn {1} {} {Plushie ~ \TeX\ lion} {31.89} {2} {63.78}%special requied for space in expl3-mode 40 | \zugferd_startInvoiceSums: 41 | \zugferd_write_TaxEntry:nnnn {S} {19} {63.78} {12.12} 42 | \zugferd_write_Summation:nnnnnnnn 43 | {63.78}% LineTotalAmount 44 | {0} %ChargeTotalAmount 45 | {0} %AllowanceTotalAmount 46 | {63.78} %TaxBasisTotalAmount 47 | {12.12} %TaxTotalAmount 48 | {75.90} %GrandTotalAmount 49 | {0} % TotalPrepaidAmount 50 | {75.90} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 51 | \zugferd_stopInvoiceSums: 52 | \end{ZUGFeRD} 53 | \endlinechar=10 54 | \char_set_catcode:nn {10}{12}% 55 | \START% 56 | \SHOWFILE{\jobname _zugferd.xml}% 57 | \END% 58 | \ExplSyntaxOff% 59 | \end{document}% 60 | -------------------------------------------------------------------------------- /testfiles/extended-address.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | -------- extended-address_zugferd.xml (start) --------- 4 | (extended-address_zugferd.xml) 5 | 6 | 7 | 8 | urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 9 | 10 | 11 | urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 12 | 13 | 14 | 15 | 1337 16 | 380 17 | 18 | 20160520 19 | 20 | 21 | 22 | 23 | 24 | 1 25 | 26 | 27 | Plushie TeX lion 28 | 29 | 30 | 31 | 31.89 32 | 33 | 34 | 35 | 2 36 | 37 | 38 | 39 | VAT 40 | S 41 | 19 42 | 43 | 44 | 63.78 45 | 46 | 47 | 48 | 49 | buyer-reference 50 | 51 | ID 52 | peiTeX (Marei Peischl) 53 | Additional legal information 54 | 55 | 12345667 56 | peiTeX 57 | 58 | 59 | Marei 60 | 61 | +4900000000 62 | 63 | 64 | marei@peitex.de 65 | 66 | 67 | 20253 68 | Address Line 1 69 | Address Line 2 70 | Address Line 3 71 | Hamburg 72 | DE 73 | 74 | 75 | kontakt@peitex.de 76 | 77 | 78 | DE123456789 79 | 80 | 81 | 82 | customer id 83 | Buyer Name 84 | 85 | 123456 86 | 87 | 88 | Loewe 89 | 90 | +4900000000 91 | 92 | 93 | loewe@customer.com 94 | 95 | 96 | 20253 97 | Hamburg 98 | DE 99 | 100 | 101 | invoice@example.org 102 | 103 | 104 | DE123456789 105 | 106 | 107 | 108 | 109 | 110 | 111 | 20160520 112 | 113 | 114 | 115 | 116 | EUR 117 | 118 | 1 119 | Instrument not defined 120 | 121 | 122 | 12.12 123 | VAT 124 | 63.78 125 | S 126 | 19 127 | 128 | 129 | 130 | 20240118 131 | 132 | 133 | 134 | 63.78 135 | 0.00 136 | 0.00 137 | 63.78 138 | 12.12 139 | 75.90 140 | 0.00 141 | 75.90 142 | 143 | 144 | 145 | 146 | -------- extended-address_zugferd.xml (end) ----------- 147 | -------------------------------------------------------------------------------- /testfiles/lostchars.lvt: -------------------------------------------------------------------------------- 1 | \DocumentMetadata{ 2 | lang=en, 3 | pdfstandard=a-3b, 4 | pdfversion=1.7 5 | } 6 | \PassOptionsToPackage{zugferd=false}{zugferd} 7 | \def\ZUGFeRDTestBeforeXML{\START} 8 | \def\ZUGFeRDTestAfterXML{\clearpage\END} 9 | \input{zugferd-test.ltx} 10 | -------------------------------------------------------------------------------- /testfiles/lostchars.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | \__zugferd_xml_writer_iow=\write... 4 | [1 5 | ] 6 | -------------------------------------------------------------------------------- /testfiles/minimal-xml.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | 4 | \usepackage[zugferd=false]{zugferd} 5 | 6 | \SetZUGFeRDData{ 7 | id=1337, 8 | unit=hour, 9 | tax/category=S, 10 | seller/name = {peiTeX (Marei Peischl)}, 11 | seller/postcode = {20253}, 12 | seller/city ={Hamburg}, 13 | seller/country = DE, 14 | seller/address = {Address 1}, 15 | seller/vatid = {DE123456789}, 16 | seller/contact= {Marei\\+4900000000\\marei@peitex.de}, 17 | seller/email = {kontakt@peitex.de}, 18 | buyer/reference = {buyer-reference}, 19 | buyer/name = {Buyer Name}, 20 | buyer/postcode = {20253}, 21 | buyer/city ={Hamburg}, 22 | buyer/country = DE, 23 | buyer/vatid = {DE123456789}, 24 | buyer/email = {invoice@example.org}, 25 | due-date={20240118}, 26 | payment-means / type = 1, 27 | delivery-date=auto 28 | } 29 | 30 | \begin{document} 31 | \ExplSyntaxOn 32 | \begin{ZUGFeRD} 33 | \zugferd_write_Item:nnnnnn {1} {} {Plushie ~ \TeX\ lion} {31.89} {2} {63.78}%special requied for space in expl3-mode 34 | \zugferd_startInvoiceSums: 35 | \zugferd_write_TaxEntry:nnnn {S} {19} {63.78} {12.12} 36 | \zugferd_write_Summation:nnnnnnnn 37 | {63.78}% LineTotalAmount 38 | {0} %ChargeTotalAmount 39 | {0} %AllowanceTotalAmount 40 | {63.78} %TaxBasisTotalAmount 41 | {12.12} %TaxTotalAmount 42 | {75.90} %GrandTotalAmount 43 | {0} % TotalPrepaidAmount 44 | {75.90} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 45 | \zugferd_stopInvoiceSums: 46 | \end{ZUGFeRD} 47 | \endlinechar=10 48 | \char_set_catcode:nn {10}{12}% 49 | \START% 50 | \SHOWFILE{\jobname _zugferd.xml}% 51 | \END% 52 | \ExplSyntaxOff% 53 | \end{document}% 54 | -------------------------------------------------------------------------------- /testfiles/minimal-xml.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | -------- minimal-xml_zugferd.xml (start) --------- 4 | (minimal-xml_zugferd.xml) 5 | 6 | 7 | 8 | urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 9 | 10 | 11 | urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 12 | 13 | 14 | 15 | 1337 16 | 380 17 | 18 | 20160520 19 | 20 | 21 | 22 | 23 | 24 | 1 25 | 26 | 27 | Plushie TeX lion 28 | 29 | 30 | 31 | 31.89 32 | 33 | 34 | 35 | 2 36 | 37 | 38 | 39 | VAT 40 | S 41 | 19 42 | 43 | 44 | 63.78 45 | 46 | 47 | 48 | 49 | buyer-reference 50 | 51 | peiTeX (Marei Peischl) 52 | 53 | Marei 54 | 55 | +4900000000 56 | 57 | 58 | marei@peitex.de 59 | 60 | 61 | 20253 62 | Address 1 63 | Hamburg 64 | DE 65 | 66 | 67 | kontakt@peitex.de 68 | 69 | 70 | DE123456789 71 | 72 | 73 | 74 | Buyer Name 75 | 76 | 20253 77 | Hamburg 78 | DE 79 | 80 | 81 | invoice@example.org 82 | 83 | 84 | DE123456789 85 | 86 | 87 | 88 | 89 | 90 | 91 | 20160520 92 | 93 | 94 | 95 | 96 | EUR 97 | 98 | 1 99 | Instrument not defined 100 | 101 | 102 | 12.12 103 | VAT 104 | 63.78 105 | S 106 | 19 107 | 108 | 109 | 110 | 20240118 111 | 112 | 113 | 114 | 63.78 115 | 0.00 116 | 0.00 117 | 63.78 118 | 12.12 119 | 75.90 120 | 0.00 121 | 75.90 122 | 123 | 124 | 125 | 126 | -------- minimal-xml_zugferd.xml (end) ----------- 127 | -------------------------------------------------------------------------------- /testfiles/mixed-vat.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | 4 | \usepackage[zugferd=false]{zugferd} 5 | 6 | \SetZUGFeRDData{ 7 | id=1337, 8 | unit=hour, 9 | tax/category=S, 10 | seller/name = {peiTeX (Marei Peischl)}, 11 | seller/postcode = {20253}, 12 | seller/city ={Hamburg}, 13 | seller/country = DE, 14 | seller/address = {Address 1}, 15 | seller/vatid = {DE123456789}, 16 | seller/contact= {Marei\\+4900000000\\marei@peitex.de}, 17 | seller/email = {kontakt@peitex.de}, 18 | buyer/reference = {buyer-reference}, 19 | buyer/name = {Buyer Name}, 20 | buyer/postcode = {20253}, 21 | buyer/city ={Hamburg}, 22 | buyer/country = DE, 23 | buyer/vatid = {DE123456789}, 24 | buyer/email = {invoice@example.org}, 25 | due-date={20240118}, 26 | payment-means / type = 1, 27 | delivery-date=auto 28 | } 29 | 30 | \begin{document} 31 | \ExplSyntaxOn 32 | \begin{ZUGFeRD} 33 | \zugferd_write_Item:nnnnnnn {tax/rate=7, tax/category=S} {2} {7} {reduced VAT item} {90} {3} {270} 34 | \zugferd_write_Item:nnnnnn {1} {} {Plushie ~ \TeX\ lion} {31.89} {2} {63.78}%special required for space in expl3-mode 35 | \zugferd_startInvoiceSums: 36 | \zugferd_write_TaxEntry:nnnn {S} {7} {270} {18.90} 37 | \zugferd_write_TaxEntry:nnnn {S} {19} {63.78} {12.12} 38 | \zugferd_write_Summation:nnnnnnnn 39 | {333.78}% LineTotalAmount 40 | {0} %ChargeTotalAmount 41 | {0} %AllowanceTotalAmount 42 | {333.78} %TaxBasisTotalAmount 43 | {31.02} %TaxTotalAmount 44 | {364.80} %GrandTotalAmount 45 | {0} % TotalPrepaidAmount 46 | {364.80} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 47 | \zugferd_stopInvoiceSums: 48 | \end{ZUGFeRD} 49 | \endlinechar=10 50 | \char_set_catcode:nn {10}{12}% 51 | \START% 52 | \SHOWFILE{\jobname _zugferd.xml}% 53 | \END% 54 | \ExplSyntaxOff% 55 | \end{document}% 56 | -------------------------------------------------------------------------------- /testfiles/mixed-vat.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | -------- mixed-vat_zugferd.xml (start) --------- 4 | (mixed-vat_zugferd.xml) 5 | 6 | 7 | 8 | urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 9 | 10 | 11 | urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 12 | 13 | 14 | 15 | 1337 16 | 380 17 | 18 | 20160520 19 | 20 | 21 | 22 | 23 | 24 | 2 25 | 26 | 27 | 7 28 | reducedVATitem 29 | 30 | 31 | 32 | 90 33 | 34 | 35 | 36 | 3 37 | 38 | 39 | 40 | VAT 41 | S 42 | 7 43 | 44 | 45 | 270 46 | 47 | 48 | 49 | 50 | 51 | 1 52 | 53 | 54 | Plushie TeX lion 55 | 56 | 57 | 58 | 31.89 59 | 60 | 61 | 62 | 2 63 | 64 | 65 | 66 | VAT 67 | S 68 | 19 69 | 70 | 71 | 63.78 72 | 73 | 74 | 75 | 76 | buyer-reference 77 | 78 | peiTeX (Marei Peischl) 79 | 80 | Marei 81 | 82 | +4900000000 83 | 84 | 85 | marei@peitex.de 86 | 87 | 88 | 20253 89 | Address 1 90 | Hamburg 91 | DE 92 | 93 | 94 | kontakt@peitex.de 95 | 96 | 97 | DE123456789 98 | 99 | 100 | 101 | Buyer Name 102 | 103 | 20253 104 | Hamburg 105 | DE 106 | 107 | 108 | invoice@example.org 109 | 110 | 111 | DE123456789 112 | 113 | 114 | 115 | 116 | 117 | 118 | 20160520 119 | 120 | 121 | 122 | 123 | EUR 124 | 125 | 1 126 | Instrument not defined 127 | 128 | 129 | 18.90 130 | VAT 131 | 270.00 132 | S 133 | 7 134 | 135 | 136 | 12.12 137 | VAT 138 | 63.78 139 | S 140 | 19 141 | 142 | 143 | 144 | 20240118 145 | 146 | 147 | 148 | 333.78 149 | 0.00 150 | 0.00 151 | 333.78 152 | 31.02 153 | 364.80 154 | 0.00 155 | 364.80 156 | 157 | 158 | 159 | 160 | -------- mixed-vat_zugferd.xml (end) ----------- 161 | -------------------------------------------------------------------------------- /testfiles/zugferd-basic-exemption.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | 4 | \usepackage[zugferd=false,format=basic]{zugferd} 5 | 6 | \SetZUGFeRDData{ 7 | id=1337, 8 | unit=hour, 9 | tax/category=S, 10 | seller/name = {peiTeX (Marei Peischl)}, 11 | seller/postcode = {20253}, 12 | seller/city ={Hamburg}, 13 | seller/country = DE, 14 | seller/address = {Address 1}, 15 | seller/vatid = {DE123456789}, 16 | seller/contact= {Marei\\+4900000000\\marei@peitex.de}, 17 | seller/email = {kontakt@peitex.de}, 18 | buyer/reference = {buyer-reference}, 19 | buyer/name = {Buyer Name}, 20 | buyer/postcode = {20253}, 21 | buyer/city ={Hamburg}, 22 | buyer/country = DE, 23 | buyer/vatid = {DE123456789}, 24 | buyer/email = {invoice@example.org}, 25 | due-date={20240118}, 26 | payment-means / type = 1, 27 | delivery-date=auto, 28 | shipto/name = {ShipTo Name}, 29 | shipto/postcode = {Postcode}, 30 | shipto/city ={City}, 31 | shipto/country = AT, 32 | } 33 | 34 | \begin{document} 35 | \ExplSyntaxOn 36 | \begin{ZUGFeRD} 37 | \zugferd_write_Item:nnnnnnn {tax/rate=0, tax/category=K} {2} {0} {Intra community Item} {90} {3} {270} 38 | \zugferd_write_Item:nnnnnn {1} {} {Plushie ~ \TeX\ lion} {31.89} {2} {63.78}%special required for space in expl3-mode 39 | \zugferd_startInvoiceSums: 40 | \group_begin: 41 | \keys_set:nn {zugferd}{tax/exemption-reason= Intra-Community~Supply} 42 | \zugferd_write_TaxEntry:nnnn {K} {0} {270} {0} 43 | \group_end: 44 | \zugferd_write_TaxEntry:nnnn {S} {19} {63.78} {12.12} 45 | \zugferd_write_Summation:nnnnnnnn 46 | {333.78}% LineTotalAmount 47 | {0} %ChargeTotalAmount 48 | {0} %AllowanceTotalAmount 49 | {333.78} %TaxBasisTotalAmount 50 | {12.12} %TaxTotalAmount 51 | {345.90} %GrandTotalAmount 52 | {0} % TotalPrepaidAmount 53 | {345.90} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 54 | \zugferd_stopInvoiceSums: 55 | \end{ZUGFeRD} 56 | \endlinechar=10 57 | \char_set_catcode:nn {10}{12}% 58 | \START% 59 | \SHOWFILE{\jobname _zugferd.xml}% 60 | \END% 61 | \ExplSyntaxOff% 62 | \end{document}% 63 | -------------------------------------------------------------------------------- /testfiles/zugferd-basic-exemption.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | -------- zugferd-basic-exemption_zugferd.xml (start) --------- 4 | (zugferd-basic-exemption_zugferd.xml) 5 | 6 | 7 | 8 | urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 9 | 10 | 11 | urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic 12 | 13 | 14 | 15 | 1337 16 | 380 17 | 18 | 20160520 19 | 20 | 21 | 22 | 23 | 24 | 2 25 | 26 | 27 | IntracommunityItem 28 | 29 | 30 | 31 | 90 32 | 33 | 34 | 35 | 3 36 | 37 | 38 | 39 | VAT 40 | K 41 | 0 42 | 43 | 44 | 270 45 | 46 | 47 | 48 | 49 | 50 | 1 51 | 52 | 53 | Plushie TeX lion 54 | 55 | 56 | 57 | 31.89 58 | 59 | 60 | 61 | 2 62 | 63 | 64 | 65 | VAT 66 | S 67 | 19 68 | 69 | 70 | 63.78 71 | 72 | 73 | 74 | 75 | buyer-reference 76 | 77 | peiTeX (Marei Peischl) 78 | 79 | 20253 80 | Address 1 81 | Hamburg 82 | DE 83 | 84 | 85 | kontakt@peitex.de 86 | 87 | 88 | DE123456789 89 | 90 | 91 | 92 | Buyer Name 93 | 94 | 20253 95 | Hamburg 96 | DE 97 | 98 | 99 | invoice@example.org 100 | 101 | 102 | DE123456789 103 | 104 | 105 | 106 | 107 | 108 | ShipTo Name 109 | 110 | Postcode 111 | City 112 | AT 113 | 114 | 115 | 116 | 117 | 20160520 118 | 119 | 120 | 121 | 122 | EUR 123 | 124 | 0.00 125 | VAT 126 | Intra-Community Supply 127 | 270.00 128 | K 129 | 0 130 | 131 | 132 | 12.12 133 | VAT 134 | 63.78 135 | S 136 | 19 137 | 138 | 139 | 140 | 20240118 141 | 142 | 143 | 144 | 333.78 145 | 0.00 146 | 0.00 147 | 333.78 148 | 12.12 149 | 345.90 150 | 0.00 151 | 345.90 152 | 153 | 154 | 155 | 156 | -------- zugferd-basic-exemption_zugferd.xml (end) ----------- 157 | -------------------------------------------------------------------------------- /testfiles/zugferd-basic.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | 4 | \usepackage[zugferd=false,format=basic]{zugferd} 5 | 6 | \SetZUGFeRDData{ 7 | id=1337, 8 | unit=hour, 9 | tax/category=S, 10 | seller/name = {peiTeX (Marei Peischl)}, 11 | seller/country = DE, 12 | seller/vatid = {DE123456789}, 13 | buyer/name = {Buyer Name}, 14 | buyer/country = DE, 15 | due-date={20240118}, 16 | } 17 | 18 | \begin{document} 19 | \ExplSyntaxOn 20 | \begin{ZUGFeRD} 21 | \zugferd_write_Item:nnnnnn {1} {} {Plushie ~ \TeX\ lion} {31.89} {2} {63.78}%special requied for space in expl3-mode 22 | \zugferd_startInvoiceSums: 23 | \zugferd_write_TaxEntry:nnnn {S} {19} {63.78} {12.12} 24 | \zugferd_write_Summation:nnnnnnnn 25 | {63.78}% LineTotalAmount 26 | {0} %ChargeTotalAmount 27 | {0} %AllowanceTotalAmount 28 | {63.78} %TaxBasisTotalAmount 29 | {12.12} %TaxTotalAmount 30 | {75.90} %GrandTotalAmount 31 | {0} % TotalPrepaidAmount 32 | {75.90} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 33 | \zugferd_stopInvoiceSums: 34 | \end{ZUGFeRD} 35 | \endlinechar=10 36 | \char_set_catcode:nn {10}{12}% 37 | \START% 38 | \SHOWFILE{\jobname _zugferd.xml}% 39 | \END% 40 | \ExplSyntaxOff% 41 | \end{document}% 42 | -------------------------------------------------------------------------------- /testfiles/zugferd-basic.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | -------- zugferd-basic_zugferd.xml (start) --------- 4 | (zugferd-basic_zugferd.xml) 5 | 6 | 7 | 8 | urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 9 | 10 | 11 | urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic 12 | 13 | 14 | 15 | 1337 16 | 380 17 | 18 | 20160520 19 | 20 | 21 | 22 | 23 | 24 | 1 25 | 26 | 27 | Plushie TeX lion 28 | 29 | 30 | 31 | 31.89 32 | 33 | 34 | 35 | 2 36 | 37 | 38 | 39 | VAT 40 | S 41 | 19 42 | 43 | 44 | 63.78 45 | 46 | 47 | 48 | 49 | 50 | 51 | peiTeX (Marei Peischl) 52 | 53 | DE 54 | 55 | 56 | DE123456789 57 | 58 | 59 | 60 | Buyer Name 61 | 62 | DE 63 | 64 | 65 | 66 | 67 | 68 | 69 | 20160520 70 | 71 | 72 | 73 | 74 | EUR 75 | 76 | 12.12 77 | VAT 78 | 63.78 79 | S 80 | 19 81 | 82 | 83 | 84 | 20240118 85 | 86 | 87 | 88 | 63.78 89 | 0.00 90 | 0.00 91 | 63.78 92 | 12.12 93 | 75.90 94 | 0.00 95 | 75.90 96 | 97 | 98 | 99 | 100 | -------- zugferd-basic_zugferd.xml (end) ----------- 101 | -------------------------------------------------------------------------------- /testfiles/zugferd-minimum-drop.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | 4 | \usepackage[zugferd=false,format=minimum]{zugferd} 5 | 6 | \SetZUGFeRDData{ 7 | id=1337, 8 | unit=hour, 9 | tax/category=S, 10 | seller/name = {peiTeX (Marei Peischl)}, 11 | seller/postcode = {20253}, 12 | seller/city ={Hamburg}, 13 | seller/country = DE, 14 | seller/address = {Address 1}, 15 | seller/vatid = {DE123456789}, 16 | seller/contact= {Marei\\+4900000000\\marei@peitex.de}, 17 | seller/email = {kontakt@peitex.de}, 18 | buyer/reference = {buyer-reference}, 19 | buyer/name = {Buyer Name}, 20 | buyer/postcode = {20253}, 21 | buyer/city ={Hamburg}, 22 | buyer/country = DE, 23 | buyer/vatid = {DE123456789}, 24 | buyer/email = {invoice@example.org}, 25 | due-date={20240118}, 26 | payment-means / type = 1, 27 | delivery-date=auto 28 | } 29 | 30 | \begin{document} 31 | \ExplSyntaxOn 32 | \begin{ZUGFeRD} 33 | \zugferd_write_Item:nnnnnn {1} {} {Plushie ~ \TeX\ lion} {31.89} {2} {63.78}%special requied for space in expl3-mode 34 | \zugferd_startInvoiceSums: 35 | \zugferd_write_TaxEntry:nnnn {S} {19} {63.78} {12.12} 36 | \zugferd_write_Summation:nnnnnnnn 37 | {63.78}% LineTotalAmount 38 | {0} %ChargeTotalAmount 39 | {0} %AllowanceTotalAmount 40 | {63.78} %TaxBasisTotalAmount 41 | {12.12} %TaxTotalAmount 42 | {75.90} %GrandTotalAmount 43 | {0} % TotalPrepaidAmount 44 | {75.90} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 45 | \zugferd_stopInvoiceSums: 46 | \end{ZUGFeRD} 47 | \endlinechar=10 48 | \char_set_catcode:nn {10}{12}% 49 | \START% 50 | \SHOWFILE{\jobname _zugferd.xml}% 51 | \END% 52 | \ExplSyntaxOff% 53 | \end{document}% 54 | -------------------------------------------------------------------------------- /testfiles/zugferd-minimum-drop.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | -------- zugferd-minimum-drop_zugferd.xml (start) --------- 4 | (zugferd-minimum-drop_zugferd.xml) 5 | 6 | 7 | 8 | urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 9 | 10 | 11 | urn:factur-x.eu:1p0:minimum 12 | 13 | 14 | 15 | 1337 16 | 380 17 | 18 | 20160520 19 | 20 | 21 | 22 | 23 | buyer-reference 24 | 25 | peiTeX (Marei Peischl) 26 | 27 | DE 28 | 29 | 30 | DE123456789 31 | 32 | 33 | 34 | Buyer Name 35 | 36 | 37 | 38 | 39 | EUR 40 | 41 | 63.78 42 | 12.12 43 | 75.90 44 | 75.90 45 | 46 | 47 | 48 | 49 | -------- zugferd-minimum-drop_zugferd.xml (end) ----------- 50 | -------------------------------------------------------------------------------- /testfiles/zugferd-minimum.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test.tex\relax 2 | \documentclass{article} 3 | 4 | \usepackage[zugferd=false,format=minimum]{zugferd} 5 | 6 | \SetZUGFeRDData{ 7 | id=1337, 8 | unit=hour, 9 | tax/category=S, 10 | seller/name = {peiTeX (Marei Peischl)}, 11 | seller/country = DE, 12 | seller/vatid = {DE123456789}, 13 | buyer/name = {Buyer Name}, 14 | } 15 | 16 | \begin{document} 17 | \ExplSyntaxOn 18 | \begin{ZUGFeRD} 19 | \zugferd_startInvoiceSums: 20 | \zugferd_write_Summation:nnnnnnnn 21 | {}% LineTotalAmount 22 | {} %ChargeTotalAmount 23 | {0} %AllowanceTotalAmount 24 | {63.78} %TaxBasisTotalAmount 25 | {12.12} %TaxTotalAmount 26 | {75.90} %GrandTotalAmount 27 | {0} % TotalPrepaidAmount 28 | {75.90} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 29 | \zugferd_stopInvoiceSums: 30 | \end{ZUGFeRD} 31 | \endlinechar=10 32 | \char_set_catcode:nn {10}{12}% 33 | \START% 34 | \SHOWFILE{\jobname _zugferd.xml}% 35 | \END% 36 | \ExplSyntaxOff% 37 | \end{document}% 38 | -------------------------------------------------------------------------------- /testfiles/zugferd-minimum.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | -------- zugferd-minimum_zugferd.xml (start) --------- 4 | (zugferd-minimum_zugferd.xml) 5 | 6 | 7 | 8 | urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 9 | 10 | 11 | urn:factur-x.eu:1p0:minimum 12 | 13 | 14 | 15 | 1337 16 | 380 17 | 18 | 20160520 19 | 20 | 21 | 22 | 23 | 24 | peiTeX (Marei Peischl) 25 | 26 | DE 27 | 28 | 29 | DE123456789 30 | 31 | 32 | 33 | Buyer Name 34 | 35 | 36 | 37 | 38 | EUR 39 | 40 | 63.78 41 | 12.12 42 | 75.90 43 | 75.90 44 | 45 | 46 | 47 | 48 | -------- zugferd-minimum_zugferd.xml (end) ----------- 49 | -------------------------------------------------------------------------------- /zugferd-invoice.sty: -------------------------------------------------------------------------------- 1 | % 2 | % Copyright (C) 2024–2025 Marei Peischl 3 | % --------------------------------------------------------- 4 | % 5 | % This file may be distributed and/or modified under the 6 | % conditions of the LaTeX Project Public License, either version 1.3c 7 | % of this license or (at your option) any later version. 8 | % The latest version of this license is in: 9 | % 10 | % http://www.latex-project.org/lppl.txt 11 | % 12 | % and version 1.3c or later is part of all distributions of LaTeX 13 | % version 2008-05-04 or later. 14 | % 15 | \ProvidesExplPackage{zugferd-invoice}{2025-01-02}{0.9d}{Invoice wrapper example package for the factur-x to create ZUGFerD invoices} 16 | 17 | \keys_define:nn {zugferd/invoice}{ 18 | default-vat .tl_set:N = \defaultVAT, 19 | default-vat .initial:n = 19, 20 | format .code:n = \PassOptionsToPackage{format=#1}{zugferd}, 21 | format .initial:n = xrechnung3.0, 22 | } 23 | 24 | \ProcessKeyOptions[zugferd/invoice] 25 | 26 | \msg_new:nnnn {ptxcd/zugferd} {not-for-production} { 27 | This~package~is~intented~to~be~an~example~for~a~possible~implementation~to~use~the~zugferd~package~for~invoicing.\\ 28 | 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. 29 | }{See~zugferd~documentation~for~instructions~concerning~the~interfaces~used~in~this~file.} 30 | \msg_warning:nn {ptxcd/zugferd} {not-for-production} 31 | 32 | \RequirePackage{scrletter} 33 | \RequirePackage{ragged2e} 34 | \RequirePackage{zugferd} 35 | \RequirePackage{babel} 36 | 37 | % e.g. use comma as output decimal marker if german 38 | \addto\extrasgerman{\sisetup{locale=DE}} 39 | \addto\extrasngerman{\sisetup{locale=DE}}% for backwards compatibility 40 | 41 | \RequirePackage{xltabular} 42 | \RequirePackage{booktabs} 43 | 44 | \newcounter{invoiceitem} 45 | \seq_new:N \g__ptxcd_VAT_rates_seq 46 | 47 | % InitVAT accepts 2 Arguments 48 | % Percentage + Tax Type Code the latter one is set to S as a default 49 | \NewDocumentCommand{\InitVAT}{mO{S}}{ 50 | \seq_gput_right:Nn \g__ptxcd_VAT_rates_seq {#1} 51 | \fp_new:c {g__ptxcd_invoice_sum_vat#1_fp} 52 | \fp_new:c {g__ptxcd_invoice_base_vat#1_fp} 53 | \cs_new:cn {__ptxcd_invoice_type_code#1:} {#2} 54 | } 55 | 56 | %Initialize VAT rates for (5),7,(16) and 19 % VAT 57 | %\InitVAT{16} 58 | \InitVAT{19} 59 | %\InitVAT{5} 60 | \InitVAT{7} 61 | 62 | % Tax initialisation with a different Code than S in this example Syntax would be 63 | % \InitVAT{0}[AE] 64 | 65 | 66 | \newcommand*{\SetDefaultVAT}[1]{\def\defaultVAT{#1}} 67 | 68 | 69 | \seq_new:N \l__ptxcd_invoice_items_seq 70 | 71 | % Auxiliary macro to allow setting the Invoice items at a different position as they are printed later 72 | \NewDocumentCommand{\AddInvoiceItem}{D<>{}O{\defaultVAT}mmm}{ 73 | \seq_put_right:Nn \l__ptxcd_invoice_items_seq { 74 | {#2}{#3}{#4}{#5}{#1} 75 | } 76 | } 77 | 78 | \newcolumntype{P}{r<{\PrintTableCurrency}} 79 | 80 | \fp_new:N \g__ptxcd_invoice_sum_fp 81 | \fp_new:N \g__ptxcd_invoice_total_fp 82 | \fp_new:N \g__ptxcd_tax_total_fp 83 | \fp_new:N \g__ptxcd_invoice_item_fp 84 | \fp_new:N \g__ptxcd_invoice_item_vat_fp 85 | \fp_new:N \g__ptxcd_invoice_sum_vat_fp 86 | 87 | \newcommand*{\PrintInvoiceTabular}{ 88 | \bool_gset_true:N \g_ptxcd_first_run_bool 89 | \begin{ZUGFeRD} 90 | \sisetup{round-precision=2,round-mode=places,round-pad=false,table-number-alignment=right,minimum-decimal-digits=2,mode=text} 91 | \begin{xltabular}{\linewidth}{@{}rS[round-precision=1,table-format=2.1]>{\RaggedRight}XPP@{}} 92 | \toprule[\lightrulewidth] 93 | \noalign{\global\let\PrintTableCurrency\relax}% 94 | \small\emph{Pos.}&\small\emph{Std.}&\small\emph{Beschreibung}&\small\emph{Einzelpreis}&\small\emph{Gesamtpreis}\\\midrule[\heavyrulewidth] 95 | \noalign{\global\let\PrintTableCurrency\TableCurrency}% 96 | \endhead 97 | \bottomrule[\lightrulewidth]\multicolumn{5}{@{}p{\textwidth}@{}}{\strut\hspace*{\fill}\footnotesize Fortsetzung auf der nächsten Seite}\endfoot 98 | \bottomrule\endlastfoot 99 | % Only write xml for the first run of the tabular. 100 | \fp_compare:nNnF {\g__ptxcd_invoice_sum_fp} = {\c_zero_dim} { 101 | \fp_gzero:N \g__ptxcd_invoice_sum_fp 102 | \zugferd_disable_XML_interfaces: 103 | } 104 | \seq_map_inline:Nn \g__ptxcd_VAT_rates_seq { 105 | \fp_gzero:c {g__ptxcd_invoice_sum_vat##1_fp} 106 | \fp_gzero:c {g__ptxcd_invoice_base_vat##1_fp} 107 | } 108 | \fp_gzero:N \g__ptxcd_invoice_sum_fp 109 | \seq_map_inline:Nn \l__ptxcd_invoice_items_seq { 110 | \PrintInvoiceItem##1 111 | } 112 | \tabularnewline 113 | \noalign{\skip_vertical:n {-\ht\strutbox-\dp\strutbox}}%offset for extra empty row of mapping 114 | \midrule[\heavyrulewidth] 115 | \PrintInvoiceTotal 116 | \end{xltabular} 117 | \end{ZUGFeRD} 118 | } 119 | 120 | \newcommand*{\PrintInvoiceTotal}{ 121 | \zugferd_startInvoiceSums: 122 | \fp_gset:Nn \g__ptxcd_invoice_total_fp { \g__ptxcd_invoice_sum_fp} 123 | \fp_gzero:N \g__ptxcd_tax_total_fp 124 | \PrintInvoiceSum{netto}{\fp_use:N \g__ptxcd_invoice_sum_fp} 125 | \seq_map_inline:Nn \g__ptxcd_VAT_rates_seq { 126 | \fp_compare:nNnF {\fp_use:c {g__ptxcd_invoice_sum_vat##1_fp}} = {0} { 127 | \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}} 128 | \fp_gadd:Nn \g__ptxcd_tax_total_fp {\fp_use:c {g__ptxcd_invoice_sum_vat##1_fp}} 129 | \PrintVatSum[{\fp_use:c {g__ptxcd_invoice_base_vat##1_fp}}]{##1 }{\fp_use:c {g__ptxcd_invoice_sum_vat##1_fp}} 130 | } 131 | } 132 | \PrintInvoiceSum{brutto}{\fp_eval:n {\g__ptxcd_tax_total_fp + \g__ptxcd_invoice_total_fp }} 133 | % TODO add support for allowance, chargeTotal, and prepaid 134 | \zugferd_write_Summation:nnnnnnnn 135 | {\fp_use:N \g__ptxcd_invoice_sum_fp}% LineTotalAmount 136 | {0} %ChargeTotalAmount 137 | {0} %AllowanceTotalAmount 138 | {\fp_use:N \g__ptxcd_invoice_sum_fp} %TaxBasisTotalAmount 139 | {\fp_use:N \g__ptxcd_tax_total_fp} %TaxTotalAmount 140 | {\fp_eval:n {\g__ptxcd_tax_total_fp + \g__ptxcd_invoice_total_fp }} %GrandTotalAmount 141 | {0} % TotalPrepaidAmount 142 | {\fp_eval:n {\g__ptxcd_tax_total_fp + \g__ptxcd_invoice_total_fp }} %DuePayableAmount = GrandTotalAmount - TotalPrepaidAmount 143 | \zugferd_stopInvoiceSums: 144 | } 145 | 146 | %Ausgabe der einzelnen Rechnungspositionen 147 | \newcommand*{\PrintInvoiceItem}[5]{% 148 | \stepcounter{invoiceitem}% 149 | \theinvoiceitem%Positionsnummer 150 | \zugferd_fp_gset_rounded:Nn \g__ptxcd_invoice_item_vat_fp {#2 * (#1/100) * #4} 151 | \zugferd_fp_gset_rounded:Nn \g__ptxcd_invoice_item_fp {#2 * #4} 152 | \fp_gadd:cn {g__ptxcd_invoice_base_vat#1_fp} {\g__ptxcd_invoice_item_fp} 153 | \fp_gadd:cn {g__ptxcd_invoice_sum_vat#1_fp} {\g__ptxcd_invoice_item_vat_fp} 154 | \fp_gadd:Nn \g__ptxcd_invoice_sum_fp {\g__ptxcd_invoice_item_fp} 155 | 156 | % optionen position nummer name einzel-preis anzahl gesamtpreis 157 | \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} 158 | 159 | % Anzahl 160 | \space(\printVAT{#1}~MwSt.)% Beschreibung mit Angabe der MwSt, in Klammern 161 | &\num{#4}%\num[round-mode=places,output-decimal-marker={,},round-pad = false]{#4}\tl_show:n {#4}%Einzelpreis 162 | &\exp_args:Nx \num{\fp_use:N \g__ptxcd_invoice_item_fp} 163 | \tabularnewline 164 | } 165 | 166 | 167 | 168 | \newcommand*{\PrintInvoiceSum}[2]{ 169 | \PrintSum{\csname invoicesum#1name\endcsname}{#2} 170 | } 171 | 172 | \newcommand*{\PrintVatSum}[3][]{ 173 | \PrintSum{\invoicesumvatname[#1]{#2}}{#3} 174 | } 175 | 176 | \newcommand*{\invoicesumvatname}[2][]{MwSt.~\printVAT{#2}\tl_if_empty:nF {#1} {\space(\num[round-precision=2]{#1}\TableCurrency)}} 177 | \renewcommand*{\theinvoiceitem}{\int_compare:nNnT {\value{invoiceitem}}<{10}{0}\arabic{invoiceitem}} 178 | 179 | \newcommand*{\PrintSum}[2]{ 180 | &&\multicolumn{1}{r}{#1\invoicesumseparator}&\multicolumn{1}{l}{}&\exp_args:Nx \num {#2}\tabularnewline 181 | } 182 | 183 | \ExplSyntaxOff 184 | 185 | \newcommand*{\invoicesumnettoname}{Summe (Netto)} 186 | \newcommand*{\invoicesumbruttoname}{Summe (Brutto)} 187 | \newcommand*{\invoicesumseparator}{:\space} 188 | 189 | \newcommand*{\TableCurrency}{\,€} 190 | \newcommand*{\printVAT}[1]{\num[round-mode=none]{#1}\,\%} 191 | 192 | \newcommand*{\PrintPositionenVAT}[5]{% 193 | \stepcounter{invoiceitem}% 194 | \theinvoiceitem\space(\printVAT{#3})\tabularnewline 195 | } 196 | 197 | \endinput 198 | -------------------------------------------------------------------------------- /zugferd.ins: -------------------------------------------------------------------------------- 1 | \input docstrip 2 | 3 | \preamble 4 | 5 | Copyright (C) 2023--2024 by Marei Peischl (peiTeX) 6 | 7 | \endpreamble 8 | 9 | \askforoverwritefalse 10 | 11 | \usedir{tex/latex/zugferd} 12 | 13 | \generate{ 14 | \file{zugferd.sty}{ 15 | \from{zugferd.dtx}{package} 16 | } 17 | } 18 | 19 | \endbatchfile 20 | --------------------------------------------------------------------------------