From 2e85d45e1787d23b122b538d5f4626c7317c0278 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Paul=20H=C3=A4nsch?= Date: Wed, 29 Nov 2023 19:29:59 +0100 Subject: [PATCH] improved DBM functions --- db23.sh | 84 ++++++++++++++ invoices.sh | 314 ---------------------------------------------------- odtgen.sh | 239 --------------------------------------- 3 files changed, 84 insertions(+), 553 deletions(-) create mode 100755 db23.sh delete mode 100755 invoices.sh delete mode 100755 odtgen.sh diff --git a/db23.sh b/db23.sh new file mode 100755 index 0000000..53cd543 --- /dev/null +++ b/db23.sh @@ -0,0 +1,84 @@ +#!/bin/sh + +. "$_EXEC/cgilite/storage.sh" + +DB2() { + local call data file key val seq + data="${BR}${1}${BR}" call="$2" + shift 2 + + case $call in + new|discard) + printf '\n' + ;; + open|load) file="$1" + cat "$file" || return 1 + ;; + count|check|contains) key="$(STRING "$1")" val='' seq=0 + val="${data##*${BR}${key} }" val="${val%%${BR}*}" + [ "$val" = '' ] || val="${val} " + while [ "$val" != '' ]; do + seq=$((seq + 1)) val="${val#* }" + done + printf "%i\n" "$seq" + [ $seq = 0 ] && return 1 + ;; + get) key="$(STRING "$1")" seq="${2:-1}" + val="${data##*${BR}${key} }" val="${val%%${BR}*}" + [ "$val" = '' ] && return 1 || val="${val} " + while [ $seq -gt 1 ]; do + seq=$((seq - 1)) val="${val#* }" + done + [ "$val" = '' ] && return 1 + UNSTRING "${val%% *}" + ;; + iterate|raw) key="$(STRING "$1")" + val="${data##*${BR}${key} }" val="${val%%${BR}*}" + [ "$val" = '' ] && return 1 + printf '%s\n' $val + ;; + delete|remove) key="$(STRING "$1")" + val="${data#*${BR}${key} *${BR}}" + key="${data%${BR}${key} *${BR}*}" + [ "${key}${BR}${val}" = "${data}" ] && return 1 + printf '%s' "${key#${BR}}${BR}${val%${BR}}" + ;; + set|store) key="$(STRING "$1")" val="" + shift 1 + val="$(for v in "$@"; do STRING "$v"; printf \\t; done)" + if [ "${data#${BR}${key} *}" != "$data" ]; then + data="${data%${BR}${key} *${BR}*}${BR}${key} ${val% }${BR}${data#*${BR}${key} *${BR}}" + data="${data#${BR}}" data="${data%${BR}}" + else + data="${data#${BR}}${key} ${val% }${BR}" + fi + printf %s\\n "${data}" + ;; + flush|save|write) file="$1" + data="${data#${BR}}" data="${data%${BR}}" + if LOCK "$file"; then + printf '%s\n' "$data" >"$file" + RELEASE "$file" + else + return 1 + fi + ;; + esac + return 0 +} + +DB3() { + # wrapper function that allows easyer use of DB2 + # by always keeping file data in $db3_data + + case "$1" in + new|discard|open|load|delete|remove|set|store) + db3_data="$(DB2 "$db3_data" "$@")" + return "$?" + ;; + get|count|check|contains|iterate|raw|flush|save|write) + DB2 "$db3_data" "$@" + return "$?" + ;; + esac +} diff --git a/invoices.sh b/invoices.sh deleted file mode 100755 index 072b5b7..0000000 --- a/invoices.sh +++ /dev/null @@ -1,314 +0,0 @@ -#!/bin/sh - -sender_list(){ - local select="$1" n name address iban bic - [ -d senders/ ] && for n in '' senders/*; do - [ "$n" ] && read -r address iban bic x<"$n" - name="$(UNSTRING "${address#address=}" |sed q |HTML)" - [ "${n#senders/}" = "$select" ] \ - && printf '' "${n#senders/}" "$name" \ - || printf '' "${n#senders/}" "$name" - done -} - -client_list(){ - local select="$1" n address hourly name - [ -d clients/ ] && for n in '' clients/*; do - [ "$n" ] && read -r address hourly x<"$n" - name="$(UNSTRING "${address#address=}" |sed q |HTML)" - [ "${n#clients/}" = "$select" ] \ - && printf '' "${n#clients/}" "$name" \ - || printf '' "${n#clients/}" "$name" - done -} - -list_invoices(){ - [ -d invoices/ ] || return 0 - - printf '[h1 Offen]' - for i in invoices/*; do case "$(sed 1q <$i)" in - *status=open*) list_invoice "$i";; - *status=*) :;; - *) list_invoice "$i";; - esac; done - - for n in resent:Erinnert sent:Verschickt paid:Bezahlt cancelled:Storniert; do - printf '[h1 %s]' "${n#*:}" - for i in invoices/*; do case "$(sed 1q <$i)" in - *status=${n%:*}*) list_invoice "$i";; - esac; done - done -} - -list_invoice(){ - local i="$1" - local sender client date number vat vatrate iban bic hourly \ - taxtype nett tax gross total status - - read -r sender client date number vat vatrate hourly status x<<-EOF - $(sed q "$i") - EOF - - [ ! -f "senders/${sender#sender=}" ] \ - && sender="(unset)" \ - || read -r sender iban bic x<"senders/${sender#sender=}" - - [ ! -f "clients/${client#client=}" ] \ - && client="(unset)" \ - || read -r client hourly x<"clients/${client#client=}" - - [ "${date#date=}" -ge 0 ] 2>&- \ - && date="$(date -d "@${date#date=}" +%x)" \ - || date="(unset)" - - read -r taxtype nett tax gross x<<-EOF - $(invoice_total "${i#invoices/}") - EOF - case $taxtype in - nett) total="${nett} € + VAT";; - gross) total="${gross} € incl. VAT";; - *) total="${gross} €";; - esac - - case $status in - status=sent|status=resent|status=paid|status=cancelled) - status="${status#status=}" - ;; - *) status=open;; - esac - - printf '[div .invoice - [h2 - %s] - [label Von:] %s [label An:] %s [label am] %s - [label Über:] %s - [a href="/invoices/%s" Edit] - ]' "$(UNSTRING "${number#number=}" |HTML)" \ - "$(UNSTRING "${sender#address=}" |sed q |HTML)" \ - "$(UNSTRING "${client#address=}" |sed q |HTML)" "$(HTML "$date")" \ - "$total" \ - "$(HTML ${i#invoices/})" -} - -edit_invoice(){ - local id="$1" sender client date number vat vatrate caddress hourly \ - taxtype nett tax gross status novatreason - - if [ -f "invoices/$id" ]; then - read -r sender client date number vat vatrate hourly status novatreason x<<-EOF - $(sed q "invoices/$id") - EOF - fi - - case $status in - status=sent|status=resent|status=paid|status=cancelled) - status="${status#status=}" - ;; - *) status=open;; - esac - - [ "${date#date=}" -ge 0 ] 2>&- \ - && date="$(date -d "@${date#date=}" +%F)" \ - || date="$(date +%F)" - [ "${number#number=}" ] \ - && number="${number#number=}" \ - || number="$(date +%s)" - [ "${vatrate#vatrate=}" -ge 0 ] 2>&- \ - && vatrate="${vatrate#vatrate=}" \ - || vatrate=19 - - [ -f "clients/${client#client=}" ] \ - && read -r caddress chourly x<"clients/${client#client=}" - [ "${chourly#hourly=}" -ge 0 ] 2>&- \ - && chourly="${chourly#hourly=}" \ - || chourly=0 - [ "${hourly#hourly=}" -ge 0 ] 2>&- \ - && hourly="${hourly#hourly=}" \ - || hourly="${chourly}" - - novatreason="$(UNSTRING "${novatreason#novatreason=}")" - - tid="$(transid "invoices/$id")" - - read -r taxtype nett tax gross x<<-EOF - $(invoice_total "$id") - EOF - - - cat <<-EOF - [form method="POST" action="/update_invoice" - [hidden "id" "$(HTML "$id")"] - - [label Absender:] - [select name=sender - $(sender_list "${sender#sender=}") - ] - - [label Klient:] - [select name=client - $(client_list "${client#client=}") - ] - - [label for=number Rechnungsnummer:] - [input #number name=number value="$(UNSTRING "${number}" |HTML)"] - - [label for=date Datum:] - [input #date name=date value="${date}" placeholder="YYYY-MM-TT"] - - - - [table - [tr [th Stück] [th Leistung] [th Stückpreis] [th Summe] ] -$({ sed 1d "invoices/$id"; printf 'time= work= hours=\n'; } \ - | while read -r time work hours pcs ppp x; do - pcs="$(UNSTRING "${pcs#pcs=}" \ - |grep -m1 -xE '[0-9]+' || printf 1)" - ppp="$(UNSTRING "${ppp#ppp=}" \ - |grep -m1 -xEe '-?(\.[0-9]+|[0-9]+\.?[0-9]*)' || printf 0)" - printf '[tr - [td [input type=number name=pieces value="%i" step=1] ] - [td [textarea name=work -%s] ] - [td [input type=number name=price value="%g" step=any] ] - [td %s] - ]' "$pcs" "$(UNSTRING "${work#work=}" |HTML)" "$ppp" \ - "$(awk "BEGIN { printf \"%.2f €\", ${pcs} * ${ppp}; }")" - done -) - [tr [td colspan=4 - $(case $taxtype in - (nett) printf 'Summe: %7.2f €[br] + USt.: %7.2f €[br] [strong Gesamt:] %7.2f €' \ - $nett $tax $gross ;; - (gross) printf '[strong Gesamt:] %7.2f €[br] incl. nett: %7.2f €[br] + USt.: %7.2f €' \ - $gross $nett $tax ;; - (*) printf '[strong Gesamt:] %.2f €' $nett ;; - esac) - ]] - ] - - - [radio "vat" "novat" #vatfree $([ "${vat#vat=}" = novat ] && printf checked) ] - [label for=vatfree [input type="text" name=novatreason value="${novatreason:-"Der Rechnungsbetrag ist nach §4 Abs. 25 UStG. umsatzsteuerfrei"}"]] - [radio "vat" "nett" #vatnett $([ "${vat#vat=}" = nett ] && printf checked)] - [label for=vatnett Netto] - [radio "vat" "gross" #vatgross $([ "${vat#vat=}" = gross ] && printf checked)] - [label for=vatgross Brutto] - [label for=vatrate USt.: [input type=number name="vatrate" value="${vatrate}"]% ] - [select name=status - [option value=open $( [ $status = open ] && printf selected=selected ) Offen] - [option value=sent $( [ $status = sent ] && printf selected=selected ) Verschickt] - [option value=resent $( [ $status = resent ] && printf selected=selected ) Erinnert] - [option value=paid $( [ $status = paid ] && printf selected=selected ) Bezahlt] - [option value=cancelled $( [ $status = cancelled ] && printf selected=selected ) Storniert] - ] - - [submit "genpdf" "$tid" PDF Exportieren] - [submit "update" "$tid" Aktualisieren] - ] - EOF -} - -invoice_total(){ - local id="$1" sender client date number vat vatrate \ - total=0 caddress hourly time work hours - - if [ -f "invoices/$id" ]; then - read -r sender client date number vat vatrate hourly x<<-EOF - $(sed q "invoices/$id") - EOF - - [ "${vatrate#vatrate=}" -ge 0 ] 2>&- \ - && vatrate="${vatrate#vatrate=}" \ - || vatrate=19 - - sed 1d "invoices/$id" \ - | { while read -r time work hours pcs ppp; do - pcs="$(UNSTRING "${pcs#pcs=}" \ - |grep -m1 -xE '[0-9]+' || printf 1)" - ppp="$(UNSTRING "${ppp#ppp=}" \ - |grep -m1 -xEe '-?(\.[0-9]+|[0-9]+\.?[0-9]*)' || printf 0)" - total=$(awk "BEGIN { printf \"%.2f\", ${total} + ${pcs} * ${ppp}; }") - done - case $vat in - vat=nett) - awk "BEGIN { - printf \"nett %.2f %.2f %.2f\", - $total, int($total * $vatrate + .5) / 100, - $total + int($total * $vatrate + .5) / 100 - }" ;; - vat=gross) - awk "BEGIN { - printf \"gross %.2f %.2f %.2f\", - $total - int($total / (100 + $vatrate) * $vatrate * 100 + .5) / 100, - int($total / (100 + $vatrate) * $vatrate * 100 + .5) / 100, $total - }" ;; - *) - awk "BEGIN { - printf \"notax %.2f %.2f %.2f\", - $total, 0, $total - }" ;; - esac - } - else - printf %.2f\\n 0 - fi -} - -update_invoice(){ - local id="$(POST id |checkid)" extra=0 tid - tid="$(transid invoices/$id)" - printf "Update\n" >&2 - - if [ "$(POST update)" = "$tid" ] || [ "$(POST genpdf)" = "$tid" ]; then - mkdir -p invoices - - for n in "$(POST_COUNT time)" "$(POST_COUNT work)" "$(POST_COUNT hours)" "$(POST_COUNT pieces)" "$(POST_COUNT price)"; do - [ "$n" -gt "$extra" ] && extra="$n" - done - - { printf 'sender=%s client=%s date=%s number=%s vat=%s vatrate=%s hourly=%s status=%s novatreason=%s\n' \ - "$(POST sender)" "$(POST client)" \ - "$(date -d "$(POST date)" +%s)" \ - "$(POST number |STRING)" \ - "$(POST vat |grep -m1 -xE 'smallbusiness|youthwork|gross|nett|novat')" \ - "$(POST vatrate |grep -m1 -xE '[0-9]+')" \ - "$(POST hourly |grep -m1 -xE '[0-9]+')" \ - "$(POST status |grep -m1 -xE 'open|sent|resent|paid|cancelled')" \ - "$(POST novatreason |STRING)" - for n in $(seq 1 $extra); do - printf 'time=%s work=%s hours=%s pcs=%s ppp=%s\n' \ - "$(POST time $n |STRING)" "$(POST work $n |STRING)" \ - "$(POST hours $n |STRING)" \ - "$(POST pieces $n |STRING)" "$(POST price $n |STRING)" \ - | grep -xvF 'time=\ work=\ hours=\ pcs=1 ppp=0' - done - } >"invoices/$id" - - [ -d .git ] && { - git add "invoices/$id" - git commit -m 'Update invoice info for "'"$(POST number)"'"' -- "invoices/$id" - } >/dev/null - else - printf "TID mismatch\n" >&2 - fi - if [ "$(POST genpdf)" ]; then - read -r sender client date x<"invoices/$id" - read -r saddress x <"senders/${sender#sender=}" - read -r caddress x <"clients/${client#client=}" - filename="Rechnung $(UNSTRING "${saddress#address=}" |sed 1q) an $(UNSTRING "${caddress#address=}" |sed 1q) $(date -d@"${date#date=}" +%F).pdf" - - . $_EXEC/odtgen.sh - genpdf "$id" - REDIRECT "/export/${id}.pdf/$(URL "${filename}" |sed s/%0D//g)" - exit 0 - fi - REDIRECT "/invoices/$id" -} diff --git a/odtgen.sh b/odtgen.sh deleted file mode 100755 index 9e60106..0000000 --- a/odtgen.sh +++ /dev/null @@ -1,239 +0,0 @@ -#!/bin/zsh - -html_content(){ - local id="$1" sender="$2" client="$3" date="$4" number="$5" vat="$6" vatrate="$7" hourly="$8" \ - taxtype nett tax gross date_due - - sender="$(HTML "$sender" |sed -E 's/ / • /g;')" - client="$(HTML "$client" |sed -E ':A; /(.* ){6}/!{ s/$/\ \ /; bA; }')" - - read -r taxtype nett tax gross <<-EOF - $(invoice_total "$id") - EOF - - [ "$vatrate" ] || vatrate=0 - date_due="$((date + 86400 * 28))" - - cat <<-EOF - - - - - - - - - - -

- ${sender}

-

- ${client}

-

- Rechnung - SI $(date -d @${date} +%y) ${number}

-

- $(date -d @${date} +%d.%m.%Y)

-

- Sehr - geehrte Damen und Herren,
Liebe Alle*,

-


-
- -

- - - - - - - - - - - - - - - - - - - - - - $(sed 1d "invoices/$id" |while read -r time work hours pcs ppp; do - work="$(UNSTRING "${work#work=}" |HTML |sed -E '$!s;$;
;;')" - pcs="$(UNSTRING "${pcs#pcs=}" \ - |grep -m1 -xE '[0-9]+' || printf 1)" - ppp="$(UNSTRING "${ppp#ppp=}" \ - |grep -m1 -xEe '-?(\.[0-9]+|[0-9]+\.?[0-9]*)' || printf 0)" - ppp="$(printf "%.2f" "$ppp")" - total=$(awk "BEGIN { printf \"%.2f\", ${pcs} * ${ppp}; }") - cat <<-ROW - - - - - - - - ROW - done) - $([ $taxtype != notax ] && cat <<-ROW - - - - - - - - ROW - ) - - - - - - - - -

- Anz.

-

-
- -

-

- Leistung

-

- Einzelpreis

-

- Summe

-

- ${pcs}

-

-
- -

-

- ${work}

-

- ${ppp} - €

-

- ${total} - €

-

-
- -

-

-
- -

-

- - $([ $taxtype = gross ] && printf "incl."; [ $taxtype = nett ] && printf "zzgl."; ) - ${vatrate}% MwSt.:

-

- - $([ $taxtype = gross ] && printf "$tax €";) -

-

- - $([ $taxtype = nett ] && printf "$tax €";) -

-

-
- -

-

-
- -

-

- Gesamtsumme:

-

-
- -

-

- $gross - €

-
-

-
-
- -

-

- Ich - bitte um Überweisung des Rechnungsbetrags bis zum $(date -d @${date_due} +%d.%m.%Y)

-


-
- -

-

Vielen - Dank für den Auftrag, die gute Zusammenarbeit und freundliche Grüße,

-


-
- -

-

Olaf - Schenckenberg

-


-
- -

-


-
- -

- $([ $taxtype = notax ] && cat <<-EOF -

- ${novatreason}

- EOF - ) - - - EOF -} - -genhtml(){ - local id="$1" - mkdir -p "export/" - - read -r sender client date number vat vatrate hourly status novatreason x<<-EOF - $(sed q "invoices/$id") - EOF - read -r sender iban bic x<"senders/${sender#sender=}" - read -r client chourly x<"clients/${client#client=}" - - html_content "$id" \ - "$(UNSTRING "${sender#address=}")" \ - "$(UNSTRING "${client#address=}")" \ - "${date#date=}" \ - "$(UNSTRING "${number#number=}")" \ - "${vat#vat=}" "${vatrate#vatrate=}" \ - "${hourly#hourly=}" \ - "$(UNSTRING "${novatreason#novatreason=}")" \ - >"export/$id.html" -} - -genpdf(){ - local id="$1" tmp="tmp$(randomid)" - genhtml "$id" - lowriter --convert-to pdf --outdir "export/" "export/${id}.html" >/dev/null - pdftk "export/${id}.pdf" background $_DATA/Background.pdf output "export/${tmp}.pdf" - mv -- "export/${tmp}.pdf" "export/${id}.pdf" - rm -- "export/${id}.html" -} - -- 2.39.5