DATEV Buchungsstapel erzeugen mit R

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
1KennzeichenEXTFEXTF = Export aus 3rd-Party App
DTVF = Export aus DATEV App
2Versionsnummer700Versionsnummer des Headers. Anhand der Versionsnummer können ältere Versionen abwärtskompatibel verarbeitet werden.
3Formatkategorie2116 = Debitoren-/Kreditoren
20 = Sachkontenbeschriftungen
21 = Buchungsstapel
46 = Zahlungsbedingungen
48 = Diverse Adressen
65 = Wiederkehrende Buchungen
4FormatnameBuchungsstapelFormatname
5Formatversion12Debitoren-/Kreditoren = 5
Sachkontenbeschriftungen = 3
Buchungsstapel = 12
Zahlungsbedingungen = 2
Wiederkehrende Buchungen = 4
Diverse Adressen = 2
6Erzeugt am20211116154846000Zeitstempel:YYYYMMDDHHMMSSFFF
7Reserviert(leer)Leerfeld
8Reserviert(leer)Leerfeld
9Reserviert(leer)Leerfeld
10Reserviert(leer)Leerfeld
11Beraternummer1001Bereich 1001-9999999
12Mandantennummer99999Bereich 1-99999
13WJ-Beginn20200701Wirtschaftsjahresbeginn
Format: YYYYMMDD
14Sachkontenlänge4Nummernlänge der Sachkonten. Wert muss beim Import mit Konfiguration des Mandats in der DATEV App übereinstimmen.
15Datum von20200701Beginn der Periode des Stapels
Format: YYYYMMDD
16Datum bis20201231Ende der Periode des Stapels
Format: YYYYMMDD
17BezeichnungBuchungenBezeichnung des Stapels
18Diktatkürzel(leer)Kürzel in Großbuchstaben des Bearbeiters, z.B. „MM“ für Max Mustermann
19Buchungstyp11 = Finanzbuchführung       (default)
2 = Jahresabschluss
20Rechnungs-legungszweck00 = unabhängig       (default)
30 = Steuerrecht
40 = Kalkulatorik
50 = Handelsrecht
64 = IFRS
21Festschreibung00 = keine Festschreibung
1 = Festschreibung
22WKZEURISO-Code der Währung
23Reserviert(leer)Leerfeld
24Derivatskennzeichen(leer)Leerfeld
25Reserviert(leer)Leerfeld
26Reserviert(leer)Leerfeld
27Sachkonten-rahmen(leer)Sachkontenrahmen der für die Bewegungsdaten verwendet wurde
28ID der Branchen-lösung(leer)Falls eine spezielle DATEV Branchenlösung genutzt wird.
29Reserviert(leer)Leerfeld
30Reserviert(leer)Leerfeld
31Anwendungs-information(leer)Verarbeitungskennzeichen der abgebenden Anwendung, z.B. „09/2019“ 
Elemente der 1. Zeile des DATEV-Headers (Quelle: DATEV, eigene Anpassungen)

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.

Elemente der 2. Zeile des DATEV-Headers (öffnen)

  • 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)
Christian Thiele
Christian Thiele

M.A. International Economics

Christian interessiert sich seit dem DotCom-Boom Ende der 1990er für die Börse und nutzt hauptsächlich die Statistik-Programmiersprache R.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert