%% %% This is file `qrbill.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% qrbill.dtx (with options: `qrbill.sty,package') %% %% Copyright (C) 2020–2022 by Marei Peischl (peiTeX) %% %% This work is a collaboration of %% Marei Peischl (peiTeX) and Alex Antener (foobar LLC). %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 %% 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.3 or later is part of all distributions of LaTeX %% version 2005/12/01 or later. %% %% This work has the LPPL maintenance status `maintained'. %% %% The Current Maintainer of this work is %% Marei Peischl . %% %% This work consists of the files %% qrbill.dtx and qrbill.ins, qrbill-vocab.csv %% and the derived files %% qrbill.sty, swiss.qrbill-cfg.tex, epc.qrbill-cfg.tex, %% qrbill-letter-demo.tex, qrbill-standalone-demo.tex. %% %% The development repository can be found at %% https://github.com/peitex/qrbill %% Please use the issue tracker for feedback! %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{expl3} \ProvidesExplPackage{qrbill}{2022/10/20}{1.07}{ Template for QR-bills based on the Swiss Payment Standards } \RequirePackage{iftex} \RequirePackage{l3keys2e} \tl_new:N \g__qrbill_font_tl \bool_new:N \g__qrbill_top_frame_bool \bool_new:N \g__qrbill_bottom_frame_bool \bool_new:N \g__qrbill_left_frame_bool \bool_new:N \g__qrbill_right_frame_bool \bool_new:N \g__qrbill_vrule_bool \bool_new:N \g__qrbill_separateinfo_bool \prop_new:N \g__qrbill_replacement_prop \msg_new:nnn {qrbill} {typo-in-option} { A~typo~within~the~option~#1~was~removed.\\ The~correct~name~for~the~option~is~#2.\\ Please~use~#2~instead~of~#1,~which~only\\ exists~for~backwards~compatibility~and~will~be~removed. } \keys_define:nn {qrbill} { font .choices:nn = {Frutiger, Arial, Helvetica, Liberation Sans} { \tl_gset_eq:NN \g__qrbill_font_tl \l_keys_choice_tl }, font .initial:n = Liberation Sans, font / custom .code:n = {\tl_gclear:N \g__qrbill_font_tl}, qrscheme .tl_gset:N = \g__qrbill_qrscheme_tl, qrscheme .initial:n = swiss, creditorprefix .tl_gset:N = \g__qrbill_creditorprefix_tl, creditorprefix .initial:n = CR-, debtorprefix .tl_gset:N = \g__qrbill_debtorprefix_tl, debtorprefix .initial:n = UD-, qrmode .choice:, qrmode / package .code:n = \bool_gset_false:N \g__qrbill_luamode_bool, qrmode / lua .code:n = \bool_gset_true:N \g__qrbill_luamode_bool, qrmode .initial:n = package, frame .choice:, frame / false .code:n = { \bool_gset_false:N \g__qrbill_top_frame_bool \bool_gset_false:N \g__qrbill_bottom_frame_bool \bool_gset_false:N \g__qrbill_left_frame_bool \bool_gset_false:N \g__qrbill_right_frame_bool }, frame / true .code:n = { \bool_gset_true:N \g__qrbill_top_frame_bool \bool_gset_true:N \g__qrbill_bottom_frame_bool \bool_gset_true:N \g__qrbill_left_frame_bool \bool_gset_true:N \g__qrbill_right_frame_bool }, frame / top .code:n = { \bool_gset_true:N \g__qrbill_top_frame_bool \bool_gset_false:N \g__qrbill_bottom_frame_bool \bool_gset_false:N \g__qrbill_left_frame_bool \bool_gset_false:N \g__qrbill_right_frame_bool }, frame / bottom .code:n = { \bool_gset_false:N \g__qrbill_top_frame_bool \bool_gset_true:N \g__qrbill_bottom_frame_bool \bool_gset_false:N \g__qrbill_left_frame_bool \bool_gset_false:N \g__qrbill_right_frame_bool }, frame / none .code:n = { \bool_gset_false:N \g__qrbill_top_frame_bool \bool_gset_false:N \g__qrbill_bottom_frame_bool \bool_gset_false:N \g__qrbill_left_frame_bool \bool_gset_false:N \g__qrbill_right_frame_bool \keys_set:nn {qrbill} {vrule=false} }, frame .initial:n = true, vrule .choice:, vrule / true .code:n = \tl_gset:Nn \g__qrbill_vrule_tl {\rule{\g__qrbill_rule_dim}{\c_qrbill_height_dim}}, vrule / false .code:n = \tl_gset:Nn \g__qrbill_vrule_tl {\rule{\g__qrbill_rule_dim}{\c_zero_dim}}, vrule / symbol .code:n = { \RequirePackage{marvosym} \tl_gset:Nn \g__qrbill_vrule_tl { \rotatebox{90}{ \hbox_to_wd:nn {\c_qrbill_height_dim}{ \leaders\hbox{\rule{1mm}{\g__qrbill_rule_dim}\hspace{1mm}}\hskip 0pt\@plus1 fill\relax \llap{\raisebox{-.5\height}[\c_zero_dim][\c_zero_dim]{\LeftScissors}} \leaders\hbox{\rule{1mm}{\g__qrbill_rule_dim}\hspace{1mm}}\hskip 0pt\@plus4 fill\relax \hbox{\rule{1mm}{\g__qrbill_rule_dim}} } } } }, vrule .initial:n = true, billinginfo .bool_gset:N = \g__grbill_billinginfo_auto_bool, billinginfo .default:n = true, billinginfo .initial:n = true, icon .choice:, icon / swiss-cross .meta:n = {icon=qrbill_swiss-cross.pdf}, icon / unknown .code:n = \tl_gset:Nn \g_qrbill_icon_tl {#1}, icon .initial:n =, iconwidth .dim_gset:N = \g_qrbill_iconwidth_dim, iconwidth .initial:n = 7mm, separate .choice:, separate / symbol .code:n = { \bool_gset_true:N \g__qrbill_separateinfo_bool \RequirePackage{marvosym} \cs_set:Nn \qrbill_print_separate_info: { \par\leaders\vbox_to_ht:nn {1sp} { \smash{ \hbox_to_wd:nn {\c_qrbill_width_dim }{ \leaders\hbox{\rule{1mm}{\g__qrbill_rule_dim}\hspace{1mm}}\hskip 0pt\@plus1 fill\relax \llap{\raisebox{-.5\height}{\LeftScissors}} \leaders\hbox{\rule{1mm}{\g__qrbill_rule_dim}\hspace{1mm}}\hskip 0pt\@plus4 fill\relax } } } \vskip 1sp \vskip -1sp } }, separate / text .code:n = { \bool_gset_true:N \g__qrbill_separateinfo_bool \cs_set:Nn \qrbill_print_separate_info: { \centerline{\raisebox{\dimexpr\depth+.3ex\relax}[0pt][0pt]{\footnotesize\qrbillseparatename}} \par\nointerlineskip \rule{\c_qrbill_width_dim}{\g__qrbill_rule_dim} } }, separate / false .code:n = {\bool_gset_false:N \g__qrbill_separateinfo_bool}, separate .initial:n = text, sep-iban .int_gset:N = \g__qrbill_ibansep_int, sep-iban .initial:n = 0, ibanseparator .tl_gset:N = \g__qrbill_ibansep_tl, ibanseparator .initial:n = {\,}, ibanseperator .code:n = \keys_set:nn {qrbill} {ibanseparator=#1}\msg_warning:nnnn {qrbill} {typo-in-option} {ibanseperator} {ibanseparator}, sep-reference .int_gset:N = \g__qrbill_referencesep_int, sep-reference .initial:n = 0, referenceseparator .tl_gset:N = \g__qrbill_referencesep_tl, referenceseparator .initial:n = {\,}, referenceseperator .code:n = \keys_set:nn {qrbill} {referenceseparator=#1}\msg_warning:nnnn {qrbill} {typo-in-option} {referenceseperator} {referenceseparator}, replace-tilde .choice:, replace-tilde / true .code:n = \prop_gput:Nxx \g__qrbill_replacement_prop {\char_generate:nn {126} {12}} {\ }, replace-tilde / false .code:n = \exp_args:NNx \prop_gremove:Nn \g__qrbill_replacement_prop {\char_generate:nn {126} {12}}, replace-umlauts .choice:, replace-umlauts / true .code:n = \prop_gput_from_keyval:Nn \g__qrbill_replacement_prop {ä=ae,Ä=AE,ü=ue,Ü=UE,ö=oe,Ö=OE,ß=ss,ẞ=SS}, replace-umlauts / false .code:n = \clist_map_inline:nn {ä,Ä,ü,Ü,ö,Ö,ß,ẞ} {\prop_gremove:Nn \g__qrbill_replacement_prop {##1}}, data-to-string .bool_gset:N = \g__qrbill_to_string_bool, ignore-if-empty .clist_gset:N = \g__qrbill_ignore_if_empty_clist, ignore-if-empty .initial:n = , } \ProcessKeysOptions{qrbill} \newcommand*{\qrbillsetup}[1]{\keys_set:nn {qrbill}{#1}} \NewDocumentCommand{\qrbillsetdata}{sm}{ \bool_if:NTF \g__qrbill_to_string_bool { \IfBooleanTF {#1} { \tl_set:Nx \l_tmpa_tl {#2} \exp_args:Nnx \keys_set:nn {qrbill/data} {\tl_to_str:V \l_tmpa_tl} }{ \exp_args:Nnx \keys_set:nn {qrbill/data} {\tl_to_str:n {#2}} } } { \IfBooleanT {#1} \exp_args:Nnx \keys_set:nn {qrbill/data}{#2} } } \tl_if_empty:NTF \g__qrbill_font_tl { \def\qrbillfont{\normalfont} }{ \RequirePackage{fontspec} \newfontfamily{\qrbillfont}{\g__qrbill_font_tl} \RequirePackage{anyfontsize} } \dim_new:N \g_qrbill_QRcode_dim \dim_gset:Nn \g_qrbill_QRcode_dim {46mm} \bool_if:NT \g__qrbill_luamode_bool { \lua_load_module:n {qrbill-latexluaqrcode} \dim_new:N \l__qrbill_QRblocksize_dim \cs_set_protected:Npn \qrbill_qrcode_black: {\rule{\l__qrbill_QRblocksize_dim}{\l__qrbill_QRblocksize_dim}} \cs_set_protected:Npn \qrbill_qrcode_white: {\rule{\l__qrbill_QRblocksize_dim}{0pt}\rule{0pt}{\l__qrbill_QRblocksize_dim}} \cs_new:Nn \qrbill_parse_QRcode:n { \lua_now:e { num, string = printQRcode("\lua_escape:n {#1}") } \dim_set:Nn \l__qrbill_QRblocksize_dim {\g_qrbill_QRcode_dim/\lua_now:n {tex.print(num)}} \let\qrblack\qrbill_qrcode_black: \let\qrwhite\qrbill_qrcode_white: \def\qrnewline{\\[\dimexpr-\baselineskip+\l__qrbill_QRblocksize_dim]} \noindent\parbox{\g_qrbill_QRcode_dim}{ \lua_now:n {tex.sprint(string)} } } } \bool_if:NF \g__qrbill_luamode_bool { \usepackage{qrcode} % modified version of \qr@encode@binary to allow utf8 qrcodes required by swiss qrbill scheme % Copyright (C) 2015 by Anders Hendrickson \cs_set:Nn \__qrbill_encode_unicode_binary:n { \edef\qr@plaintext{#1}% \def\qr@codetext{4}% %This means `binary' \__qrbill_qr_get_string_length_encoded:n { \qr@plaintext } \edef\qr@charactercountlengthinhex{\int_eval:n {\qr@charactercountbits@byte / 4}}% \qr@decimaltohex[\qr@charactercountlengthinhex]{\qr@charactercount}{\qr@stringlength}% \xa\g@addto@macro\xa\qr@codetext\xa{\qr@charactercount}% \exp_args:NNx \str_set_convert:Nnnn \l_tmpa_str { \qr@plaintext } {} {utf8/hex} \str_gput_right:NV \qr@codetext \l_tmpa_str \xdef\qr@codetext{\exp_args:No \str_lowercase:n {\qr@codetext}} \g@addto@macro\qr@codetext{0}% %This is '0000' in binary. \setcounter{qr@hexchars}{\tl_count:o {\qr@codetext}}% \edef\qr@numpaddingcodewords{\int_eval:n {(-\c@qr@hexchars / 2)+\qr@totaldatacodewords}} \int_compare:nNnT {\qr@numpaddingcodewords} < {0} { \edef\ds{ERROR:~Too~much~data!~Over~by~\qr@numpaddingcodewords~bytes.} } \int_compare:nNnT {\qr@numpaddingcodewords} > {0} { \int_step_inline:nnnn {2} {2} {\qr@numpaddingcodewords} { \g@addto@macro{\qr@codetext}{ec11}% } \int_if_odd:nT {\qr@numpaddingcodewords} { \g@addto@macro{\qr@codetext}{ec}% } } } \cs_set:Nn \qrbill_parse_QRcode:n { \cs_set_eq:NN \qr@encode@binary \__qrbill_encode_unicode_binary:n \raisebox{\depth}{ \__qrbill_enable_unicode_qrcode_patch: \qrcode[height= \g_qrbill_QRcode_dim]{#1} } } \cs_new:Nn \__qrbill_qr_get_string_length_encoded:n {% \exp_args:NNx \str_set_convert:Nnnn \l_tmpa_str { #1 } {} {utf8/hex} \xdef\qr@stringlength{\int_eval:n {\str_count:N \l_tmpa_str / 2}} } \cs_new:Nn \__qrbill_qr_padatfront:nn {% \prg_replicate:nn {\int_max:nn {0} {#2- \tl_count:N #1}} { \qr@g@preface@macro{#1}{0} } } \let\orig@qr@getstringlength\qr@getstringlength \cs_new:Nn \__qrbill_enable_unicode_qrcode_patch: { \cs_set_eq:NN \qr@padatfront \__qrbill_qr_padatfront:nn \AddToHook{cmd/qr@choose@best@version/before}{\cs_set_eq:NN \qr@getstringlength\__qrbill_qr_get_string_length_encoded:n} \AddToHook{cmd/qr@choose@best@version/after}{\let\qr@getstringlength\orig@qr@getstringlength} } } \cs_generate_variant:Nn \qrbill_parse_QRcode:n {V} \newcommand*{\QRbillAddCustomReplacement}[2]{ \prop_gput:Nxx \g__qrbill_replacement_prop {#1} {#2}, } \RequirePackage{scrbase} \RequirePackage{graphicx} \RequirePackage{numprint} \npthousandsep{\,} \npdecimalsign{.} \dim_new:N \g__qrbill_rule_dim \dim_gset:Nn \g__qrbill_rule_dim {.5pt} \dim_const:Nn \c_qrbill_sep_dim {5mm} \dim_const:Nn \c_qrbill_width_dim {210mm} \dim_const:Nn \c_qrbill_height_dim {105mm} \cs_new:Nn \qrbill_title_font: {\fontsize{11bp}{11bp}\selectfont\bfseries} \cs_new:Nn \qrbill_headingR_font: {\fontsize{6bp}{9bp}\selectfont\bfseries} \cs_new:Nn \qrbill_valueR_font: {\fontsize{8bp}{9bp}\selectfont} \cs_new:Nn \qrbill_amountR_font: {\fontsize{8bp}{11bp}\selectfont} \cs_new:Nn \qrbill_acceptance_font: {\fontsize{6bp}{8bp}\selectfont\bfseries} \cs_new:Nn \qrbill_headingP_font: {\fontsize{8bp}{11bp}\selectfont\bfseries} \cs_new:Nn \qrbill_valueP_font: {\fontsize{10bp}{11bp}\selectfont} \cs_new:Nn \qrbill_amountP_font: {\fontsize{10bp}{13bp}\selectfont} \cs_new:Nn \qrbill_infoheading_font: {\fontsize{7bp}{8bp}\selectfont\bfseries} \cs_new:Nn \qrbill_info_font: {\fontsize{7bp}{8bp}\selectfont} \dim_new:N \g_qrbill_placeholder_rule_dim \dim_gset:Nn \g_qrbill_placeholder_rule_dim {.75pt} \dim_new:N \g_qrbill_placeholder_corner_dim \dim_gset:Nn \g_qrbill_placeholder_corner_dim {3mm} \cs_new:Nn \__qrbill_placeholder_hmark: { \rule{\g_qrbill_placeholder_corner_dim}{\g_qrbill_placeholder_rule_dim} } \cs_new:Nn \__qrbill_placeholder_vmark: { \rule{\g_qrbill_placeholder_rule_dim}{\g_qrbill_placeholder_corner_dim} } \cs_new:Nn \__qrbill_placeholder:nn { \vbox_to_ht:nn {#2} { \hbox_to_wd:nn {#1} {\__qrbill_placeholder_hmark: \hfill \__qrbill_placeholder_hmark:} \nointerlineskip \hbox_to_wd:nn {#1} {\__qrbill_placeholder_vmark: \hfill \__qrbill_placeholder_vmark:} \vfill \hbox_to_wd:nn {#1} {\__qrbill_placeholder_vmark: \hfill \__qrbill_placeholder_vmark:} \nointerlineskip \hbox_to_wd:nn {#1} {\__qrbill_placeholder_hmark: \hfill \__qrbill_placeholder_hmark:} } } \cs_new:Nn \qrbill_bill_create: { \begingroup \qrbill_parse_BillingInfo: \qrbillfont \setlength{\parindent}{\z@} \parbox{\c_qrbill_width_dim }{ \vbox to \c_qrbill_height_dim { \bool_if:NTF \g__qrbill_top_frame_bool { \bool_if:NTF \g__qrbill_separateinfo_bool {\qrbill_print_separate_info:} {\rule{\c_qrbill_width_dim}{\g__qrbill_rule_dim}} } {\rule{\c_zero_dim}{\g__qrbill_rule_dim}} \par\nointerlineskip \skip_vertical:n {\c_qrbill_sep_dim-\g__qrbill_rule_dim} \skip_horizontal:n {\c_qrbill_sep_dim-\g__qrbill_rule_dim} \begin{minipage}[c][95mm][t]{52mm} \vbox_to_ht:nn {7mm} {\qrbill_title_font:\qrbillreceiptname} \par\nointerlineskip \vbox_to_ht:nn {56mm}{ {\qrbill_headingR_font:\qrbillaccountname\par} { \qrbill_valueR_font: \__qrbill_sep_tl:nV {iban} \l_qrbill_data_Account_tl\par \qrbill_insert_address:N \g__qrbill_creditorprefix_tl \par\vskip\baselineskip } \tl_if_empty:NF \l_qrbill_data_Reference_tl { {\qrbill_headingR_font:\qrbillreferencename\par} { \qrbill_valueR_font: \__qrbill_sep_tl:nV {reference} \l_qrbill_data_Reference_tl \par\vskip\baselineskip } } \tl_if_empty:cTF {l_qrbill_data_\g__qrbill_debtorprefix_tl Name_tl} { {\qrbill_headingR_font:\qrbilldebtoraddrname\par} \__qrbill_placeholder:nn {52mm} {20mm} }{ {\qrbill_headingR_font:\qrbilldebtorname\par} { \qrbill_valueR_font: \qrbill_insert_address:N \g__qrbill_debtorprefix_tl \par } } } \par\nointerlineskip \vbox_to_ht:nn {14mm}{ \qrbill_headingR_font: \begin{tabular}[t]{@{}ll@{}} \qrbillcurrencyname&\qrbill_headingR_font:\qrbillamountname\\ \qrbill_amountR_font:\l_qrbill_data_Currency_tl &\qrbill_amountR_font: \tl_if_empty:NF \l_qrbill_data_Amount_tl {\numprint{\l_qrbill_data_Amount_tl}} \end{tabular} \tl_if_empty:NTF \l_qrbill_data_Amount_tl { \hfill \raisebox{\dimexpr-\height+\ht\strutbox}[\z@]{\llap{ \__qrbill_placeholder:nn {30mm} {10mm} }} } \vfill } \par\nointerlineskip \vbox_to_ht:nn {18mm} { \makebox[\linewidth][r]{\qrbill_headingR_font:\qrbillacceptantname}\par } \end{minipage}% \skip_horizontal:n {2\c_qrbill_sep_dim} \begin{minipage}[c][95mm][t]{138mm} \begin{minipage}[c][85mm][t]{51mm} \parbox[t][7mm][t]{\linewidth}{\qrbill_title_font:\qrbillpaymentpartname} \par\nointerlineskip \skip_vertical:n {\c_qrbill_sep_dim} \qrcode_setup_QRcode: \leavevmode\qrbill_parse_QRcode:V \l_qrbill_data_str \tl_if_empty:NF \g_qrbill_icon_tl { \llap{\hbox_to_wd:nn {\g_qrbill_QRcode_dim} { \hfill \raisebox{\dimexpr-.5\height+.5\g_qrbill_QRcode_dim}[0pt][0pt]{ \includegraphics[width=\g_qrbill_iconwidth_dim]{\g_qrbill_icon_tl} } \hfill }} } \skip_vertical:n {\c_qrbill_sep_dim} \vbox_to_ht:nn {22mm}{ \begin{tabular}[b]{@{}ll@{}} \qrbill_headingP_font:\qrbillcurrencyname&\qrbill_headingP_font: \qrbillamountname\\ \qrbill_amountP_font:\tl_use:c {l_qrbill_data_Currency_tl}& \tl_if_empty:NF \l_qrbill_data_Amount_tl { \qrbill_amountP_font:\numprint{\l_qrbill_data_Amount_tl} } \end{tabular} \tl_if_empty:NTF \l_qrbill_data_Amount_tl { \hfill \raisebox{\dimexpr-\height+\ht\strutbox}[\z@]{ \llap{\__qrbill_placeholder:nn {40mm} {15mm} }} } } \end{minipage} \begin{minipage}[c][85mm][t]{87mm} \par\nointerlineskip {\qrbill_headingP_font:\qrbillaccountname\par} { \qrbill_valueP_font: \__qrbill_sep_tl:nV {iban} \l_qrbill_data_Account_tl \par \qrbill_insert_address:N \g__qrbill_creditorprefix_tl \par\vskip\baselineskip } \tl_if_empty:NF \l_qrbill_data_Reference_tl { {\qrbill_headingP_font:\qrbillreferencename\par} {\qrbill_valueP_font: \__qrbill_sep_tl:nV {reference} \l_qrbill_data_Reference_tl \par\vskip\baselineskip} } \exp_args:Nf \tl_if_empty:nF { \l_qrbill_data_BillingInfo_tl \l_qrbill_data_Message_tl }{ {\qrbill_headingP_font:\qrbilladdinfoname\par} { \qrbill_valueP_font: \l_qrbill_data_Message_tl\par \tl_replace_all:Nnn \l_qrbill_data_BillingInfo_tl {/} {\discretionary{}{}{}/} \l_qrbill_data_BillingInfo_tl \par\vskip\baselineskip } } \tl_if_empty:cTF {l_qrbill_data_\g__qrbill_debtorprefix_tl Name_tl} { {\qrbill_headingP_font:\qrbilldebtoraddrname\par} \__qrbill_placeholder:nn {65mm} {25mm} }{ {\qrbill_headingP_font:\qrbilldebtorname\par} { \qrbill_valueP_font: \qrbill_insert_address:N \g__qrbill_debtorprefix_tl \par } } \end{minipage}\par\nointerlineskip \begin{minipage}[b][10mm][t]{\linewidth} \strut \qrbill_insert_AV_parameters:NNn \qrbill_infoheading_font: \qrbill_info_font: {AV1,AV2} \end{minipage} \end{minipage} \par\nointerlineskip\skip_vertical:n {\c_qrbill_sep_dim} \smash{ \bool_if:NT \g__qrbill_bottom_frame_bool {\rlap{\rule{\c_qrbill_width_dim}{\g__qrbill_rule_dim}}} \bool_if:NTF \g__qrbill_left_frame_bool {\rule{\g__qrbill_rule_dim}{\c_qrbill_height_dim}} {\rule{\g__qrbill_rule_dim}{\c_zero_dim}} \hspace{\dimexpr62mm-1.5\g__qrbill_rule_dim} \g__qrbill_vrule_tl \hspace{\dimexpr148mm-1.5\g__qrbill_rule_dim} \bool_if:NTF \g__qrbill_right_frame_bool {\rule{\g__qrbill_rule_dim}{\c_qrbill_height_dim}} {\rule{\g__qrbill_rule_dim}{\c_zero_dim}} } } } \endgroup } \NewDocumentCommand{\QRbill}{so}{ \begingroup \IfNoValueF{#2} {\keys_set:nn {qrbill/data} {#2}} \IfBooleanTF {#1} { \qrcode_setup_QRcode: \qrbill_parse_QRcode:V \l_qrbill_data_str }{ \qrbill_bill_create: } \endgroup } \ior_new:N \qrbill_ior \clist_new:N \l_qrbill_tmpa_clist \ior_open:Nn \qrbill_ior {qrbill-vocab.csv} \ior_get:NN \qrbill_ior \l_tmpa_tl \clist_set:Nx \l_qrbill_tmpa_clist {\l_tmpa_tl} \int_set:Nn \l_tmpa_int {\clist_count:N \l_qrbill_tmpa_clist} \ior_str_map_inline:Nn \qrbill_ior { \int_step_inline:nnn {2} {\l_tmpa_int } { \exp_args:Nnx \use:n {\exp_args:NNx \exp_args:Nnc \defcaptionname {\clist_item:Nn \l_qrbill_tmpa_clist {##1}} {qrbill\clist_item:nn {#1} {1}name}} {\clist_item:nn {#1} {##1}} } } \ior_close:N \qrbill_ior \seq_new:N \l_qrbill_tmp_seq \cs_new:Nn \qrbill_set_address_combined:nn { \bool_if:NTF \g__qrbill_to_string_bool { \exp_args:NNxx \seq_set_split:Nnn \l_qrbill_tmp_seq {\tl_to_str:n {\\}} { \str_range:nnn { #2 } { 2 } { -2 } } } { \seq_set_split:Nnn \l_qrbill_tmp_seq {\\} {#2} } \exp_args:Nnx \keys_set:nn {qrbill/data} { #1AddressType=K, #1Name={\seq_item:Nn \l_qrbill_tmp_seq {1}}, #1Address1={\seq_item:Nn \l_qrbill_tmp_seq {2}}, #1Address2={\seq_item:Nn \l_qrbill_tmp_seq {3}}, #1PostalCode=, #1City=, #1Country={\seq_item:Nn \l_qrbill_tmp_seq {4}}, } } \cs_new:Nn \qrbill_set_address_structured:nn { \bool_if:NTF \g__qrbill_to_string_bool { \exp_args:NNxx \seq_set_split:Nnn \l_qrbill_tmp_seq {\tl_to_str:n {\\}} { \str_range:nnn { #2 } { 2 } { -2 } } } { \seq_set_split:Nnn \l_qrbill_tmp_seq {\\} {#2} } \exp_args:Nnx \keys_set:nn {qrbill/data} { #1AddressType=S, #1Name={\seq_item:Nn \l_qrbill_tmp_seq {1}}, #1Address1={\seq_item:Nn \l_qrbill_tmp_seq {2}}, #1Address2={\seq_item:Nn \l_qrbill_tmp_seq {3}}, #1PostalCode={\seq_item:Nn \l_qrbill_tmp_seq {4}}, #1City={\seq_item:Nn \l_qrbill_tmp_seq {5}}, #1Country={\seq_item:Nn \l_qrbill_tmp_seq {6}}, } } \cs_new:Nn \qrbill_insert_address:N { \tl_use:c {l_qrbill_data_#1Name_tl}\ifhmode\\\fi \str_case_e:nnF {\use:c {l_qrbill_data_#1AddressType_tl}} { {K} { \tl_use:c {l_qrbill_data_#1Address1_tl} \tl_if_empty:cF {l_qrbill_data_#1Address2_tl} { \ifhmode\\\fi \tl_if_empty:cF {l_qrbill_data_#1Country_tl} {\tl_use:c {l_qrbill_data_#1Country_tl}-} \tl_use:c {l_qrbill_data_#1Address2_tl} } } }{ \tl_use:c {l_qrbill_data_#1Address1_tl}~ \tl_use:c {l_qrbill_data_#1Address2_tl} \tl_if_empty:cF {l_qrbill_data_#1City_tl} { \ifhmode\\\fi \tl_if_empty:cF {l_qrbill_data_#1Country_tl} {\tl_use:c {l_qrbill_data_#1Country_tl}-} \tl_use:c {l_qrbill_data_#1PostalCode_tl}~ \tl_use:c {l_qrbill_data_#1City_tl} } } } \cs_new:Nn \__qrbill_sep_tl:nn { \int_compare:nTF {\int_use:c {g__qrbill_#1sep_int} = 0} { #2 }{ \str_set:Nn \l_tmpa_str {#2} \int_compare:nT {\int_use:c {g__qrbill_#1sep_int} < 0} { \tl_reverse:N \l_tmpa_str } \int_set:Nn \l_tmpb_int {\int_abs:n {\int_use:c {g__qrbill_#1sep_int}}} \int_set:Nn \l_tmpa_int {1} \tl_clear:N \l_tmpa_tl \int_while_do:nNnn {\l_tmpa_int} < {\str_count:N \l_tmpa_str - \l_tmpb_int +1 } { \tl_put_right:Nx \l_tmpa_tl { \str_range:Nnn \l_tmpa_str {\l_tmpa_int} {\l_tmpa_int + \l_tmpb_int-1} } \int_add:Nn \l_tmpa_int {\l_tmpb_int} \tl_put_right:Nn \l_tmpa_tl {{\tl_use:c {g__qrbill_#1sep_tl}}} } \tl_put_right:Nx \l_tmpa_tl { \str_range:Nnn \l_tmpa_str {\l_tmpa_int} {\str_count:N \l_tmpa_str} } \int_compare:nT {\int_use:c {g__qrbill_#1sep_int} < 0} { \tl_reverse:N \l_tmpa_tl } \l_tmpa_tl } } \cs_generate_variant:Nn \__qrbill_sep_tl:nn {nV} \newcommand*{\insertdebtor}{\null\qrbill_insert_address:N \g__qrbill_debtorprefix_tl} \newcommand*{\insertcreditor}{\null\qrbill_insert_address:N \g__qrbill_creditorprefix_tl} \newcommand*{\insertcurrency}{\l_qrbill_data_Currency_tl} \keys_define:nn {qrbill/data} { creditor .code:n = \qrbill_set_address_combined:nn {\g__qrbill_creditorprefix_tl}{#1}, creditor* .code:n = \qrbill_set_address_structured:nn {\g__qrbill_creditorprefix_tl} {#1}, debtor .code:n = \qrbill_set_address_combined:nn {\g__qrbill_debtorprefix_tl}{#1}, debtor* .code:n = \qrbill_set_address_structured:nn {\g__qrbill_debtorprefix_tl} {#1}, account .tl_set:N = \l_qrbill_iban_tl, } \clist_map_inline:nn {AV1, AV2} { \keys_define:nn {qrbill/data} { #1 .code:n = { \tl_if_empty:nF {##1}{ \exp_args:Nnx \keys_set:nn {qrbill/data} { #1-Parameters={\qrbill_av_prefix:n {#1}##1} } } \tl_set:cn {l_qrbill_#1_tl} {##1} }, #1 .initial:n =, } } \newcommand*{\SetupQrBill}[1]{ \bool_if:NTF \g__qrbill_to_string_bool { \exp_args:Nnx \keys_set:nn {qrbill/data} {\tl_to_str:n {#1}} } { \keys_set:nn {qrbill/data} {#1} } } \str_new:N \l_qrbill_data_str \cs_new:Nn \qrcode_setup_QRcode: { \str_clear:N \l_qrbill_data_str \bool_set_false:N \l_tmpa_bool \seq_map_inline:Nn \g__qrbill_qrscheme_seq { \clist_if_in:NnTF \g__qrbill_ignore_if_empty_clist {##1} { \tl_if_empty:cTF {l_qrbill_data_##1_tl} \use_none:n \use:n } \use:n { \bool_if:NTF \l_tmpa_bool {\str_put_right:Nn\l_qrbill_data_str {^^J}} {\bool_set_true:N \l_tmpa_bool} \exp_args:NNv \str_put_right:Nn \l_qrbill_data_str {l_qrbill_data_##1_tl} } } %necessary to preserve spaces! \bool_if:NF \g__qrbill_luamode_bool { \str_replace_all:Nnn \l_qrbill_data_str {~ } {\ } } \prop_map_inline:Nn \g__qrbill_replacement_prop { \str_replace_all:Nnn \l_qrbill_data_str {##1} {##2} } \tl_set_rescan:Nno \l_qrbill_data_str {\ExplSyntaxOff} {\l_qrbill_data_str} } \seq_new:N \g__qrbill_qrscheme_seq \newcommand*\SetQrScheme[1]{ \seq_gset_from_clist:Nn \g__qrbill_qrscheme_seq {#1} \seq_map_inline:Nn \g__qrbill_qrscheme_seq { \keys_define:nn {qrbill/data} { ##1 .tl_set:c = l_qrbill_data_##1_tl, ##1 .initial:n =, } } } \prop_new:N \g__qrbill_billing_info_prop \seq_new:N \g__qrbill_billing_info_seq \clist_new:N \g__qrbill_billing_info_static_clist \newcommand*{\SetStaticData}[1]{\clist_gset:Nx \g__qrbill_billing_info_static_clist {\tl_to_str:n {#1}}} \newcommand*{\SetBillingInfoScheme}[1]{ \prop_gset_from_keyval:Nn \g__qrbill_billing_info_prop {#1} \seq_gclear:N \g__qrbill_billing_info_seq \prop_map_inline:Nn \g__qrbill_billing_info_prop { \clist_if_in:NnF \g__qrbill_billing_info_static_clist {##1} { \seq_push:Nn \g__qrbill_billing_info_seq {##1} } \keys_define:nn {qrbill/data} { ##2 .tl_set:c = l_qrbill_##2_tl, ##2 .initial:n =, } } \seq_if_empty:NF \g__qrbill_billing_info_seq { \prop_map_inline:Nn \g__qrbill_billing_info_prop { \clist_if_in:NnT \g__qrbill_billing_info_static_clist {##1} { \exp_args:Nx \clist_if_in:nnF {\tl_to_str:n {prefix , postfix}} {##1} { \seq_push:Nn \g__qrbill_billing_info_seq {##1} } } } } \seq_sort:Nn \g__qrbill_billing_info_seq { \int_compare:nNnTF { ##1 } > { ##2 } { \sort_return_swapped: } { \sort_return_same: } } } \tl_new:N \l_qrbill_data_BillingInfo_tl \cs_new:Nn \qrbill_parse_BillingInfo: { \bool_if:NT \g__grbill_billinginfo_auto_bool { \str_put_right:Nx \l_qrbill_data_BillingInfo_tl { \prop_item:Nn \g__qrbill_billing_info_prop {prefix} } \seq_map_inline:Nn \g__qrbill_billing_info_seq { \prop_get:NnN \g__qrbill_billing_info_prop {##1} \l_tmpa_tl \tl_if_empty:cF {l_qrbill_\l_tmpa_tl _tl} { \str_put_right:Nx \l_qrbill_data_BillingInfo_tl { /##1/\tl_use:c {l_qrbill_\l_tmpa_tl _tl} } } } } } \cs_set:Nn \qrbill_parse_date:nnn { #1- \int_compare:nNnT {#2} < {10} {0}#2- \int_compare:nNnT {#3} < {10} {0}#3 } \cs_generate_variant:Nn \qrbill_parse_date:nnn {eee} \cs_set:Npn \QRbillParseDate #1#2#3 { \qrbill_parse_date:eee {#1}{#2}{#3} } \cs_new:Nn \qrbill_insert_AV_parameters:NNn { \clist_map_inline:nn {#3} { \tl_if_empty:cF {l_qrbill_##1_tl} {{#1\qrbill_av_prefix:n {##1}}{#2 \tl_use:c {l_qrbill_##1_tl}}} } } \cs_new:Nn \qrbill_av_prefix:n {Name~#1:~} \input{\g__qrbill_qrscheme_tl.qrbill-cfg} \endinput %% %% End of file `qrbill.sty'.