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