From 0f43b65d34a7da6db8e738b3f58cde0fe2e537d5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Paul=20H=C3=A4nsch?= Date: Wed, 14 Nov 2018 04:38:04 +0100 Subject: [PATCH] invoice head editing --- .gitignore | 4 ++ invoices.cgi | 118 +++++++++++++++++++++++++++++++++++++++++++++------ invoices.css | 81 ++++++++++++++++++++++++++++++++--- 3 files changed, 184 insertions(+), 19 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d3e532 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +clients/ +invoices/ +senders/ +.*.swp diff --git a/invoices.cgi b/invoices.cgi index d079ced..f1a90e0 100755 --- a/invoices.cgi +++ b/invoices.cgi @@ -37,7 +37,7 @@ printf 'Content-Type: text/html; charset=utf-8\r\n\r\n' ./cgilite/html-sh.sed <%s[a href="/clients/%s" Edit]] - ' "$(HTML "$address")" "$(HTML "${c#clients/}")" + -->%s + +[label Hourly Rate:] %s€ + [a href="/clients/%s" Edit]] + ' "$(HTML "$address")" \ + "$(HTML "${hourly#hourly=}")" \ + "$(HTML "${c#clients/}")" done } @@ -117,31 +122,102 @@ list_senders(){ done } +sender_list(){ + local select="$1" n name + [ -d senders/ ] && for n in '' senders/*; do + [ "$n" ] && name="$(sed q "$n" |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 <"$n" + name="$(UNSTRING "${address#address=}" |sed q |HTML)" + [ "${n#clients/}" = "$select" ] \ + && printf '' "${n#clients/}" "$name" \ + || printf '' "${n#clients/}" "$name" + done +} + list_invoices(){ [ -d invoices/ ] && for i in invoices/*; do read -r sender client date number vat<<-EOF - sed q "$i" + $(sed q "$i") EOF [ -f "senders/${sender#sender=}" ] \ && sender="$(sed q "senders/${sender#sender=}")" \ || sender="(unset)" - [ -f "clients/${client#client=}" ] \ - && client="$(sed q "client/${client#client=}")" \ - || client="(unset)" - [ "$date" -gt 0 ] \ - && date="$(date -d @$date +%x)" \ + [ ! -f "clients/${client#client=}" ] \ + && client="(unset)" \ + || read -r client hourly <"clients/${client#client=}" + [ "${date#date=}" -ge 0 ] 2>&- \ + && date="$(date -d "@${date#date=}" +%x)" \ || date="(unset)" printf '[div .invoice [h2 %s] [label From:] %s [label To:] %s [label on] %s - [a href="/invoices/%s" Edit] - ]' "$(HTML "$number")" "$(HTML "$sender")" \ - "$(HTML "$client")" "$(HTML "$date")" + [a href="/invoice/%s" Edit] + ]' "$(UNSTRING "${number#number=}" |HTML)" \ + "$(HTML "$sender")" \ + "$(UNSTRING "${client#address=}" |sed q |HTML)" "$(HTML "$date")" \ + "$(HTML ${i#invoices/})" done } +edit_invoice(){ + id="$1" + if [ -f "invoices/$id" ]; then + read -r sender client date number vat<<-EOF + $(sed q "invoices/$id") + EOF + fi + + [ "${date#date=}" -ge 0 ] 2>&- \ + && date="$(date -d "@${date#date=}" +%F)" \ + || date="$(date +%F)" + [ "${number#number=}" ] || number="number=$(date +%s)" + [ "${vat%=*}" = vat -a "${vat#vat=}" -ge 0 ] 2>&- \ + && vatrate="${vat#vat=}" \ + || vatrate=19 + + cat <<-EOF + [form method="POST" action="/update_invoice" + [hidden "id" "$(HTML "$id")"] + + [label Sender:] + [select name=sender + $(sender_list "${sender#sender=}") + ] + + [label Client:] + [select name=client + $(client_list "${client#client=}") + ] + + [label for=number Invoice Number:] + [input #number name=number value="$(UNSTRING "${number#number=}" |HTML)"] + + [label for=date Date:] + [input #date name=date value="${date}" placeholder="YYYY-MM-TT"] + + [radio "vat" "smallbusiness" #vatsb $([ "$vat" = smallbusiness ] && printf checked) ] + [label for=vatsb Small business exemption from VAT] + [radio "vat" "allgross" #vatgross $([ "$vat" = allgross ] && printf checked)] + [label for=vatgross All amounts are gross] + [radio "vat" "rate" #vatrate $([ "${vat%=*}" = vat ] && printf checked) ] + [label for=vatrate VAT Rate: [input type=number name="vatrate" value="${vatrate}"]% ] + + [submit "update" "update" Update] + ] + EOF +} + info="$(PATH "${PATH_INFO}")" case $info in @@ -187,11 +263,25 @@ case $info in ;; /invoices) { list_invoices - printf '[a href="/invoices/%s" New]' "$(timeid)" + printf '[a .new href="/invoice/%s" New]' "$(timeid)" } | yield_page invoices ;; /invoice/*) - edit_invoice "${info#/invoices/}" |yield_page invoice + edit_invoice "${info#/invoice/}" |yield_page invoice + ;; + /update_invoice) + id="$(POST id |checkid)" + if [ "$(POST update)" = update -a "$id" ]; then + mkdir -p invoices + vat="$(POST vat |grep -m1 -xE 'smallbusiness|allgross|rate' )" + printf 'sender=%s client=%s date=%s number=%s %s\n' \ + "$(POST sender)" "$(POST client)" \ + "$(date -d "$(POST date)" +%s)" \ + "$(POST number |STRING)" \ + "$([ "$vat" = rate ] && printf 'vat=%i' "$(POST vatrate)" || printf %s "$vat" )" \ + >"invoices/$id" + fi + REDIRECT "/invoice/$id" ;; *) REDIRECT /invoices ;; diff --git a/invoices.css b/invoices.css index d495fc8..3b7592b 100755 --- a/invoices.css +++ b/invoices.css @@ -8,6 +8,10 @@ body { color: black; background-color: white; } + + +/* ==================== MENU ==================== */ + #menu { margin: 0; padding: .5em 1em; border-bottom: 1px solid black; @@ -23,6 +27,10 @@ body { border-color: #888; } + +/* ==================== ADDRESS LISTS ==================== */ + +.invoices .invoice, .clients .address, .senders .address { display: inline-block; @@ -32,6 +40,24 @@ body { margin: 1em 0 0 1em; width: 20em; } +.invoices .invoice { + white-space: normal; +} +.invoices .invoice h2{ + display: block; + letter-spacing: .25em; + text-align: center; + margin-bottom: -.5em; + font-size: 1.125em; +} +.invoices .invoice label { + font-weight: bold; +} +.invoices .invoice label::before { + white-space: pre; + content: '\0A'; +} +.invoices .invoice a, .clients .address a, .senders .address a, a.new { @@ -42,6 +68,7 @@ a.new { padding: .125em 1em; border: 1px solid #08F; } +.invoices .invoice a:hover, .clients .address a:hover, .senders .address a:hover, a.new:hover { @@ -52,12 +79,22 @@ a.new { margin: 1em; } + +/* ==================== ADDRESS FORMS ==================== */ + +form select, form textarea, form input { - padding: .25em .5em; + padding: .125em .5em; background-color: #FFF; text-align: left; } +form input[type=number] { + width: 5em; + text-align: right; +} + +.invoice form, .client form, .sender form { position: relative; @@ -82,10 +119,7 @@ form input { text-align: right; font-weight: bold; } -.client form input#hourly { - min-width: 4em; width: 5em; - text-align: right; -} +.invoice form button[type=submit], .client form button[type=submit], .sender form button[type=submit] { display: block; @@ -95,3 +129,40 @@ form input { border-radius: .25em; border: 1px solid #08F; } + +/* ==================== INVOICE FORMS ==================== */ +.invoice form select { + display: inline-block; + min-width: 20em; + margin-bottom: .5em; +} + +.invoice form label { + font-weight: bold; + line-height: 2em; +} + +.invoice form label::before { + white-space: pre; + content: '\0A'; +} +.invoice form label:first-of-type::before { + content: ''; +} + +.invoice form input[type=radio] {display: none;} +.invoice form label[for^=vat] { + display: block; + text-align: left; + line-height: 1.5em; +} +.invoice form label[for^=vat]::before { + content: '[ ] '; +} +.invoice form input:checked + label[for^=vat]::before { + content: '[x] '; +} +.invoice form label[for=vatrate] { + float: left; + display: inline-block; +} -- 2.39.2