]> git.plutz.net Git - invoices/blob - invoices.cgi
cc505d4c52f3f09f7b9296811405f4b58906d551
[invoices] / invoices.cgi
1 #!/bin/sh
2
3 _EXEC="$(realpath "${0%/*}")"
4 . "$_EXEC/cgilite/cgilite.sh"
5 . "$_EXEC/cgilite/logging.sh"
6 . "$_EXEC/cgilite/storage.sh"
7 . "$_EXEC/cgilite/session.sh"
8
9 yield_page(){
10 printf 'Content-Type: text/html; charset=utf-8\r\n\r\n'
11 ./cgilite/html-sh.sed <<EOF
12 [html [head
13   [meta name="viewport" content="width=device-width"]
14   [link rel="stylesheet" type="text/css" href="/invoices.css"]
15   [title Invoices]
16 ] [body class="$1"
17   [div #menu
18     [a "/invoices/" Invoices]
19     [a "/clients/" Clients]
20     [a "/senders/" Senders]
21   ]
22   $(cat)
23 ] ]
24 EOF
25 }
26
27 edit_client(){
28   id="$1"
29   if [ -f "clients/$id" ]; then
30     read -r address hourly <"clients/$id"
31   fi
32   [ "$address" ] || address="address="
33   [  "$hourly" ] ||  hourly="hourly="
34   printf '
35     [form method="POST" action="/update_client"
36       [hidden "id" "%s"]
37       <textarea name="address" placeholder="address">
38 %s</textarea>
39       [label for=hourly Hourly Rate:]
40       [input #hourly type=number name=hourly value="%s"]
41       [submit "update" "update" Update]
42     ]' \
43     "$(HTML $id)" \
44     "$(UNSTRING "${address#address=}" |HTML)" \
45     "$(UNSTRING "${hourly#hourly=}" |grep -xE '[0-9]+')"
46 }
47
48 edit_sender(){
49   id="$1"
50   if [ -f "senders/$id" ]; then
51     address="$(cat "senders/$id")"
52   fi
53   [ "$address" ] || address="Name
54 Street
55 City
56
57 Phone:
58 000 000000
59
60 Tax no.
61 xxx / 000 / ###
62 "
63   printf '
64     [form method="POST" action="/update_sender"
65       [hidden "id" "%s"]
66       <textarea name="address" placeholder="address">%s</textarea>
67       [submit "update" "update" Update]
68     ]' \
69     "$(HTML $id)" \
70     "$(HTML "${address}")"
71 }
72
73 list_clients(){
74   [ -d clients/ ] && for c in clients/*; do
75     read -r address hourly <"$c"
76     address="$(UNSTRING "${address#address=}")"
77     [ "$address" ] || address="(no address)"
78     printf '[div .client .address <!--
79       -->%s
80
81 [label Hourly Rate:] %s€
82     [a href="/clients/%s" Edit]]
83     ' "$(HTML "$address")" \
84       "$(HTML "${hourly#hourly=}")" \
85       "$(HTML "${c#clients/}")"
86   done
87 }
88
89 list_senders(){
90   [ -d senders/ ] && for s in senders/*; do
91     address=$(cat "$s")
92     [ "$address" ] || address="(no address)"
93     printf '[div .sender .address <!--
94       -->%s[a href="/senders/%s" Edit]]
95     ' "$(HTML "$address")" "$(HTML "${s#senders/}")"
96   done
97 }
98
99 sender_list(){
100   local select="$1" n name
101   [ -d senders/ ] && for n in '' senders/*; do
102     [ "$n" ] && name="$(sed q "$n" |HTML)"
103     [ "${n#senders/}" = "$select" ] \
104     && printf '<option value="%s" selected=selected>%s</option>' "${n#senders/}" "$name" \
105     || printf '<option value="%s">%s</option>' "${n#senders/}" "$name"
106   done
107 }
108
109 client_list(){
110   local select="$1" n address hourly name
111   [ -d clients/ ] && for n in '' clients/*; do
112     [ "$n" ] && read -r address hourly <"$n"
113     name="$(UNSTRING "${address#address=}" |sed q |HTML)"
114     [ "${n#clients/}" = "$select" ] \
115     && printf '<option value="%s" selected=selected>%s</option>' "${n#clients/}" "$name" \
116     || printf '<option value="%s">%s</option>' "${n#clients/}" "$name"
117   done
118 }
119
120 list_invoices(){
121   [ -d invoices/ ] && for i in invoices/*; do
122     read -r sender client date number vat vatrate<<-EOF
123         $(sed q "$i")
124         EOF
125     [ -f "senders/${sender#sender=}" ] \
126     && sender="$(sed q "senders/${sender#sender=}")" \
127     || sender="(unset)"
128     [ ! -f "clients/${client#client=}" ] \
129     && client="(unset)" \
130     || read -r client hourly <"clients/${client#client=}"
131     [ "${date#date=}" -ge 0 ] 2>&- \
132     && date="$(date -d "@${date#date=}" +%x)" \
133     || date="(unset)"
134
135     printf '[div .invoice
136       [h2
137           %s]
138       [label From:] %s [label To:] %s [label on] %s
139       [a href="/invoice/%s" Edit]
140     ]' "$(UNSTRING "${number#number=}" |HTML)" \
141        "$(HTML "$sender")" \
142        "$(UNSTRING "${client#address=}" |sed q |HTML)" "$(HTML "$date")" \
143        "$(HTML ${i#invoices/})"
144   done
145 }
146
147 edit_invoice(){
148   id="$1"
149   if [ -f "invoices/$id" ]; then
150     read -r sender client date number vat vatrate<<-EOF
151         $(sed q "invoices/$id")
152         EOF
153   fi
154
155   [ "${date#date=}" -ge 0 ] 2>&- \
156   && date="$(date -d "@${date#date=}" +%F)" \
157   || date="$(date +%F)"
158   [ "${number#number=}" ] || number="number=$(date +%s)"
159   [ "${vatrate#vatrate=}" -ge 0 ] 2>&- || vatrate="vatrate=19"
160
161   cat <<-EOF 
162         [form method="POST" action="/update_invoice"
163           [hidden "id" "$(HTML "$id")"]
164
165           [label Sender:]
166           [select name=sender
167             $(sender_list "${sender#sender=}")
168           ]
169
170           [label Client:]
171           [select name=client
172             $(client_list "${client#client=}")
173           ]
174         
175           [label for=number Invoice Number:]
176           [input #number name=number value="$(UNSTRING "${number#number=}" |HTML)"]
177
178           [label for=date Date:]
179           [input #date name=date value="${date}" placeholder="YYYY-MM-TT"]
180
181           [radio "vat" "smallbusiness" #vatsb $([ "${vat#vat=}" = smallbusiness ] && printf checked) ]
182           [label for=vatsb Small business exemption from VAT]
183           [radio "vat" "nett" #vatnett $([ "${vat#vat=}" = nett ] && printf checked)]
184           [label for=vatnett Nett]
185           [radio "vat" "gross" #vatgross $([ "${vat#vat=}" = gross ] && printf checked)]
186           [label for=vatgross Gross]
187           [label for=vatrate VAT Rate: [input type=number name="vatrate" value="${vatrate#vatrate=}"]% ]
188
189           [table
190             [tr [th Date] [th Work] [th Hours] [th Price] ]
191 $({ sed 1d "invoices/$id"; printf 'time= work= hours=\n'; } \
192     | while read -r time work hours; do
193       hours="$(UNSTRING "${hours#hours=}" |grep -m1 -xE '[0-9]+' || printf 0)"
194       printf '[tr
195               [td [textarea name=date
196 %s] ]
197               [td [textarea name=work
198 %s] ]
199               [td [input type=number name=hours value="%s"] ]
200               [td %s]
201      ]' "$(UNSTRING "${time#time=}" |HTML)" \
202         "$(UNSTRING "${work#work=}" |HTML)" \
203         "$hours" "$((hours * hourly)) €"
204     done
205 )
206           ]
207           [submit "update" "update" Update]
208         ]
209         EOF
210 }
211
212 info="$(PATH "${PATH_INFO}")"
213
214 case $info in
215   /invoices.css)
216     . "$_EXEC/cgilite/file.sh"
217     FILE "$_EXEC/invoices.css"
218     ;;
219   /clients)
220     { list_clients
221       printf '[a .new href="/clients/%s" New]' "$(timeid)"
222     } | yield_page clients
223     ;;
224   /clients/*)
225     edit_client "${info#/clients/}" |yield_page client
226     ;;
227   /update_client)
228     id="$(POST id |checkid)"
229     if [ "$(POST update)" = update -a "$id" ]; then
230       mkdir -p clients
231       printf 'address=%s        hourly=%s' \
232         "$(POST address |STRING)" "$(POST hourly |STRING)" \
233         >"clients/$id"
234     else
235       echo Invalid Data "$(POST id)" "$(POST update)" >&2
236     fi
237     REDIRECT /clients/
238     ;;
239   /senders)
240     { list_senders
241       printf '[a .new href="/senders/%s" New]' "$(timeid)"
242     } | yield_page senders
243     ;;
244   /senders/*)
245     edit_sender "${info#/senders/}" |yield_page sender
246     ;;
247   /update_sender)
248     id="$(POST id |checkid)"
249     if [ "$(POST update)" = update -a "$id" ]; then
250       mkdir -p senders
251       POST address >"senders/$id"
252     fi
253     REDIRECT /senders/
254     ;;
255   /invoices)
256     { list_invoices
257       printf '[a .new href="/invoice/%s" New]' "$(timeid)"
258     } | yield_page invoices
259     ;;
260   /invoice/*)
261     edit_invoice "${info#/invoice/}" |yield_page invoice
262     ;;
263   /update_invoice)
264     id="$(POST id |checkid)"
265     if [ "$(POST update)" = update -a "$id" ]; then
266       mkdir -p invoices
267       printf 'sender=%s client=%s       date=%s number=%s       vat=%s  vatrate=%s\n' \
268         "$(POST sender)" "$(POST client)" \
269         "$(date -d "$(POST date)" +%s)" \
270         "$(POST number |STRING)" \
271         "$(POST vat |grep -m1 -xE 'smallbusiness|gross|nett')" \
272         "$(POST vatrate |grep -m1 -xE '[0-9]+')" \
273       >"invoices/$id"
274     fi
275     REDIRECT "/invoice/$id"
276     ;;
277   *) REDIRECT /invoices
278     ;;
279 esac