commit 3714984af5dd042041ddc6ee61247b0d5652de0b Author: bernd Date: Mon May 3 12:56:43 2021 +0200 initialer commit diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..cd07f7a --- /dev/null +++ b/TODO.txt @@ -0,0 +1,11 @@ +TODO +---- + +* Ausgabe (besonders farbige) im Terminal verbessern. +* Parameterübergabe um einzelne Kunden zu bearbeiten. + * Parameter für den Versand der Rechnung. +* Parameterübergabe für ein Ausgabeverzeichnis. + * Ansonsten vielleicht PDF verschieben +* Nicht mehr benötigte Dateien (*.log, *.aux, etc.) der Rechnung löschen. +* Den Begleittext dürch eine Variable ersetzen. + diff --git a/octorech.lco b/octorech.lco new file mode 100644 index 0000000..cd40ac8 --- /dev/null +++ b/octorech.lco @@ -0,0 +1,9 @@ +\setkomavar{fromname}{OctoPi.Consulting} +\setkomavar{fromaddress}{Zitzmannstr.\,15\\07743 Jena} +\setkomavar{frommobilephone}[\faMobilePhone~]{01\,63 / 615 61 98} +\setkomavar{fromurl}{https://octopi.consulting/} +\setkomavar{fromemail}[\faEnvelopeO~]{rechnung@octopi.consulting} +\setkomavar{place}{Jena} +\setkomavar{placeseparator}{, } +\setkomavar{signature}{Jens Kubieziel} +\setkomavar{frombank}{Commerzbank AG Jena} diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..54130e7 --- /dev/null +++ b/readme.txt @@ -0,0 +1,21 @@ +rechnung.sh +----------- + +Erstellt aus einer Kundendatei Rechnungen. + +Beschreibung +------------ + +Aus einer Kundendatei (rechnung.ini) werden blockweise Kundendaten gelesen +und in Variablen gespeichert. Am Ende des Blocks wird eine Kopie des +Templates (template.ltx) erstellt und die Platzhalter in der Kopie durch die +entsprechenden Variablen erstellt. Diese Kopie wird zweimal mittels pdflatex +übersetzt. + +Installation +------------ + +Kopieren Sie die Dateien template.ltx, octorech.lco, rechnung.ini und +rechnung.sh in ein Verzeichnis Ihrer Wahl. Passen Sie die Dateien +rechnung.ini und octorech.lco an Ihre Bedürfnisse an. + diff --git a/rechnung.ini b/rechnung.ini new file mode 100644 index 0000000..9fcb2fc --- /dev/null +++ b/rechnung.ini @@ -0,0 +1,36 @@ +# file: rechnung.ini +# + +[start] +kunde=Firma A +adresse1= Strasse A; 012345 Stadt A +anrede=Sehr geehrte Damen und Herren, +anzahl=1 +position=Dienstleistung A mit etwas mehr Text +short=Leistung A +betrag=100 +lfdnr=1 +[ende] + +[start] +kunde=Firma B +adresse=Personalabteilung; Frau B; Strasse B; 01234 Stadt B +anrede=Sehr geehrte Frau B, +anzahl=1 +position=Dienstleistung B mit mehr noch viel Text +short=Leistung B +betrag=99 +lfdnr=1 +[ende] + +[start] +kunde=Herr C +adresse=Strasse C; 12345 Stadt C +anrede=Sehr geehrter Herr C, +anzahl=1 +position=Dienstleistung C +short=Leistung C +betrag=110 +lfdnr=1 +[ende] + diff --git a/rechnung.sh b/rechnung.sh new file mode 100755 index 0000000..d7cdb83 --- /dev/null +++ b/rechnung.sh @@ -0,0 +1,302 @@ +#!/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 -o posix + +# 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") +LATEX_BIN=$(which pdflatex 2>/dev/null || echo "pdflatex") +EXECUTABLES_TO_CHECK="$BC_BIN $TR_BIN $SED_BIN $CUT_BIN $TPUT_BIN $DATE_BIN $LATEX_BIN" + +# 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 month_ascii=$(date '+%B') + local inv_day=$(date '+%j') + local inv_date=$(date '+%Y%m%d') + local inv_dead=$(date -d '+14days' +%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 + $LATEX_BIN -halt-on-error $filename + $LATEX_BIN -halt-on-error $filename + 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 [ "$EUID" -eq 0 ]; then + echo "$0: Das Skript muss nicht als Root ausfegührt werden." + quit 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 + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..d99d9d6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,15 @@ +Abhängigkeiten von rechnung.sh: + +a) rechnung.sh + + 1.) bc + 2.) tr + 3.) sed + 4.) date + 5.) pdflatex + 6.) optional tput für farbe im terminal + +b) pdflatex + + 1.) fontawesome.sty + 2.) rechnung.sty (https://github.com/tomka/rechnung) diff --git a/template.ltx b/template.ltx new file mode 100644 index 0000000..1b9bc08 --- /dev/null +++ b/template.ltx @@ -0,0 +1,78 @@ +\documentclass[ngerman,headsepline=off,% +parskip=half,% +%DIV=calc,% +% Was kommt in den Briefkopf und in die Anschrift + fromalign=right,%% Plazierung des Briefkopfs + frommobilephone=on,%% Telefonnummer im Absender + fromrule=aftername,%% Linie im Absender (aftername, afteraddress) + fromfax=off,%% Faxnummer + fromemail=on,%% Emailadresse + fromurl=off,%% Homepage + fromlogo=off,%% Firmenlogo + addrfield=on,%% Adressfeld fuer Fensterkuverts + backaddress=on,%% ...und Absender im Fenster + subject=beforeopening,%% Plazierung der Betreffzeile + locfield=narrow,%% zusaetzliches Feld fuer Absender + foldmarks=on,%% Faltmarken setzen + numericaldate=off,%% Datum numerisch ausgeben + refline=narrow,%% Geschaeftszeile im Satzspiegel + firstfoot=on,%% Footerbereich +octorech]{scrlttr2} +\usepackage[ngerman]{babel} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{lmodern} +\usepackage{charter} +\usepackage{eurosym} +\usepackage{tabularx} +\usepackage{fontawesome} +\usepackage{rechnung} +\usepackage{csquotes} +\let\raggedsignature=\raggedright + +\begin{document} +\LoadLetterOption{DIN} +\makeatletter +\@addtoplength[-]{firstfootvpos}{.75cm} % Fuß ein Stück nach oben +\makeatother +\setkomavar{firstfoot}{\footnotesize% +\rule[3pt]{\textwidth}{.4pt} \\ +\begin{tabularx}{\textwidth}{XXl} + OctoPi.Consulting & Amtsgericht Jena & \textbf{Bankverbindung}\\ + Jens Kubieziel & USt.-IdNr.: & IBAN: DE50 8204 0000\\ + Zitzmannstr.\,15 & DE298453137 & \hfill{}0264 3955 00\\ + 07743 Jena & & Commerzbank AG Jena +\end{tabularx}% +} + +\begin{letter}{#ANSCHRIFT#} + + %% Rechnungsnummer im Format YYYYMMDD--LFDNR + \setkomavar{invoice}{#RECHNUNGSNUMMER#} + %% Betreff der Rechnung + \setkomavar{subject}{#SUBJECT#} + %% Anrede + \opening{#ANREDE#} + +wie besprochen, stelle ich für die Durchführung des Seminars +folgende Rechnung. + + +\begin{Rechnung}[B] + \TrennerAus + \Waehrung{\euro} + \Artikel{#ANZAHL#}{#POSITION#}{#BETRAG#} +\end{Rechnung} + +Ich bitte Sie, den +Rechnungsbetrag bis zum #DEADLINE# auf das unten genannte Konto +zu überweisen. + +Ich danke Ihnen für diesen Auftrag und würde mich freuen, bald wieder +für Sie tätig zu werden. + + + +\closing{Mit freundlichen Grüßen} +\end{letter} +\end{document}