-
Notifications
You must be signed in to change notification settings - Fork 0
/
lagerkasse.sh
executable file
·474 lines (419 loc) · 12.6 KB
/
lagerkasse.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
#!/bin/bash
# Lagerkasse (Getränkeverkauf, Einzahlung, Abrechnung).
printUsage() {
cat <<EOF
usage: $PROGNAME [options]
options:
-V
Verkauf nicht automatisch starten. Nützlich für Abrechnung der
Lagerkasse.
-P
Pfandrückgabe nicht automatisch starten. Nützlich bei Einzahlung in
Lagerkasse.
-c
Credit mode - we give credit to customers. They do not have to pay in
advance. Currently, the only effect of this option is that a warning is
omitted when a person's balance is less than a few Euros.
-K
Skip syntax check of files $PERSONS_FILE and $COMMODITIES_FILE on startup.
-f LEDGER_FILE
Ledger journal file - used to record book entries and passed to hledger.
If not specified, the environment variable LEDGER_FILE is used.
-h
Print help message.
EOF
}
set -o errexit -o pipefail
shopt -s nullglob
readonly PROGNAME=${0##*/}
readonly COMMODITY_PFANDFLASCHE=pfandflasche
readonly PERSONS_FILE=personen.txt
readonly COMMODITIES_FILE=artikel.txt
readonly REGEX_METACHAR_REGEX='[][(){}\^$*+?.|]'
# $1: error message
exitWithError() {
declare msg=${1:-}
echo "$msg" >&2
exit 1
}
# $*: command line arguments = "$@"
parseCommandLine() {
# declare options globally and readonly
declare option
while getopts 'hcKf:VP' option; do
case $option in
h)
printUsage
exit 0
;;
f)
declare -gr LEDGER_FILE=$OPTARG
;;
c)
declare -gr CREDIT_MODE=1
;;
K)
declare -gr SKIP_SYNTAX_CHECK=1
;;
V)
declare -gr NO_SELL=1
;;
P)
declare -gr NO_DEPOSIT_RETURN=1
;;
*) printUsage >&2
# prints usage after the default error message (invalid option or missing option argument).
# default error messages are disabled if the first character of optstring is ":".
exit 1
;;
esac
done
shift $((OPTIND-1))
if [[ -z $LEDGER_FILE ]]; then
exitWithError "error: ledger file not defined. use -f or export environment variable LEDGER_FILE."
fi
if (( $# != 0 )); then
printUsage
exit 1
fi
return 0
}
printPersonNamesOnly() {
cut -d$'\t' -f1 < "$PERSONS_FILE"
}
checkSyntax() {
echo "Checking syntax..."
# Must not contain ","! Because hledger tag values are seperated by comma.
if grep -v '[A-Za-z0-9]' "$COMMODITIES_FILE"; then
exitWithError "$COMMODITIES_FILE: invalid characters"
fi
if grep -E "$REGEX_METACHAR_REGEX|," "$PERSONS_FILE"; then
exitWithError "$PERSONS_FILE: invalid characters"
fi
echo "Checking person names for duplicates..."
if ! diff <(printPersonNamesOnly | sort) <(printPersonNamesOnly | sort -u); then
exitWithError "$PERSONS_FILE: found duplicate names. use a nickname or number to distinguish."
fi
}
pressAnyKey() {
read -rp "Press enter to continue"
}
# $*: command line options for hledger balance
hledgerBalance() {
hledgerCmd bal --drop=1 --flat --invert "$@"
}
# $*: command line options for hledger
hledgerCmd() {
hledger "$@" 'assets:forderungen|liabilities:lagerkasse' tag:'^person$'="^$person$"
}
# $1: selected commodity
# return value: 0 on success
# other return value: global variable $amount
askForNumber() {
declare commodity=$1
declare input
echo
echo " $commodity"
echo
IFS= read -rp "Anzahl oder '..' oder ' ' eingeben: " input
if [[ $input =~ ^[0-9]+$ ]]; then
amount=$input
elif [[ $input =~ ^(\ *|\.*)$ ]]; then
amount=${#input}
else
return 1
fi
}
# See askForNumber
askForNumberHandleErrors() {
while ! askForNumber "$@"; do
echo "error: malformed input."
pressAnyKey
done
}
printNotReturnedDeposit() {
declare person=$1
declare number
number=$(hledger -f "$LEDGER_FILE" balance "assets:forderungen:$COMMODITY_PFANDFLASCHE" tag:person="$person" \
| awk '{ print $1; exit }')
if [[ $number =~ ^[0-9]+$ ]]; then
echo "$number"
else
echo 0
fi
}
depositReturn() {
declare person=$1
declare group=$2
declare amount=$3
declare commodity=$COMMODITY_PFANDFLASCHE
declare purchasedDeposit
purchasedDeposit=$(printNotReturnedDeposit "$person")
if (( purchasedDeposit == 0 )); then
echo "Geht nicht. $purchasedDeposit Pfandflaschen ausstehend."
pressAnyKey
return 1
elif (( amount > purchasedDeposit )); then
echo "Geht nicht. Nur $purchasedDeposit Pfandflaschen ausstehend."
read -rp "$purchasedDeposit statt $amount Pfandflaschen zurückgeben? [Y/n] " answer
if [[ $answer =~ ^[yY]$|^$ ]]; then
amount=$purchasedDeposit
else
return 1
fi
fi
echo "$amount $commodity zurück"
echo "noch $(( purchasedDeposit - amount )) $commodity ausstehend"
addTransaction "$person" "$group" "Pfandrückgabe" \
"-$amount" "$commodity" \
"assets:forderungen:$COMMODITY_PFANDFLASCHE" \
"assets:getränke:$COMMODITY_PFANDFLASCHE"
}
purchase() {
declare person=$1
declare group=$2
declare amount=$3
declare commodity=$4
echo "$amount $commodity"
addTransaction "$person" "$group" "Getränkekauf" \
"-$amount" "$commodity" \
"assets:getränke:$commodity" \
"assets:forderungen:$commodity"
}
addTransaction() {
declare person=$1
declare group=$2
declare description=$3
declare amount=$4
declare commodity=$5
declare acc1=$6
declare acc2=$7
cat <<TEXT >> "$LEDGER_FILE"
$(date -I) $description ; person: $person, gruppe: $group, time: $(date +%T)
$acc1 $amount $commodity
$acc2
TEXT
# hledger -f "$LEDGER_FILE" add -- "$(date -I)" \
# "$description ; person: $person, gruppe: $group, time: $(date +%T)" \
# "$acc1" "$amount $commodity" \
# "$acc2"
}
sell() {
declare person=$1
declare group=$2
declare commodity=$3
if [[ $commodity != "$COMMODITY_PFANDFLASCHE" && -z $CREDIT_MODE ]]; then
# Standardmodus: Guthaben auf Lagerkasse
# Check if person can effort $amount of $commodity + deposit
# TODO schwierig... dazu müsste dieses Programm wissen was
# $commodity wert ist und selbst Berechnungen machen...
# Vllt einfach warnen, wenn debit < 3 €?
declare balanceValue
balanceValue=$(hledgerBallanceValue)
if math "${balanceValue/,/.} < 3"; then
echo "Vorsicht: Guthaben < 3 €"
pressAnyKey
fi
fi
askForNumberHandleErrors "$commodity"
if (( amount > 0 )); then
if [[ $commodity == "$COMMODITY_PFANDFLASCHE" ]]; then
depositReturn "$person" "$group" "$amount" \
|| true
else
purchase "$person" "$group" "$amount" "$commodity"
purchase "$person" "$group" "$amount" "$COMMODITY_PFANDFLASCHE"
fi
fi
}
# $*: args for fzf
runFzf() {
fzf --reverse "$@"
}
verkaufen() {
declare person=$1
declare group=$2
declare commodity
commodity=$(runFzf < "$COMMODITIES_FILE") || return 1
sell "$person" "$group" "$commodity"
}
einzahlen() {
declare person=$1
declare group=$2
declare amount balanceAmount
balanceAmount=$(hledgerBallanceValue)
if math "${balanceAmount/,/.} < 0"; then
balanceAmount=${balanceAmount#-}
read -rp "Einzuzahlender Betrag [enter for balance amount: $balanceAmount]: " amount
if [[ -z $amount ]]; then
if math "${balanceAmount/,/.} == 0"; then
return
else
if confirmYn "$balanceAmount wirklich einbezahlen?"; then
amount=$balanceAmount
else
return 1
fi
fi
fi
else
read -rp "Einzuzahlender Betrag: " amount
amount=${amount/,/.}
if [[ -z $amount ]]; then
return 1
fi
fi
amount=${amount/,/.}
if [[ $amount =~ ^[0-9]+(.[0-9]*)?$ ]]; then
addTransaction "$person" "$group" \
"Einzahlung" \
"$amount" "€" \
"expenses:einzahlung" \
"liabilities:lagerkasse"
else
echo "Ungültige Eingabe."
pressAnyKey
return 1
fi
}
confirmYn() {
declare question=$1
declare answer
read -rp "$question [Y/n] " answer
[[ $answer =~ ^([Yy]|)$ ]]
}
math() {
declare expression=$1
declare result
result=$(bc <<< "$expression")
[[ $result == 1 ]]
}
hledgerBallanceValue() {
hledgerBalance -V | awk 'END { print $1 }'
}
abrechnen() {
declare person=$1
declare group=$2
declare restAmount
restAmount=$(hledgerBallanceValue)
if math "${restAmount/,/.} < 0"; then
echo "${restAmount#-} ausstehend! Bitte Einzahlung machen."
einzahlen "$person" "$group" \
&& return || return 1
fi
read -rp "Auszuzahlender Betrag [enter for rest amount: $restAmount]: " amount
if [[ -z $amount ]]; then
if math "${restAmount/,/.} == 0"; then
return
else
if confirmYn "$restAmount wirklich ausbezahlen?"; then
amount=$restAmount
else
return 1
fi
fi
fi
if [[ $amount =~ ^[0-9]+(.[0-9]*)?$ ]]; then
amount=${amount/,/.}
if math "$amount > ${restAmount/,/.}"; then
echo "Auszuzahlender Betrag ist größer als Restbetrag."
if ! confirmYn "Das bedeutet, die Kasse ist nacher im Minus. Fortfahren?"; then
return 1
fi
fi
addTransaction "$person" "$group" \
"Auszahlung" \
"$amount" "€" \
"liabilities:lagerkasse" \
"expenses:einzahlung"
else
echo "Ungültige Eingabe."
pressAnyKey
return 1
fi
}
printMenu() {
echo "Choose an option:"
echo " v, enter for Verkauf"
echo " e Einzahlen"
echo " a Abrechnen"
echo " b Bilanz mit €-Werten"
echo " l Kontoauszug"
echo " r Buchungssätze manuell reparieren"
echo " n, x for next person"
echo " q quit"
}
printPerson() {
declare person=$1
declare group=$2
echo
echo "$person, $group"
}
main() {
parseCommandLine "$@"
if [[ -z $SKIP_SYNTAX_CHECK ]]; then
checkSyntax
fi
while true; do
declare personSelection person group
personSelection=$(sort "$PERSONS_FILE" | runFzf --delimiter='\t')
IFS=$'\t' read -r person group <<< "$personSelection"
if [[ -z $NO_DEPOSIT_RETURN ]]; then
printPerson "$person" "$group"
sell "$person" "$group" "$COMMODITY_PFANDFLASCHE"
fi
declare choice=default
while true; do
echo
case $choice in
default)
if [[ -z $NO_SELL ]]; then
printPerson "$person" "$group"
verkaufen "$person" "$group" \
|| true
fi
;;
''|v|V)
printPerson "$person" "$group"
verkaufen "$person" "$group" \
|| true
;;
e|E)
printPerson "$person" "$group"
einzahlen "$person" "$group" \
|| true
;;
a|A)
printPerson "$person" "$group"
abrechnen "$person" "$group" \
|| true
;;
b)
printPerson "$person" "$group"
hledgerBalance -V
;;
l)
hledgerCmd register
;;
r)
vim "$LEDGER_FILE"
;;
m) printMenu
;;
n|x) break ;;
q) return ;;
*) echo "Invalid input." ;;
esac
printPerson "$person" "$group"
echo
hledgerBalance
# Also print sum of balance -V
# Leider geht durch tail die Farbe verloren
hledgerBalance -V | tail -2
echo
read -rp "Choose an option ([V]erkauf = enter, [E]inzahlen, [A]brechnen, [n]ext person, [m]ore): " choice
echo
done
done
}
main "$@"