rechnung/rechnung.sh
qbi df4a20e623 Check auf Wochenende eingebaut
Das Zahlungsziel darf nicht an einem Wochenende liegen. Der Code prüft jetzt, ob
es ein Wochenendtag ist und verlängert das Datum um zwei Tage.
2021-05-03 19:49:57 +02:00

321 lines
6.7 KiB
Bash
Executable file

#!/bin/sh
# file: rechnung.sh
# date: 02.05.2021
# user: bernd@nr18.space
# desc: Liest verschiedene Kunden und Dienstleistungen aus der Datei
# rechnung.ini und erstellt daraus Rechnungen mit Hilfe eines
# Latex-Templates.
set -u
set -e
# Benötigte Programme
# -------------------
TR_BIN=$(which tr 2>/dev/null || echo "tr")
BC_BIN=$(which bc 2>/dev/null || echo "bc")
SED_BIN=$(which sed 2>/dev/null || echo "sed")
CUT_BIN=$(which cut 2>/dev/null || echo "cut")
DATE_BIN=$(which date 2>/dev/null || echo "date")
TPUT_BIN=$(which tput 2>/dev/null || echo "tput")
PDFLATEX_BIN=$(which pdflatex 2>/dev/null || echo "pdflatex")
RUBBER_BIN=$(which rubber 2>/dev/null || echo "rubber")
EXECUTABLES_TO_CHECK="$BC_BIN $TR_BIN $SED_BIN $CUT_BIN $TPUT_BIN $DATE_BIN $PDFLATEX_BIN $RUBBER_BIN"
GENPDF=""
if [ -x $RUBBER_BIN ]; then
GENPDF="$RUBBER_BIN -d "
else
GENPDF="$PDFLATEX_BIN -halt-on-error "
fi
# Variablen definieren
# --------------------
PROGRAMM_NAME=$0
PROGRAMM_VERSION="0.0.1"
VERBOSITY=0
RECHNUNGSFILE="rechnung.ini"
TEMPLATEFILE="template.ltx"
SEDFILE="sed.txt"
LINE_BUFFER=""
KEY_BUFFER=""
VALUE_BUFFER=""
ERROR=0
KUNDE=""
ADRESSE=""
ANREDE=""
ANZAHL=""
POSITION=""
SHORT=""
BETRAG=""
LFDNR=""
# Farben definieren
# -----------------
NUMBER_OF_COLORS=$($TPUT_BIN colors)
COLORED_OUTPUT=0
RED="\\033[1;31m"
GREEN="\\033[1;32m"
YELLOW="\\033[1;33m"
BLUE="\\033[1;34m"
NORMAL="\\033[0;39m"
# Diverse Checks
# --------------
check_readable() {
printf "\n[+] Datei \"$1\" ist lesbar ..."
if [ -f "$1" ] && [ -r "$1" ]
then
print_ok
else
print_failed
quit 1
fi
}
check_binaries() {
local program=""
local binaries=$*
for program in $binaries; do
printf "\n[+] Suche nach Programm $program ..."
if [ ! -x "$program" ]; then
print_failed
printf "\n[-] Das Programm \"$program\" wird benötigt, aber nicht gefunden."
quit 3
else
print_ok
fi
done
}
is_option() (
local line="$*"
if [ "${line#*=}" != "$line" ]; then
return 0
else
return 1
fi
)
# Ausgaben im Terminal
# --------------------
print_failed() {
if [ "$COLORED_OUTPUT" -eq 1 ]; then
printf "$RED Failed$NORMAL"
else
printf " Failed"
fi
}
print_ok() {
if [ "$COLORED_OUTPUT" -eq 1 ]; then
printf "$GREEN OK$NORMAL"
else
printf " OK"
fi
}
print_warn() {
local msg=$*
if [ "$COLORED_OUTPUT" -eq 1 ]; then
echo -e "$YELLOW[-]$NORMAL $msg"
else
echo -e "[-] $msg"
fi
}
# Whitespaces entfernen
# ---------------------
trim_line() {
set -f
set -- $*
LINE_BUFFER=$(printf '%s' "$*")
set +f
}
trim_key() {
set -f
set -- $*
KEY_BUFFER=$(printf '%s' "$*")
set +f
}
trim_value() {
set -f
set -- $*
VALUE_BUFFER=$(printf '%s' "$*")
set +f
}
reset_values() {
echo -e "\n[+] Initialisiere Felder für Rechnung neu."
LINE_BUFFER=""
KEY_BUFFER=""
VALUE_BUFFER=""
ERROR=0
KUNDE=""
ADRESSE=""
ANREDE=""
ANZAHL=""
POSITION=""
SHORT=""
BETRAG=""
LFDNR=""
}
set_value() {
local key=$(echo "$*" | $CUT_BIN -d "=" -f1)
local value=$(echo "$*" | $CUT_BIN -d "=" -f2)
trim_key $key
trim_value $value
case $KEY_BUFFER in
kunde) KUNDE="$VALUE_BUFFER";;
adresse) ADRESSE="$VALUE_BUFFER";;
anrede) ANREDE="$VALUE_BUFFER";;
anzahl) ANZAHL="$VALUE_BUFFER";;
position) POSITION="$VALUE_BUFFER";;
betrag) BETRAG="$VALUE_BUFFER";;
lfdnr) LFDNR="$VALUE_BUFFER";;
short) SHORT="$VALUE_BUFFER";;
*) print_warn "Unbekanntes Feld: $KEY_BUFFER"; ERROR=1;;
esac
}
make_invoice() {
local dead_days="14"
if [ $(date +%u) -gt 5 ]; then
dead_days="16"
fi
local month_ascii=$(date '+%B')
local inv_day=$(date '+%j')
local inv_date=$(date '+%Y%m%d')
local inv_dead=$(date -d "+${dead_days}days" +%d.%m.%Y)
local rechnungsnummer="$inv_date-$LFDNR"
local subject="Rechnung zu $SHORT"
local filename="$(date '+%Y%m%d')_Rechnung_$(echo "$month_ascii")_$(echo "$KUNDE" | $TR_BIN " " "_").ltx"
local buffer="$KUNDE; $ADRESSE"
local anschrift="$(echo "$buffer" | sed 's/; /\\\\\\\\\\\\\\ /g')"
echo "[+] Erstelle Rechnung: $filename"
echo -n "s!#SUBJECT#!" >$SEDFILE; echo "$subject!" >>$SEDFILE
echo -n "s!#ANREDE#!" >>$SEDFILE; echo "$ANREDE!" >>$SEDFILE
echo -n "s!#ANSCHRIFT#!" >>$SEDFILE; echo "$anschrift!" >>$SEDFILE
echo -n "s!#RECHNUNGSNUMMER#!" >>$SEDFILE; echo "$rechnungsnummer!" >>$SEDFILE
echo -n "s!#ANZAHL#!" >>$SEDFILE; echo "$ANZAHL!" >>$SEDFILE
echo -n "s!#POSITION#!" >>$SEDFILE; echo "$POSITION!" >>$SEDFILE
echo -n "s!#BETRAG#!" >>$SEDFILE; echo "$BETRAG!" >>$SEDFILE
echo -n "s!#DEADLINE#!" >>$SEDFILE; echo "$inv_dead!" >>$SEDFILE
cp $TEMPLATEFILE $filename
$SED_BIN -i -f $SEDFILE $filename
$GENPDF $filename
if [ -x $RUBBER_BIN ]; then
$RUBBER_BIN --clean $filename
fi
if [ $? -eq 0 ]; then
echo "[+] Rechnung erfolgreich erstellt"
else
echo "[-] Rechnung fehlgeschlagen"
fi
}
proced_ini_line() {
local line=$*
local first=$(echo "$line" | cut -c1-1)
# leerzeilen ignorieren
if [ "$line" = "" ]; then
return
# kommentarzeilen ignorieren
elif [ "$first" = "#" ]; then
return
# start einer neuen rechnung
elif [ "$line" = "[start]" ]; then
reset_values
# ende einer rechnung
elif [ "$line" = "[ende]" ]; then
if [ $ERROR -ne 0 ]; then
print_warn "Kunde \"$KUNDE\" enthält einen Fehler. Erstelle keine Rechung."
return
else
make_invoice
fi
# alle anderen zeilen
else
is_option $line
if [ $? -eq 0 ]
then
set_value $line
else
print_warn "Invalid syntax: $line"
fi
fi
}
quit() {
printf "\n$BLUE"
printf "[-] Exit$NORMAL\n"
exit $1
}
# --- Programmstart --- #
# --------------------- #
echo "==================="
echo "= Rechnung v$PROGRAMM_VERSION ="
echo "==================="
# Verschiedene Basic Checks
if [ -n $NUMBER_OF_COLORS ] && [ "$NUMBER_OF_COLORS" -ge 8 ]; then
COLORED_OUTPUT=1
fi
if [ $(id -u) -eq 0 ]; then
echo "$0: Das Skript darf nicht als Root ausgeführt werden."
exit 1
fi
check_binaries $EXECUTABLES_TO_CHECK
check_readable $RECHNUNGSFILE
check_readable $TEMPLATEFILE
printf "\n"
# Kundendatei einlesen und rechnungen erstellen
while IFS= read -r rawline
do
trim_line $rawline
proced_ini_line $LINE_BUFFER
done <$RECHNUNGSFILE