]> git.plutz.net Git - invoices/blob - invoices.sh
9e07e9fab11ffbec85a9d97fbd37c31c02f59e94
[invoices] / invoices.sh
1 #!/bin/sh
2
3 sender_list(){
4   local select="$1" n name
5   [ -d senders/ ] && for n in '' senders/*; do
6     [ "$n" ] && name="$(sed q "$n" |HTML)"
7     [ "${n#senders/}" = "$select" ] \
8     && printf '<option value="%s" selected=selected>%s</option>' "${n#senders/}" "$name" \
9     || printf '<option value="%s">%s</option>' "${n#senders/}" "$name"
10   done
11 }
12
13 client_list(){
14   local select="$1" n address hourly name
15   [ -d clients/ ] && for n in '' clients/*; do
16     [ "$n" ] && read -r address hourly <"$n"
17     name="$(UNSTRING "${address#address=}" |sed q |HTML)"
18     [ "${n#clients/}" = "$select" ] \
19     && printf '<option value="%s" selected=selected>%s</option>' "${n#clients/}" "$name" \
20     || printf '<option value="%s">%s</option>' "${n#clients/}" "$name"
21   done
22 }
23
24 list_invoices(){
25   [ -d invoices/ ] && for i in invoices/*; do
26     read -r sender client date number vat vatrate<<-EOF
27         $(sed q "$i")
28         EOF
29     [ -f "senders/${sender#sender=}" ] \
30     && sender="$(sed q "senders/${sender#sender=}")" \
31     || sender="(unset)"
32     [ ! -f "clients/${client#client=}" ] \
33     && client="(unset)" \
34     || read -r client hourly <"clients/${client#client=}"
35     [ "${date#date=}" -ge 0 ] 2>&- \
36     && date="$(date -d "@${date#date=}" +%x)" \
37     || date="(unset)"
38
39     printf '[div .invoice
40       [h2
41           %s]
42       [label From:] %s [label To:] %s [label on] %s
43       [label Amount:] %.2f €
44       [a href="/invoices/%s" Edit]
45     ]' "$(UNSTRING "${number#number=}" |HTML)" \
46        "$(HTML "$sender")" \
47        "$(UNSTRING "${client#address=}" |sed q |HTML)" "$(HTML "$date")" \
48        "$(invoice_total "${i#invoices/}")" \
49        "$(HTML ${i#invoices/})"
50   done
51 }
52
53 edit_invoice(){
54   local id="$1" sender client date number vat vatrate caddress hourly total
55   if [ -f "invoices/$id" ]; then
56     read -r sender client date number vat vatrate<<-EOF
57         $(sed q "invoices/$id")
58         EOF
59   fi
60
61   [ "${date#date=}" -ge 0 ] 2>&- \
62   && date="$(date -d "@${date#date=}" +%F)" \
63   || date="$(date +%F)"
64   [ "${number#number=}" ] \
65   && number="${number#number=}" \
66   || number="$(date +%s)"
67   [ "${vatrate#vatrate=}" -ge 0 ] 2>&- \
68   && vatrate="${vatrate#vatrate=}" \
69   || vatrate=19
70
71   [ -f "clients/${client#client=}" ] \
72   && read -r caddress hourly <"clients/${client#client=}"
73   hourly="${hourly#hourly=}"
74
75   total=$(invoice_total "$id")
76
77   cat <<-EOF 
78         [form method="POST" action="/update_invoice"
79           [hidden "id" "$(HTML "$id")"]
80         
81           [label Sender:]
82           [select name=sender
83             $(sender_list "${sender#sender=}")
84           ]
85         
86           [label Client:]
87           [select name=client
88             $(client_list "${client#client=}")
89           ]
90         
91           [label for=number Invoice Number:]
92           [input #number name=number value="$(UNSTRING "${number}" |HTML)"]
93         
94           [label for=date Date:]
95           [input #date name=date value="${date}" placeholder="YYYY-MM-TT"]
96         
97           [radio "vat" "smallbusiness" #vatsb $([ "${vat#vat=}" = smallbusiness ] && printf checked) ]
98           [label for=vatsb Small business exemption from VAT]
99           [radio "vat" "nett" #vatnett $([ "${vat#vat=}" = nett ] && printf checked)]
100           [label for=vatnett Nett]
101           [radio "vat" "gross" #vatgross $([ "${vat#vat=}" = gross ] && printf checked)]
102           [label for=vatgross Gross]
103           [label for=vatrate VAT Rate: [input type=number name="vatrate" value="${vatrate}"]% ]
104         
105           [table
106             [tr [th Date] [th Work] [th Hours] [th Price] ]
107 $({ sed 1d "invoices/$id"; printf 'time= work= hours=\n'; } \
108   | while read -r time work hours; do
109     hours="$(UNSTRING "${hours#hours=}" |grep -m1 -xE '[0-9]+' || printf 0)"
110     printf '[tr
111             [td [textarea name=time
112 %s] ]
113             [td [textarea name=work
114 %s] ]
115             [td [input type=number name=hours value="%s"] ]
116             [td %s]
117    ]' "$(UNSTRING "${time#time=}" |HTML)" \
118       "$(UNSTRING "${work#work=}" |HTML)" \
119       "$hours" "$((hours * hourly)) €"
120   done
121 )
122             [tr [td colspan=4 
123             $(case $vat in
124               vat=nett)
125                 awk "BEGIN {
126                   printf \"Sum: %7.2f €<br/> + VAT: %7.2f €<br/> [strong Total:] %7.2f €\",
127                    $total, int($total * $vatrate + .5) / 100,
128                    $total + int($total * $vatrate + .5) / 100
129                 }" ;;
130               vat=gross)
131                 awk "BEGIN {
132                   printf \"[strong Total:] %7.2f €<br/> incl VAT: %7.2f €<br/>+ nett: %7.2f €\",
133                    $total, int($total / (100 + $vatrate) * $vatrate * 100 + .5) / 100,
134                    $total - int($total / (100 + $vatrate) * $vatrate * 100 + .5) / 100
135                 }" ;;
136               *) printf '[strong Total:] %.2f €' "$total" ;;
137             esac)
138             ]]
139           ]
140           [submit "update" "$(tid "invoices/$id")" Update]
141         ]
142         EOF
143 }
144
145 invoice_total(){
146   local id="$1" sender client date number vat vatrate \
147         total=0 caddress hourly time work hours
148
149   if [ -f "invoices/$id" ]; then
150     read -r sender client date number vat vatrate<<-EOF
151         $(sed q "invoices/$id")
152         EOF
153
154     [ -f "clients/${client#client=}" ] \
155     && read -r caddress hourly <"clients/${client#client=}"
156     [ "${hourly#hourly=}" -gt 0 ] 2>&- \
157     && hourly="${hourly#hourly=}" \
158     || hourly=0
159
160     sed 1d "invoices/$id" \
161     | { while read time work hours; do
162         [ "${hours#hours=}" -gt 0 ] 2>&- \
163         && hours="${hours#hours=}" \
164         || hours=0
165         total=$((total + hours * hourly))
166       done
167       printf %.2f\\n "$total"
168     }
169   else
170     printf %.2f\\n 0
171   fi
172 }
173
174 update_invoice(){
175   local id="$(POST id |checkid)" extra=0
176
177   if [ "$(POST update)" = "$(tid "invoices/$id")" ]; then
178     mkdir -p invoices
179
180     for n in "$(POST_COUNT time)" "$(POST_COUNT work)" "$(POST_COUNT hours)"; do
181       [ "$n" -gt "$extra" ] && extra="$n"
182     done
183
184     { printf 'sender=%s client=%s       date=%s number=%s       vat=%s  vatrate=%s\n' \
185         "$(POST sender)" "$(POST client)" \
186         "$(date -d "$(POST date)" +%s)" \
187         "$(POST number |STRING)" \
188         "$(POST vat |grep -m1 -xE 'smallbusiness|gross|nett')" \
189         "$(POST vatrate |grep -m1 -xE '[0-9]+')"
190       for n in $(seq 1 $extra); do
191         printf 'time=%s work=%s hours=%s\n' \
192           "$(POST time $n |STRING)" "$(POST work $n |STRING)" \
193           "$(POST hours $n |STRING)" \
194         | grep -xvF 'time=      work=   hours=0'
195       done
196     } >"invoices/$id"
197   fi
198   REDIRECT "/invoices/$id"
199 }