Merge pull request #20582 from alyf-de/fix_datev

fix(regional): update DATEV Export to DATEV-Format v7.0
This commit is contained in:
Deepesh Garg
2020-02-19 19:36:45 +05:30
committed by GitHub
2 changed files with 133 additions and 81 deletions

View File

@@ -72,17 +72,16 @@ def get_transactions(filters, as_dict=1):
case gl.debit when 0 then 'H' else 'S' end as 'Soll/Haben-Kennzeichen', case gl.debit when 0 then 'H' else 'S' end as 'Soll/Haben-Kennzeichen',
/* account number or, if empty, party account number */ /* 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 */ /* against number or, if empty, party against number */
coalesce(acc_against.account_number, acc_against_pa.account_number) as 'Gegenkonto (ohne BU-Schlüssel)', coalesce(acc_against.account_number, acc_against_pa.account_number) as 'Gegenkonto (ohne BU-Schlüssel)',
gl.posting_date as 'Belegdatum', gl.posting_date as 'Belegdatum',
gl.voucher_no as 'Belegfeld 1',
gl.remarks as 'Buchungstext', gl.remarks as 'Buchungstext',
gl.voucher_type as 'Beleginfo - Art 1', gl.against_voucher_type as 'Beleginfo - Art 1',
gl.voucher_no as 'Beleginfo - Inhalt 1', gl.against_voucher as 'Beleginfo - Inhalt 1'
gl.against_voucher_type as 'Beleginfo - Art 2',
gl.against_voucher as 'Beleginfo - Inhalt 2'
FROM `tabGL Entry` gl FROM `tabGL Entry` gl
@@ -240,8 +239,6 @@ def get_datev_csv(data, filters, csv_class):
filters -- dict filters -- dict
csv_class -- defines DATA_CATEGORY, FORMAT_NAME and COLUMNS csv_class -- defines DATA_CATEGORY, FORMAT_NAME and COLUMNS
""" """
header = get_header(filters, csv_class)
empty_df = pd.DataFrame(columns=csv_class.COLUMNS) empty_df = pd.DataFrame(columns=csv_class.COLUMNS)
data_df = pd.DataFrame.from_records(data) data_df = pd.DataFrame.from_records(data)
@@ -253,7 +250,6 @@ def get_datev_csv(data, filters, csv_class):
if csv_class.DATA_CATEGORY == DataCategory.ACCOUNT_NAMES: if csv_class.DATA_CATEGORY == DataCategory.ACCOUNT_NAMES:
result['Sprach-ID'] = 'de-DE' result['Sprach-ID'] = 'de-DE'
header = ';'.join(header).encode('latin_1')
data = result.to_csv( data = result.to_csv(
# Reason for str(';'): https://github.com/pandas-dev/pandas/issues/6035 # Reason for str(';'): https://github.com/pandas-dev/pandas/issues/6035
sep=str(';'), sep=str(';'),
@@ -274,66 +270,91 @@ def get_datev_csv(data, filters, csv_class):
if not six.PY2: if not six.PY2:
data = data.encode('latin_1') 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 return header + b'\r\n' + data
def get_header(filters, csv_class): 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 = [ header = [
# A = DATEV format # DATEV format
# DTVF = created by DATEV software, # "DTVF" = created by DATEV software,
# EXTF = created by other software # "EXTF" = created by other software
"EXTF", '"EXTF"',
# B = version of the DATEV format # version of the DATEV format
# 141 = 1.41, # 141 = 1.41,
# 510 = 5.10, # 510 = 5.10,
# 720 = 7.20 # 720 = 7.20
"510", '700',
csv_class.DATA_CATEGORY, csv_class.DATA_CATEGORY,
csv_class.FORMAT_NAME, '"%s"' % csv_class.FORMAT_NAME,
# E = Format version (regarding format name) # Format version (regarding format name)
"", csv_class.FORMAT_VERSION,
# F = Generated on # Generated on
datetime.datetime.now().strftime("%Y%m%d"), datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
# G = Imported on -- stays empty # Imported on -- stays empty
"", '',
# H = Origin (SV = other (?), RE = KARE) # Origin. Any two symbols, will be replaced by "SV" on import.
"SV", '"EN"',
# I = Exported by # I = Exported by
frappe.session.user, '"%s"' % frappe.session.user,
# J = Imported by -- stays empty # J = Imported by -- stays empty
"", '',
# K = Tax consultant number (Beraternummer) # 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) # 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) # M = Start of the fiscal year (Wirtschaftsjahresbeginn)
frappe.utils.formatdate(frappe.defaults.get_user_default("year_start_date"), "yyyyMMdd"), frappe.utils.formatdate(frappe.defaults.get_user_default("year_start_date"), "yyyyMMdd"),
# N = Length of account numbers (Sachkontenlänge) # N = Length of account numbers (Sachkontenlänge)
"4", '4',
# O = Transaction batch start date (YYYYMMDD) # O = Transaction batch start date (YYYYMMDD)
frappe.utils.formatdate(filters.get('from_date'), "yyyyMMdd"), frappe.utils.formatdate(filters.get('from_date'), "yyyyMMdd"),
# P = Transaction batch end date (YYYYMMDD) # P = Transaction batch end date (YYYYMMDD)
frappe.utils.formatdate(filters.get('to_date'), "yyyyMMdd"), frappe.utils.formatdate(filters.get('to_date'), "yyyyMMdd"),
# Q = Description (for example, "January - February 2019 Transactions") # Q = Description (for example, "January - February 2019 Transactions")
"{} - {} {}".format( '"{} - {} {}"'.format(
frappe.utils.formatdate(filters.get('from_date'), "MMMM yyyy"), frappe.utils.formatdate(filters.get('from_date'), "MMMM yyyy"),
frappe.utils.formatdate(filters.get('to_date'), "MMMM yyyy"), frappe.utils.formatdate(filters.get('to_date'), "MMMM yyyy"),
csv_class.FORMAT_NAME csv_class.FORMAT_NAME
), ),
# R = Diktatkürzel # R = Diktatkürzel
"", '',
# S = Buchungstyp # S = Buchungstyp
# 1 = Transaction batch (Buchungsstapel), # 1 = Transaction batch (Finanzbuchführung),
# 2 = Annual financial statement (Jahresabschluss) # 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 # T = Rechnungslegungszweck
"", '',
# U = Festschreibung # U = Festschreibung
"", '',
# V = Kontoführungs-Währungskennzeichen des Geldkontos # V = Default currency, for example, "EUR"
frappe.get_value("Company", filters.get("company"), "default_currency") '"%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 return header

View File

@@ -13,24 +13,27 @@ TRANSACTION_COLUMNS = [
"Basis-Umsatz", "Basis-Umsatz",
"WKZ Basis-Umsatz", "WKZ Basis-Umsatz",
# Konto/Gegenkonto # Konto/Gegenkonto
"Kontonummer", "Konto",
"Gegenkonto (ohne BU-Schlüssel)", "Gegenkonto (ohne BU-Schlüssel)",
"BU-Schlüssel", "BU-Schlüssel",
# Datum # Datum
"Belegdatum", "Belegdatum",
# Belegfelder # Rechnungs- / Belegnummer
"Belegfeld 1", "Belegfeld 1",
# z.B. Fälligkeitsdatum Format: TTMMJJ
"Belegfeld 2", "Belegfeld 2",
# Weitere Felder # Skonto-Betrag / -Abzug (Der Wert 0 ist unzulässig)
"Skonto", "Skonto",
# Beschreibung des Buchungssatzes
"Buchungstext", "Buchungstext",
# OPOS-Informationen # Mahn- / Zahl-Sperre (1 = Postensperre)
"Postensperre", "Postensperre",
"Diverse Adressnummer", "Diverse Adressnummer",
"Geschäftspartnerbank", "Geschäftspartnerbank",
"Sachverhalt", "Sachverhalt",
# Keine Mahnzinsen
"Zinssperre", "Zinssperre",
# Digitaler Beleg # Link auf den Buchungsbeleg (Programmkürzel + GUID)
"Beleglink", "Beleglink",
# Beleginfo # Beleginfo
"Beleginfo - Art 1", "Beleginfo - Art 1",
@@ -49,22 +52,30 @@ TRANSACTION_COLUMNS = [
"Beleginfo - Inhalt 7", "Beleginfo - Inhalt 7",
"Beleginfo - Art 8", "Beleginfo - Art 8",
"Beleginfo - Inhalt 8", "Beleginfo - Inhalt 8",
# Kostenrechnung # Zuordnung des Geschäftsvorfalls für die Kostenrechnung
"Kost 1 - Kostenstelle", "KOST1 - Kostenstelle",
"Kost 2 - Kostenstelle", "KOST2 - Kostenstelle",
"Kost-Menge", "KOST-Menge",
# Steuerrechnung # USt-ID-Nummer (Beispiel: DE133546770)
"EU-Land u. UStID", "EU-Mitgliedstaat u. USt-IdNr.",
# Der im EU-Bestimmungsland gültige Steuersatz
"EU-Steuersatz", "EU-Steuersatz",
# I = Ist-Versteuerung,
# K = keine Umsatzsteuerrechnung
# P = Pauschalierung (z. B. für Land- und Forstwirtschaft),
# S = Soll-Versteuerung
"Abw. Versteuerungsart", "Abw. Versteuerungsart",
# L+L Sachverhalt # Sachverhalte gem. § 13b Abs. 1 Satz 1 Nrn. 1.-5. UStG
"Sachverhalt L+L", "Sachverhalt L+L",
# Steuersatz / Funktion zum L+L-Sachverhalt (Beispiel: Wert 190 für 19%)
"Funktionsergänzung L+L", "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 Hauptfunktionstyp",
"BU 49 Hauptfunktionsnummer", "BU 49 Hauptfunktionsnummer",
"BU 49 Funktionsergänzung", "BU 49 Funktionsergänzung",
# Zusatzinformationen # Zusatzinformationen, besitzen den Charakter eines Notizzettels und können
# frei erfasst werden.
"Zusatzinformation - Art 1", "Zusatzinformation - Art 1",
"Zusatzinformation - Inhalt 1", "Zusatzinformation - Inhalt 1",
"Zusatzinformation - Art 2", "Zusatzinformation - Art 2",
@@ -105,54 +116,76 @@ TRANSACTION_COLUMNS = [
"Zusatzinformation - Inhalt 19", "Zusatzinformation - Inhalt 19",
"Zusatzinformation - Art 20", "Zusatzinformation - Art 20",
"Zusatzinformation - Inhalt 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", "Stück",
"Gewicht", "Gewicht",
# Forderungsart # 1 = Lastschrift
# 2 = Mahnung
# 3 = Zahlung
"Zahlweise", "Zahlweise",
"Forderungsart", "Forderungsart",
# JJJJ
"Veranlagungsjahr", "Veranlagungsjahr",
# TTMMJJJJ
"Zugeordnete Fälligkeit", "Zugeordnete Fälligkeit",
# Weitere Felder # 1 = Einkauf von Waren
# 2 = Erwerb von Roh-Hilfs- und Betriebsstoffen
"Skontotyp", "Skontotyp",
# Anzahlungen # Allgemeine Bezeichnung, des Auftrags / Projekts.
"Auftragsnummer", "Auftragsnummer",
# AA = Angeforderte Anzahlung / Abschlagsrechnung
# AG = Erhaltene Anzahlung (Geldeingang)
# AV = Erhaltene Anzahlung (Verbindlichkeit)
# SR = Schlussrechnung
# SU = Schlussrechnung (Umbuchung)
# SG = Schlussrechnung (Geldeingang)
# SO = Sonstige
"Buchungstyp", "Buchungstyp",
"USt-Schlüssel (Anzahlungen)", "USt-Schlüssel (Anzahlungen)",
"EU-Land (Anzahlungen)", "EU-Mitgliedstaat (Anzahlungen)",
"Sachverhalt L+L (Anzahlungen)", "Sachverhalt L+L (Anzahlungen)",
"EU-Steuersatz (Anzahlungen)", "EU-Steuersatz (Anzahlungen)",
"Erlöskonto (Anzahlungen)", "Erlöskonto (Anzahlungen)",
# Stapelinformationen # Wird beim Import durch SV (Stapelverarbeitung) ersetzt.
"Herkunft-Kz", "Herkunft-Kz",
# Technische Identifikation # Wird von DATEV verwendet.
"Buchungs GUID", "Leerfeld",
# Kostenrechnung # Format TTMMJJJJ
"Kost-Datum", "KOST-Datum",
# OPOS-Informationen # Vom Zahlungsempfänger individuell vergebenes Kennzeichen eines Mandats
# (z.B. Rechnungs- oder Kundennummer).
"SEPA-Mandatsreferenz", "SEPA-Mandatsreferenz",
# 1 = Skontosperre
# 0 = Keine Skontosperre
"Skontosperre", "Skontosperre",
# Gesellschafter und Sonderbilanzsachverhalt # Gesellschafter und Sonderbilanzsachverhalt
"Gesellschaftername", "Gesellschaftername",
# Amtliche Nummer aus der Feststellungserklärung
"Beteiligtennummer", "Beteiligtennummer",
"Identifikationsnummer", "Identifikationsnummer",
"Zeichnernummer", "Zeichnernummer",
# OPOS-Informationen # Format TTMMJJJJ
"Postensperre bis", "Postensperre bis",
# Gesellschafter und Sonderbilanzsachverhalt # Gesellschafter und Sonderbilanzsachverhalt
"Bezeichnung SoBil-Sachverhalt", "Bezeichnung SoBil-Sachverhalt",
"Kennzeichen SoBil-Buchung", "Kennzeichen SoBil-Buchung",
# Stapelinformationen # 0 = keine Festschreibung
# 1 = Festschreibung
"Festschreibung", "Festschreibung",
# Datum # Format TTMMJJJJ
"Leistungsdatum", "Leistungsdatum",
# Format TTMMJJJJ
"Datum Zuord. Steuerperiode", "Datum Zuord. Steuerperiode",
# OPOS-Informationen # OPOS-Informationen, Format TTMMJJJJ
"Fälligkeit", "Fälligkeit",
# Konto/Gegenkonto # G oder 1 = Generalumkehr
# 0 = keine Generalumkehr
"Generalumkehr (GU)", "Generalumkehr (GU)",
# Steuersatz für Steuerschlüssel # Steuersatz für Steuerschlüssel
"Steuersatz", "Steuersatz",
# Beispiel: DE für Deutschland
"Land" "Land"
] ]
@@ -439,8 +472,8 @@ QUERY_REPORT_COLUMNS = [
"fieldtype": "Data", "fieldtype": "Data",
}, },
{ {
"label": "Kontonummer", "label": "Konto",
"fieldname": "Kontonummer", "fieldname": "Konto",
"fieldtype": "Data", "fieldtype": "Data",
}, },
{ {
@@ -453,6 +486,11 @@ QUERY_REPORT_COLUMNS = [
"fieldname": "Belegdatum", "fieldname": "Belegdatum",
"fieldtype": "Date", "fieldtype": "Date",
}, },
{
"label": "Belegfeld 1",
"fieldname": "Belegfeld 1",
"fieldtype": "Data",
},
{ {
"label": "Buchungstext", "label": "Buchungstext",
"fieldname": "Buchungstext", "fieldname": "Buchungstext",
@@ -460,21 +498,11 @@ QUERY_REPORT_COLUMNS = [
}, },
{ {
"label": "Beleginfo - Art 1", "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", "fieldname": "Beleginfo - Art 2",
"fieldtype": "Data", "fieldtype": "Data",
}, },
{ {
"label": "Beleginfo - Inhalt 2", "label": "Beleginfo - Inhalt 1",
"fieldname": "Beleginfo - Inhalt 2", "fieldname": "Beleginfo - Inhalt 2",
"fieldtype": "Data", "fieldtype": "Data",
} }
@@ -499,14 +527,17 @@ class FormatName():
class Transactions(): class Transactions():
DATA_CATEGORY = DataCategory.TRANSACTIONS DATA_CATEGORY = DataCategory.TRANSACTIONS
FORMAT_NAME = FormatName.TRANSACTIONS FORMAT_NAME = FormatName.TRANSACTIONS
FORMAT_VERSION = "9"
COLUMNS = TRANSACTION_COLUMNS COLUMNS = TRANSACTION_COLUMNS
class DebtorsCreditors(): class DebtorsCreditors():
DATA_CATEGORY = DataCategory.DEBTORS_CREDITORS DATA_CATEGORY = DataCategory.DEBTORS_CREDITORS
FORMAT_NAME = FormatName.DEBTORS_CREDITORS FORMAT_NAME = FormatName.DEBTORS_CREDITORS
FORMAT_VERSION = "5"
COLUMNS = DEBTOR_CREDITOR_COLUMNS COLUMNS = DEBTOR_CREDITOR_COLUMNS
class AccountNames(): class AccountNames():
DATA_CATEGORY = DataCategory.ACCOUNT_NAMES DATA_CATEGORY = DataCategory.ACCOUNT_NAMES
FORMAT_NAME = FormatName.ACCOUNT_NAMES FORMAT_NAME = FormatName.ACCOUNT_NAMES
FORMAT_VERSION = "2"
COLUMNS = ACCOUNT_NAME_COLUMNS COLUMNS = ACCOUNT_NAME_COLUMNS