Das Buchungsformat von DATEV ist nach wie vor der de-facto Standard bei Steuerberatern, wird aber auch häufig von Wirtschaftsprüfern, Rechtsanwälten usw. eingesetzt. Möchte man also beispielsweise seinem Steuerberater zuarbeiten, indem man nicht nur Belege, sondern auch gleich die passenden Buchungsstapel liefert, müssen DATEV-konforme Dateien erzeugt werden. Wir zeigen hier, wie wir es gemacht haben.
Im Endeffekt handelt es sich bei DATEV-Dateien um nichts anderes als Tabellen bzw. CSV-Dateien in einem bestimmten Format und mit einem speziellen Header, die mit jeder Software erzeugt werden können, die solche Dateien ausgeben kann. Wir nutzen R, um die Funktion für DATEV-Buchungsstapel später in anderen Skripten oder Anwendungen aufrufen zu können.
Dieser Artikel behandelt ein Steuer- oder Finanzthema. Wir stellen die Informationen auf dieser Webseite kostenlos und nach bestem Gewissen zusammen, können aber nicht für deren Richtigkeit garantieren. Meist liefern die Artikel einen Startpunkt, jedoch in der Regel keine individuell passenden Lösungen. DYOR (Do your own research).
Struktur eines DATEV-Buchungsstapels
Die erste Zeile eines DATEV-Buchungsstapels besteht wie gesagt aus dem Header, der einem bestimmten „Satzaufbau“ folgen muss, den DATEV hier genauer erklärt hat. Die einzelnen Bestandteile des „Satzes“ werden hierbei ganz normal wie Spaltennamen einer CSV mit Komma oder Semikolon voneinander getrennt.
Hier die Bestandteile des Headers und in der Spalte „Beispiel“ zum Teil die Werte, die in der später folgenden Funktion als Standard eingestellt sind. Das Ganze lässt sich natürlich leicht für die eigenen Zwecke anpassen. In diesem Beispiel handelt es sich um einen Buchungsstapel aus dem November 2021 in Euro für ein Unternehmen, dessen Wirtschaftsjahr im Juli 2020 begann.
# | Überschrift | Beispiel | Beschreibung |
1 | Kennzeichen | EXTF | EXTF = Export aus 3rd-Party App DTVF = Export aus DATEV App |
2 | Versionsnummer | 700 | Versionsnummer des Headers. Anhand der Versionsnummer können ältere Versionen abwärtskompatibel verarbeitet werden. |
3 | Formatkategorie | 21 | 16 = Debitoren-/Kreditoren 20 = Sachkontenbeschriftungen 21 = Buchungsstapel 46 = Zahlungsbedingungen 48 = Diverse Adressen 65 = Wiederkehrende Buchungen |
4 | Formatname | Buchungsstapel | Formatname |
5 | Formatversion | 12 | Debitoren-/Kreditoren = 5 Sachkontenbeschriftungen = 3 Buchungsstapel = 12 Zahlungsbedingungen = 2 Wiederkehrende Buchungen = 4 Diverse Adressen = 2 |
6 | Erzeugt am | 20211116154846000 | Zeitstempel:YYYYMMDDHHMMSSFFF |
7 | Reserviert | (leer) | Leerfeld |
8 | Reserviert | (leer) | Leerfeld |
9 | Reserviert | (leer) | Leerfeld |
10 | Reserviert | (leer) | Leerfeld |
11 | Beraternummer | 1001 | Bereich 1001-9999999 |
12 | Mandantennummer | 99999 | Bereich 1-99999 |
13 | WJ-Beginn | 20200701 | Wirtschaftsjahresbeginn Format: YYYYMMDD |
14 | Sachkontenlänge | 4 | Nummernlänge der Sachkonten. Wert muss beim Import mit Konfiguration des Mandats in der DATEV App übereinstimmen. |
15 | Datum von | 20200701 | Beginn der Periode des Stapels Format: YYYYMMDD |
16 | Datum bis | 20201231 | Ende der Periode des Stapels Format: YYYYMMDD |
17 | Bezeichnung | Buchungen | Bezeichnung des Stapels |
18 | Diktatkürzel | (leer) | Kürzel in Großbuchstaben des Bearbeiters, z.B. „MM“ für Max Mustermann |
19 | Buchungstyp | 1 | 1 = Finanzbuchführung (default) 2 = Jahresabschluss |
20 | Rechnungs-legungszweck | 0 | 0 = unabhängig (default) 30 = Steuerrecht 40 = Kalkulatorik 50 = Handelsrecht 64 = IFRS |
21 | Festschreibung | 0 | 0 = keine Festschreibung 1 = Festschreibung |
22 | WKZ | EUR | ISO-Code der Währung |
23 | Reserviert | (leer) | Leerfeld |
24 | Derivatskennzeichen | (leer) | Leerfeld |
25 | Reserviert | (leer) | Leerfeld |
26 | Reserviert | (leer) | Leerfeld |
27 | Sachkonten-rahmen | (leer) | Sachkontenrahmen der für die Bewegungsdaten verwendet wurde |
28 | ID der Branchen-lösung | (leer) | Falls eine spezielle DATEV Branchenlösung genutzt wird. |
29 | Reserviert | (leer) | Leerfeld |
30 | Reserviert | (leer) | Leerfeld |
31 | Anwendungs-information | (leer) | Verarbeitungskennzeichen der abgebenden Anwendung, z.B. „09/2019“ |
Die zweite Zeile des Headers besteht aus tatsächlichen Spaltennamen. Diese Spaltenbezeichungen sind für die späteren Einträge (Euro-Betrag, Kontennummern usw.) maßgeblich.
- Umsatz (ohne Soll/Haben-Kz)
- Soll/Haben-Kennzeichen
- WKZ Umsatz
- Kurs
- Basis-Umsatz
- WKZ Basis-Umsatz
- Konto
- Gegenkonto (ohne BU-Schlüssel)
- BU-Schlüssel
- Belegdatum
- Belegfeld 1
- Belegfeld 2
- Skonto
- Buchungstext
- Postensperre
- Diverse Adressnummer
- Geschäftspartnerbank
- Sachverhalt
- Zinssperre
- Beleglink
- Beleginfo – Art 1
- Beleginfo – Inhalt 1
- Beleginfo – Art 2
- Beleginfo – Inhalt 2
- Beleginfo – Art 3
- Beleginfo – Inhalt 3
- Beleginfo – Art 4
- Beleginfo – Inhalt 4
- Beleginfo – Art 5
- Beleginfo – Inhalt 5
- Beleginfo – Art 6
- Beleginfo – Inhalt 6
- Beleginfo – Art 7
- Beleginfo – Inhalt 7
- Beleginfo – Art 8
- Beleginfo – Inhalt 8
- KOST1 – Kostenstelle
- KOST2 – Kostenstelle
- Kost-Menge
- EU-Land u. UStID
- EU-Steuersatz
- Abw. Versteuerungsart
- Sachverhalt L+L
- Funktionsergänzung L+L
- BU 49 Hauptfunktionstyp
- BU 49 Hauptfunktionsnummer
- BU 49 Funktionsergänzung
- Zusatzinformation – Art 1
- Zusatzinformation- Inhalt 1
- Zusatzinformation – Art 2
- Zusatzinformation- Inhalt 2
- Zusatzinformation – Art 3
- Zusatzinformation- Inhalt 3
- Zusatzinformation – Art 4
- Zusatzinformation- Inhalt 4
- Zusatzinformation – Art 5
- Zusatzinformation- Inhalt 5
- Zusatzinformation – Art 6
- Zusatzinformation- Inhalt 6
- Zusatzinformation – Art 7
- Zusatzinformation- Inhalt 7
- Zusatzinformation – Art 8
- Zusatzinformation- Inhalt 8
- Zusatzinformation – Art 9
- Zusatzinformation- Inhalt 9
- Zusatzinformation – Art 10
- Zusatzinformation- Inhalt 10
- Zusatzinformation – Art 11
- Zusatzinformation- Inhalt 11
- Zusatzinformation – Art 12
- Zusatzinformation- Inhalt 12
- Zusatzinformation – Art 13
- Zusatzinformation- Inhalt 13
- Zusatzinformation – Art 14
- Zusatzinformation- Inhalt 14
- Zusatzinformation – Art 15
- Zusatzinformation- Inhalt 15
- Zusatzinformation – Art 16
- Zusatzinformation- Inhalt 16
- Zusatzinformation – Art 17
- Zusatzinformation- Inhalt 17
- Zusatzinformation – Art 18
- Zusatzinformation- Inhalt 18
- Zusatzinformation – Art 19
- Zusatzinformation- Inhalt 19
- Zusatzinformation – Art 20
- Zusatzinformation- Inhalt 20
- Stück
- Gewicht
- Zahlweise
- Forderungsart
- Veranlagungsjahr
- Zugeordnete Fälligkeit
- Skontotyp
- Auftragsnummer
- Buchungstyp
- Ust-Schlüssel (Anzahlungen)
- EU-Land (Anzahlungen)
- Sachverhalt L+L (Anzahlungen)
- EU-Steuersatz (Anzahlungen)
- Erlöskonto (Anzahlungen)
- Herkunft-Kz
- Leerfeld DATEV intern
- KOST-Datum
- SEPA-Mandatsreferenz
- Skontosperre
- Gesellschaftername
- Beteiligtennummer
- Identifikationsnummer
- Zeichnernummer
- Postensperre bis
- Bezeichnung SoBil-Sachverhalt
- Kennzeichnung SoBil-Buchung
- Festschreibung
- Leistungsdatum
- Datum Zuord. Steuerperiode
- Fälligkeit
- Generalumkehr (GU)
- Steuersatz
- Land
- Abrechnungsreferenz
- BVV-Posiiton
- EU-Mitgliedstaat u. UStID (Ursprung)
- EU-Steuersatz (Ursprung)“
Die weiteren Zeilen müssen nun die eigentlichen Buchungen enthalten, wobei die einzelnen „Zellen“ durch Semikolon getrennt werden.
Wie erzeugt man manuell einen DATEV-Buchungsstapel in R?
Für unseren Anwendungsfall genügt es, die folgenden Informationen in den Buchungsstapel zu übernehmen. Eventuell sind nicht alle davon zwingend notwendig:
- Anfangsdatum des Stapels
- Beginn des Wirtschaftsjahres
- Enddatum des Stapels
- Datum der Buchungen
- Betrag
- Soll/Haben Kennziffer
- Soll-Konto
- Haben-Konto
- Buchungstext
- Mandantennummer
- Mandantenname
- Beraternummer
- Sachkontenlänge
- SKR (z.B. 03)
Nachdem wir nun die Theorie besprochen haben, kann eine R-Funktion so aussehen, um funktionierende DATEV-Buchungsstapel zu erzeugen:
create_datev <- function(betrag,
belegdatum, # als R-Datum
soll_haben_kennziffer,
konto_soll,
konto_haben,
buchungstext,
name = "Mustermann",
beraternummer = 1001,
mandantennummer = 99999,
wj_beginn = "20210101",
sachkontenlaenge = 4,
skr = "03") {
# Checks
stopifnot(is.Date(belegdatum))
stopifnot(nchar(konto_soll) == sachkontenlaenge)
stopifnot(nchar(konto_haben) == sachkontenlaenge)
stopifnot(nchar(wj_beginn) == 8)
# Make sure every transaction is complete
n_transactions <- length(belegdatum)
stopifnot(length(konto_soll) == n_transactions)
stopifnot(length(konto_haben) == n_transactions)
stopifnot(length(buchungstext) == n_transactions)
stopifnot(length(betrag) == n_transactions)
# DATEV-Header bestehend aus zwei Zeilen
# Zeile 1 wird später generiert
datev_header <- c(
"",
"Umsatz (ohne Soll/Haben-Kz);Soll/Haben-Kennzeichen;WKZ Umsatz;Kurs;Basis-Umsatz;WKZ Basis-Umsatz;Konto;Gegenkonto (ohne BU-Schlüssel);BU-Schlüssel;Belegdatum;Belegfeld 1;Belegfeld 2;Skonto;Buchungstext;Postensperre;Diverse Adressnummer;Geschäftspartnerbank;Sachverhalt;Zinssperre;Beleglink;Beleginfo - Art 1;Beleginfo - Inhalt 1;Beleginfo - Art 2;Beleginfo - Inhalt 2;Beleginfo - Art 3;Beleginfo - Inhalt 3;Beleginfo - Art 4;Beleginfo - Inhalt 4;Beleginfo - Art 5;Beleginfo - Inhalt 5;Beleginfo - Art 6;Beleginfo - Inhalt 6;Beleginfo - Art 7;Beleginfo - Inhalt 7;Beleginfo - Art 8;Beleginfo - Inhalt 8;KOST1 - Kostenstelle;KOST2 - Kostenstelle;Kost-Menge;EU-Land u. UStID;EU-Steuersatz;Abw. Versteuerungsart;Sachverhalt L+L;Funktionsergänzung L+L;BU 49 Hauptfunktionstyp;BU 49 Hauptfunktionsnummer;BU 49 Funktionsergänzung;Zusatzinformation - Art 1;Zusatzinformation- Inhalt 1;Zusatzinformation - Art 2;Zusatzinformation- Inhalt 2;Zusatzinformation - Art 3;Zusatzinformation- Inhalt 3;Zusatzinformation - Art 4;Zusatzinformation- Inhalt 4;Zusatzinformation - Art 5;Zusatzinformation- Inhalt 5;Zusatzinformation - Art 6;Zusatzinformation- Inhalt 6;Zusatzinformation - Art 7;Zusatzinformation- Inhalt 7;Zusatzinformation - Art 8;Zusatzinformation- Inhalt 8;Zusatzinformation - Art 9;Zusatzinformation- Inhalt 9;Zusatzinformation - Art 10;Zusatzinformation- Inhalt 10;Zusatzinformation - Art 11;Zusatzinformation- Inhalt 11;Zusatzinformation - Art 12;Zusatzinformation- Inhalt 12;Zusatzinformation - Art 13;Zusatzinformation- Inhalt 13;Zusatzinformation - Art 14;Zusatzinformation- Inhalt 14;Zusatzinformation - Art 15;Zusatzinformation- Inhalt 15;Zusatzinformation - Art 16;Zusatzinformation- Inhalt 16;Zusatzinformation - Art 17;Zusatzinformation- Inhalt 17;Zusatzinformation - Art 18;Zusatzinformation- Inhalt 18;Zusatzinformation - Art 19;Zusatzinformation- Inhalt 19;Zusatzinformation - Art 20;Zusatzinformation- Inhalt 20;Stück;Gewicht;Zahlweise;Forderungsart;Veranlagungsjahr;Zugeordnete Fälligkeit;Skontotyp;Auftragsnummer;Buchungstyp;Ust-Schlüssel (Anzahlungen);EU-Land (Anzahlungen);Sachverhalt L+L (Anzahlungen);EU-Steuersatz (Anzahlungen);Erlöskonto (Anzahlungen);Herkunft-Kz;Leerfeld DATEV intern;KOST-Datum;SEPA-Mandatsreferenz;Skontosperre;Gesellschaftername;Beteiligtennummer;Identifikationsnummer;Zeichnernummer;Postensperre bis;Bezeichnung SoBil-Sachverhalt;Kennzeichnung SoBil-Buchung;Festschreibung;Leistungsdatum;Datum Zuord. Steuerperiode;Fälligkeit;Generalumkehr (GU);Steuersatz;Land;Abrechnungsreferenz;BVV-Posiiton;.EU-Mitgliedstaat u. UStID (Ursprung);EU-Steuersatz (Ursprung)"
)
created_at <- format(Sys.time(), "%Y%m%d%H%M%S")
created_at <- paste0(created_at, "000")
beginndatum_stapel <- min(belegdatum)
beginndatum_stapel <- format(beginndatum_stapel, "%Y%m%d")
enddatum_stapel <- max(belegdatum)
enddatum_stapel <- format(enddatum_stapel, "%Y%m%d")
datev_header[1] <- paste0(
'"EXTF";700;21;"Buchungsstapel";12;',
created_at,
';;;',
name,
';"";',
beraternummer,
';', mandantennummer, ';',
wj_beginn, ';',
sachkontenlaenge, ';',
beginndatum_stapel, ';',
enddatum_stapel, ';',
'"Bezeichnung des Buchungsstapels";"";1;;;"EUR";;;;;',
skr, ';;;"";""'
)
betrag <- gsub(pattern = "\\.", replacement = ",", x = as.character(betrag))
datum_tag <- day(belegdatum)
datum_monat <- month(belegdatum)
datum_tag <- ifelse(test = datum_tag < 10,
yes = paste0("0", datum_tag),
no = as.character(datum_tag))
datum_monat <- ifelse(test = datum_monat < 10,
yes = paste0("0", datum_monat),
no = as.character(datum_monat))
belegdatum <- paste0(datum_tag, datum_monat)
buchungen <- paste0(
betrag,
';\"',
soll_haben_kennziffer,
'\";\"\";\"\";\"\";\"\";',
konto_soll,
';',
konto_haben,
';\"\";',
belegdatum,
';\"\";\"\";\"\";\"',
buchungstext,
'\";0;\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";;\"\";;\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";\"\";0;;;\"\";0;0;\"\";\"\";\"\";\"\";\"\"'
)
return(c(datev_header, buchungen))
}
Code-Sprache: R (r)
Beispielbuchung in DATEV-Buchungsstapel umwandeln
Nehmen wir an, wir hätten nun folgenden Buchungsvorgang: Zinseinnahme von 100€ wird auf das Konto des Unternehmens gutgeschrieben.
Ein möglicher Buchungssatz (SKR03) wäre also:
1200 Bank an 2650 Sonstige Zinsen und ähnliche Erträge
Mit obiger R-Funktion kann man diesen Buchungssatz nun in einen DATEV-Buchungsstapel umwandeln, sodass er von gängigen Buchhaltungsprogrammen oder vom Steuerberater eingelesen werden kann.
buchungsstapel <- create_datev(
betrag = 100,
belegdatum = as.Date("2022-04-05"),
soll_haben_kennziffer = "S",
konto_soll = "1200",
konto_haben = "2650",
buchungstext = "Mein Zinsertrag",
name = "Muster GmbH",
wj_beginn = "20220101"
)
write_lines(buchungsstapel, "mein_buchungsstapel.txt")
Code-Sprache: R (r)
Beispiel: CSV mit Buchungen in DATEV-Buchungsstapel umwandeln
Praxisnäher ist sicherlich dieses Beispiel, in dem wir Buchungen aus einer CSV-Datei einlesen und in einen DATEV-Buchungsstapel umwandeln. Mit read_csv kann hierfür eine Tabelle von der Festplatte eingelesen werden, zur besseren Anschaulichkeit generieren wir hier die CSV direkt im Code. Abschließend speichern wir den Buchungsstapel als Textdatei, sodass er von Buchhaltungsprogrammen importiert werden kann.
Nochmals: Ein DATEV-konformer Buchungsstapel ist letztlich nichts anderes als eine CSV-Datei mit bestimmten Spalten. Eine CSV wiederum ist eine Tabelle in Textform, wo die Spalten durch Kommas oder Semikolons voneinander getrennt sind.
Im ersten Abschnitt des Codes erstellen wir solch eine CSV und lesen sie ein. Anschließend erzeugen wir mit create_datev den Buchungsstapel und speichern ihn im letzten Schritt als .txt Datei, die dann vom Buchhaltungsprogramm importiert werden kann.
buchungen <- c(
"Datum, Betrag, Sollkonto, Habenkonto, Text
2022-01-01, 100, 1200, 2600, Zinsertrag
2022-02-01, 200, 1200, 2600, Zinsertrag
2022-03-01, 300, 1200, 2600, Zinsertrag"
)
buchungen <- read_csv(buchungen)
buchungen$Datum <- as.Date(buchungen$Datum)
datev_stapel <- create_datev(
betrag = buchungen$Betrag,
belegdatum = buchungen$Datum,
soll_haben_kennziffer = "S",
konto_soll = buchungen$Sollkonto,
konto_haben = buchungen$Habenkonto,
buchungstext = buchungen$Text,
wj_beginn = "20220101"
)
write_lines(datev_stapel, "mein_buchungsstapel.txt")
Code-Sprache: R (r)