Merge pull request #20582 from alyf-de/fix_datev
fix(regional): update DATEV Export to DATEV-Format v7.0
diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py
index bd70639..7ceaf50 100644
--- a/erpnext/regional/report/datev/datev.py
+++ b/erpnext/regional/report/datev/datev.py
@@ -72,17 +72,16 @@
case gl.debit when 0 then 'H' else 'S' end as 'Soll/Haben-Kennzeichen',
/* account number or, if empty, party account number */
- coalesce(acc.account_number, acc_pa.account_number) as 'Kontonummer',
+ coalesce(acc.account_number, acc_pa.account_number) as 'Konto',
/* against number or, if empty, party against number */
coalesce(acc_against.account_number, acc_against_pa.account_number) as 'Gegenkonto (ohne BU-Schlüssel)',
gl.posting_date as 'Belegdatum',
+ gl.voucher_no as 'Belegfeld 1',
gl.remarks as 'Buchungstext',
- gl.voucher_type as 'Beleginfo - Art 1',
- gl.voucher_no as 'Beleginfo - Inhalt 1',
- gl.against_voucher_type as 'Beleginfo - Art 2',
- gl.against_voucher as 'Beleginfo - Inhalt 2'
+ gl.against_voucher_type as 'Beleginfo - Art 1',
+ gl.against_voucher as 'Beleginfo - Inhalt 1'
FROM `tabGL Entry` gl
@@ -240,8 +239,6 @@
filters -- dict
csv_class -- defines DATA_CATEGORY, FORMAT_NAME and COLUMNS
"""
- header = get_header(filters, csv_class)
-
empty_df = pd.DataFrame(columns=csv_class.COLUMNS)
data_df = pd.DataFrame.from_records(data)
@@ -253,7 +250,6 @@
if csv_class.DATA_CATEGORY == DataCategory.ACCOUNT_NAMES:
result['Sprach-ID'] = 'de-DE'
- header = ';'.join(header).encode('latin_1')
data = result.to_csv(
# Reason for str(';'): https://github.com/pandas-dev/pandas/issues/6035
sep=str(';'),
@@ -274,66 +270,91 @@
if not six.PY2:
data = data.encode('latin_1')
+ header = get_header(filters, csv_class)
+ header = ';'.join(header).encode('latin_1')
+
+ # 1st Row: Header with meta data
+ # 2nd Row: Data heading (Überschrift der Nutzdaten), included in `data` here.
+ # 3rd - nth Row: Data (Nutzdaten)
return header + b'\r\n' + data
def get_header(filters, csv_class):
+ coa = frappe.get_value("Company", filters.get("company"), "chart_of_accounts")
+ coa_used = "SKR04" if "SKR04" in coa else ("SKR03" if "SKR03" in coa else "")
+
header = [
- # A = DATEV format
- # DTVF = created by DATEV software,
- # EXTF = created by other software
- "EXTF",
- # B = version of the DATEV format
+ # DATEV format
+ # "DTVF" = created by DATEV software,
+ # "EXTF" = created by other software
+ '"EXTF"',
+ # version of the DATEV format
# 141 = 1.41,
# 510 = 5.10,
# 720 = 7.20
- "510",
+ '700',
csv_class.DATA_CATEGORY,
- csv_class.FORMAT_NAME,
- # E = Format version (regarding format name)
- "",
- # F = Generated on
- datetime.datetime.now().strftime("%Y%m%d"),
- # G = Imported on -- stays empty
- "",
- # H = Origin (SV = other (?), RE = KARE)
- "SV",
+ '"%s"' % csv_class.FORMAT_NAME,
+ # Format version (regarding format name)
+ csv_class.FORMAT_VERSION,
+ # Generated on
+ datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
+ # Imported on -- stays empty
+ '',
+ # Origin. Any two symbols, will be replaced by "SV" on import.
+ '"EN"',
# I = Exported by
- frappe.session.user,
+ '"%s"' % frappe.session.user,
# J = Imported by -- stays empty
- "",
+ '',
# K = Tax consultant number (Beraternummer)
- frappe.get_value("DATEV Settings", filters.get("company"), "consultant_number") or "",
- "",
+ frappe.get_value("DATEV Settings", filters.get("company"), "consultant_number"),
# L = Tax client number (Mandantennummer)
- frappe.get_value("DATEV Settings", filters.get("company"), "client_number") or "",
- "",
+ frappe.get_value("DATEV Settings", filters.get("company"), "client_number"),
# M = Start of the fiscal year (Wirtschaftsjahresbeginn)
frappe.utils.formatdate(frappe.defaults.get_user_default("year_start_date"), "yyyyMMdd"),
# N = Length of account numbers (Sachkontenlänge)
- "4",
+ '4',
# O = Transaction batch start date (YYYYMMDD)
frappe.utils.formatdate(filters.get('from_date'), "yyyyMMdd"),
# P = Transaction batch end date (YYYYMMDD)
frappe.utils.formatdate(filters.get('to_date'), "yyyyMMdd"),
# Q = Description (for example, "January - February 2019 Transactions")
- "{} - {} {}".format(
+ '"{} - {} {}"'.format(
frappe.utils.formatdate(filters.get('from_date'), "MMMM yyyy"),
frappe.utils.formatdate(filters.get('to_date'), "MMMM yyyy"),
csv_class.FORMAT_NAME
),
# R = Diktatkürzel
- "",
+ '',
# S = Buchungstyp
- # 1 = Transaction batch (Buchungsstapel),
+ # 1 = Transaction batch (Finanzbuchführung),
# 2 = Annual financial statement (Jahresabschluss)
- "1" if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else "",
+ '1' if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '',
# T = Rechnungslegungszweck
- "",
+ '',
# U = Festschreibung
- "",
- # V = Kontoführungs-Währungskennzeichen des Geldkontos
- frappe.get_value("Company", filters.get("company"), "default_currency")
+ '',
+ # V = Default currency, for example, "EUR"
+ '"%s"' % frappe.get_value("Company", filters.get("company"), "default_currency"),
+ # reserviert
+ '',
+ # Derivatskennzeichen
+ '',
+ # reserviert
+ '',
+ # reserviert
+ '',
+ # SKR
+ '"%s"' % coa_used,
+ # Branchen-Lösungs-ID
+ '',
+ # reserviert
+ '',
+ # reserviert
+ '',
+ # Anwendungsinformation (Verarbeitungskennzeichen der abgebenden Anwendung)
+ ''
]
return header
diff --git a/erpnext/regional/report/datev/datev_constants.py b/erpnext/regional/report/datev/datev_constants.py
index 1c9bd23..a4cd5fc 100644
--- a/erpnext/regional/report/datev/datev_constants.py
+++ b/erpnext/regional/report/datev/datev_constants.py
@@ -13,24 +13,27 @@
"Basis-Umsatz",
"WKZ Basis-Umsatz",
# Konto/Gegenkonto
- "Kontonummer",
+ "Konto",
"Gegenkonto (ohne BU-Schlüssel)",
"BU-Schlüssel",
# Datum
"Belegdatum",
- # Belegfelder
+ # Rechnungs- / Belegnummer
"Belegfeld 1",
+ # z.B. Fälligkeitsdatum Format: TTMMJJ
"Belegfeld 2",
- # Weitere Felder
+ # Skonto-Betrag / -Abzug (Der Wert 0 ist unzulässig)
"Skonto",
+ # Beschreibung des Buchungssatzes
"Buchungstext",
- # OPOS-Informationen
+ # Mahn- / Zahl-Sperre (1 = Postensperre)
"Postensperre",
"Diverse Adressnummer",
"Geschäftspartnerbank",
"Sachverhalt",
+ # Keine Mahnzinsen
"Zinssperre",
- # Digitaler Beleg
+ # Link auf den Buchungsbeleg (Programmkürzel + GUID)
"Beleglink",
# Beleginfo
"Beleginfo - Art 1",
@@ -49,22 +52,30 @@
"Beleginfo - Inhalt 7",
"Beleginfo - Art 8",
"Beleginfo - Inhalt 8",
- # Kostenrechnung
- "Kost 1 - Kostenstelle",
- "Kost 2 - Kostenstelle",
- "Kost-Menge",
- # Steuerrechnung
- "EU-Land u. UStID",
+ # Zuordnung des Geschäftsvorfalls für die Kostenrechnung
+ "KOST1 - Kostenstelle",
+ "KOST2 - Kostenstelle",
+ "KOST-Menge",
+ # USt-ID-Nummer (Beispiel: DE133546770)
+ "EU-Mitgliedstaat u. USt-IdNr.",
+ # Der im EU-Bestimmungsland gültige Steuersatz
"EU-Steuersatz",
+ # I = Ist-Versteuerung,
+ # K = keine Umsatzsteuerrechnung
+ # P = Pauschalierung (z. B. für Land- und Forstwirtschaft),
+ # S = Soll-Versteuerung
"Abw. Versteuerungsart",
- # L+L Sachverhalt
+ # Sachverhalte gem. § 13b Abs. 1 Satz 1 Nrn. 1.-5. UStG
"Sachverhalt L+L",
+ # Steuersatz / Funktion zum L+L-Sachverhalt (Beispiel: Wert 190 für 19%)
"Funktionsergänzung L+L",
- # Funktion Steuerschlüssel 49
+ # Bei Verwendung des BU-Schlüssels 49 für „andere Steuersätze“ muss der
+ # steuerliche Sachverhalt mitgegeben werden
"BU 49 Hauptfunktionstyp",
"BU 49 Hauptfunktionsnummer",
"BU 49 Funktionsergänzung",
- # Zusatzinformationen
+ # Zusatzinformationen, besitzen den Charakter eines Notizzettels und können
+ # frei erfasst werden.
"Zusatzinformation - Art 1",
"Zusatzinformation - Inhalt 1",
"Zusatzinformation - Art 2",
@@ -105,54 +116,76 @@
"Zusatzinformation - Inhalt 19",
"Zusatzinformation - Art 20",
"Zusatzinformation - Inhalt 20",
- # Mengenfelder LuF
+ # Wirkt sich nur bei Sachverhalt mit SKR 14 Land- und Forstwirtschaft aus,
+ # für andere SKR werden die Felder beim Import / Export überlesen bzw.
+ # leer exportiert.
"Stück",
"Gewicht",
- # Forderungsart
+ # 1 = Lastschrift
+ # 2 = Mahnung
+ # 3 = Zahlung
"Zahlweise",
"Forderungsart",
+ # JJJJ
"Veranlagungsjahr",
+ # TTMMJJJJ
"Zugeordnete Fälligkeit",
- # Weitere Felder
+ # 1 = Einkauf von Waren
+ # 2 = Erwerb von Roh-Hilfs- und Betriebsstoffen
"Skontotyp",
- # Anzahlungen
+ # Allgemeine Bezeichnung, des Auftrags / Projekts.
"Auftragsnummer",
+ # AA = Angeforderte Anzahlung / Abschlagsrechnung
+ # AG = Erhaltene Anzahlung (Geldeingang)
+ # AV = Erhaltene Anzahlung (Verbindlichkeit)
+ # SR = Schlussrechnung
+ # SU = Schlussrechnung (Umbuchung)
+ # SG = Schlussrechnung (Geldeingang)
+ # SO = Sonstige
"Buchungstyp",
"USt-Schlüssel (Anzahlungen)",
- "EU-Land (Anzahlungen)",
+ "EU-Mitgliedstaat (Anzahlungen)",
"Sachverhalt L+L (Anzahlungen)",
"EU-Steuersatz (Anzahlungen)",
"Erlöskonto (Anzahlungen)",
- # Stapelinformationen
+ # Wird beim Import durch SV (Stapelverarbeitung) ersetzt.
"Herkunft-Kz",
- # Technische Identifikation
- "Buchungs GUID",
- # Kostenrechnung
- "Kost-Datum",
- # OPOS-Informationen
+ # Wird von DATEV verwendet.
+ "Leerfeld",
+ # Format TTMMJJJJ
+ "KOST-Datum",
+ # Vom Zahlungsempfänger individuell vergebenes Kennzeichen eines Mandats
+ # (z.B. Rechnungs- oder Kundennummer).
"SEPA-Mandatsreferenz",
+ # 1 = Skontosperre
+ # 0 = Keine Skontosperre
"Skontosperre",
# Gesellschafter und Sonderbilanzsachverhalt
"Gesellschaftername",
+ # Amtliche Nummer aus der Feststellungserklärung
"Beteiligtennummer",
"Identifikationsnummer",
"Zeichnernummer",
- # OPOS-Informationen
+ # Format TTMMJJJJ
"Postensperre bis",
# Gesellschafter und Sonderbilanzsachverhalt
"Bezeichnung SoBil-Sachverhalt",
"Kennzeichen SoBil-Buchung",
- # Stapelinformationen
+ # 0 = keine Festschreibung
+ # 1 = Festschreibung
"Festschreibung",
- # Datum
+ # Format TTMMJJJJ
"Leistungsdatum",
+ # Format TTMMJJJJ
"Datum Zuord. Steuerperiode",
- # OPOS-Informationen
+ # OPOS-Informationen, Format TTMMJJJJ
"Fälligkeit",
- # Konto/Gegenkonto
+ # G oder 1 = Generalumkehr
+ # 0 = keine Generalumkehr
"Generalumkehr (GU)",
# Steuersatz für Steuerschlüssel
"Steuersatz",
+ # Beispiel: DE für Deutschland
"Land"
]
@@ -439,8 +472,8 @@
"fieldtype": "Data",
},
{
- "label": "Kontonummer",
- "fieldname": "Kontonummer",
+ "label": "Konto",
+ "fieldname": "Konto",
"fieldtype": "Data",
},
{
@@ -454,27 +487,22 @@
"fieldtype": "Date",
},
{
+ "label": "Belegfeld 1",
+ "fieldname": "Belegfeld 1",
+ "fieldtype": "Data",
+ },
+ {
"label": "Buchungstext",
"fieldname": "Buchungstext",
"fieldtype": "Text",
},
{
"label": "Beleginfo - Art 1",
- "fieldname": "Beleginfo - Art 1",
- "fieldtype": "Data",
- },
- {
- "label": "Beleginfo - Inhalt 1",
- "fieldname": "Beleginfo - Inhalt 1",
- "fieldtype": "Data",
- },
- {
- "label": "Beleginfo - Art 2",
"fieldname": "Beleginfo - Art 2",
"fieldtype": "Data",
},
{
- "label": "Beleginfo - Inhalt 2",
+ "label": "Beleginfo - Inhalt 1",
"fieldname": "Beleginfo - Inhalt 2",
"fieldtype": "Data",
}
@@ -499,14 +527,17 @@
class Transactions():
DATA_CATEGORY = DataCategory.TRANSACTIONS
FORMAT_NAME = FormatName.TRANSACTIONS
+ FORMAT_VERSION = "9"
COLUMNS = TRANSACTION_COLUMNS
class DebtorsCreditors():
DATA_CATEGORY = DataCategory.DEBTORS_CREDITORS
FORMAT_NAME = FormatName.DEBTORS_CREDITORS
+ FORMAT_VERSION = "5"
COLUMNS = DEBTOR_CREDITOR_COLUMNS
class AccountNames():
DATA_CATEGORY = DataCategory.ACCOUNT_NAMES
FORMAT_NAME = FormatName.ACCOUNT_NAMES
+ FORMAT_VERSION = "2"
COLUMNS = ACCOUNT_NAME_COLUMNS