Merge pull request #22487 from frappe/mergify/bp/version-13-beta-pre-release/pr-21690
fix(regional): DATEV report (bp #21690)
This commit is contained in:
commit
23c64c0b3a
@ -8,17 +8,18 @@ Provide a report and downloadable CSV according to the German DATEV format.
|
|||||||
all required columns. Used to import the data into the DATEV Software.
|
all required columns. Used to import the data into the DATEV Software.
|
||||||
"""
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
import zlib
|
|
||||||
import zipfile
|
import zipfile
|
||||||
import six
|
import six
|
||||||
|
import frappe
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
from frappe import _
|
||||||
from csv import QUOTE_NONNUMERIC
|
from csv import QUOTE_NONNUMERIC
|
||||||
from six import BytesIO
|
from six import BytesIO
|
||||||
from six import string_types
|
from six import string_types
|
||||||
import frappe
|
|
||||||
from frappe import _
|
|
||||||
import pandas as pd
|
|
||||||
from .datev_constants import DataCategory
|
from .datev_constants import DataCategory
|
||||||
from .datev_constants import Transactions
|
from .datev_constants import Transactions
|
||||||
from .datev_constants import DebtorsCreditors
|
from .datev_constants import DebtorsCreditors
|
||||||
@ -130,8 +131,10 @@ def get_customers(filters):
|
|||||||
SELECT
|
SELECT
|
||||||
|
|
||||||
acc.account_number as 'Konto',
|
acc.account_number as 'Konto',
|
||||||
cus.customer_name as 'Name (Adressatentyp Unternehmen)',
|
CASE cus.customer_type WHEN 'Company' THEN cus.customer_name ELSE null END as 'Name (Adressatentyp Unternehmen)',
|
||||||
case cus.customer_type when 'Individual' then 1 when 'Company' then 2 else 0 end as 'Adressatentyp',
|
CASE cus.customer_type WHEN 'Individual' THEN con.last_name ELSE null END as 'Name (Adressatentyp natürl. Person)',
|
||||||
|
CASE cus.customer_type WHEN 'Individual' THEN con.first_name ELSE null END as 'Vorname (Adressatentyp natürl. Person)',
|
||||||
|
CASE cus.customer_type WHEN 'Individual' THEN '1' WHEN 'Company' THEN '2' ELSE '0' end as 'Adressatentyp',
|
||||||
adr.address_line1 as 'Straße',
|
adr.address_line1 as 'Straße',
|
||||||
adr.pincode as 'Postleitzahl',
|
adr.pincode as 'Postleitzahl',
|
||||||
adr.city as 'Ort',
|
adr.city as 'Ort',
|
||||||
@ -140,8 +143,7 @@ def get_customers(filters):
|
|||||||
con.email_id as 'E-Mail',
|
con.email_id as 'E-Mail',
|
||||||
coalesce(con.mobile_no, con.phone) as 'Telefon',
|
coalesce(con.mobile_no, con.phone) as 'Telefon',
|
||||||
cus.website as 'Internet',
|
cus.website as 'Internet',
|
||||||
cus.tax_id as 'Steuernummer',
|
cus.tax_id as 'Steuernummer'
|
||||||
ccl.credit_limit as 'Kreditlimit (Debitor)'
|
|
||||||
|
|
||||||
FROM `tabParty Account` par
|
FROM `tabParty Account` par
|
||||||
|
|
||||||
@ -160,10 +162,6 @@ def get_customers(filters):
|
|||||||
left join `tabContact` con
|
left join `tabContact` con
|
||||||
on con.name = cus.customer_primary_contact
|
on con.name = cus.customer_primary_contact
|
||||||
|
|
||||||
left join `tabCustomer Credit Limit` ccl
|
|
||||||
on ccl.parent = cus.name
|
|
||||||
and ccl.company = par.company
|
|
||||||
|
|
||||||
WHERE par.company = %(company)s
|
WHERE par.company = %(company)s
|
||||||
AND par.parenttype = 'Customer'""", filters, as_dict=1)
|
AND par.parenttype = 'Customer'""", filters, as_dict=1)
|
||||||
|
|
||||||
@ -179,8 +177,10 @@ def get_suppliers(filters):
|
|||||||
SELECT
|
SELECT
|
||||||
|
|
||||||
acc.account_number as 'Konto',
|
acc.account_number as 'Konto',
|
||||||
sup.supplier_name as 'Name (Adressatentyp Unternehmen)',
|
CASE sup.supplier_type WHEN 'Company' THEN sup.supplier_name ELSE null END as 'Name (Adressatentyp Unternehmen)',
|
||||||
case sup.supplier_type when 'Individual' then '1' when 'Company' then '2' else '0' end as 'Adressatentyp',
|
CASE sup.supplier_type WHEN 'Individual' THEN con.last_name ELSE null END as 'Name (Adressatentyp natürl. Person)',
|
||||||
|
CASE sup.supplier_type WHEN 'Individual' THEN con.first_name ELSE null END as 'Vorname (Adressatentyp natürl. Person)',
|
||||||
|
CASE sup.supplier_type WHEN 'Individual' THEN '1' WHEN 'Company' THEN '2' ELSE '0' end as 'Adressatentyp',
|
||||||
adr.address_line1 as 'Straße',
|
adr.address_line1 as 'Straße',
|
||||||
adr.pincode as 'Postleitzahl',
|
adr.pincode as 'Postleitzahl',
|
||||||
adr.city as 'Ort',
|
adr.city as 'Ort',
|
||||||
@ -226,9 +226,18 @@ def get_suppliers(filters):
|
|||||||
|
|
||||||
|
|
||||||
def get_account_names(filters):
|
def get_account_names(filters):
|
||||||
return frappe.get_list("Account",
|
return frappe.db.sql("""
|
||||||
fields=["account_number as Konto", "name as Kontenbeschriftung"],
|
SELECT
|
||||||
filters={"company": filters.get("company"), "is_group": "0"})
|
|
||||||
|
account_number as 'Konto',
|
||||||
|
LEFT(account_name, 40) as 'Kontenbeschriftung',
|
||||||
|
'de-DE' as 'Sprach-ID'
|
||||||
|
|
||||||
|
FROM `tabAccount`
|
||||||
|
WHERE company = %(company)s
|
||||||
|
AND is_group = 0
|
||||||
|
AND account_number != ''
|
||||||
|
""", filters, as_dict=1)
|
||||||
|
|
||||||
|
|
||||||
def get_datev_csv(data, filters, csv_class):
|
def get_datev_csv(data, filters, csv_class):
|
||||||
@ -287,9 +296,7 @@ def get_datev_csv(data, filters, csv_class):
|
|||||||
|
|
||||||
|
|
||||||
def get_header(filters, csv_class):
|
def get_header(filters, csv_class):
|
||||||
coa = frappe.get_value("Company", filters.get("company"), "chart_of_accounts")
|
description = filters.get('voucher_type', csv_class.FORMAT_NAME)
|
||||||
description = filters.get("voucher_type", csv_class.FORMAT_NAME)
|
|
||||||
coa_used = "04" if "SKR04" in coa else ("03" if "SKR03" in coa else "")
|
|
||||||
|
|
||||||
header = [
|
header = [
|
||||||
# DATEV format
|
# DATEV format
|
||||||
@ -316,19 +323,19 @@ def get_header(filters, csv_class):
|
|||||||
# 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"),
|
filters.get('consultant_number', '0000000'),
|
||||||
# L = Tax client number (Mandantennummer)
|
# L = Tax client number (Mandantennummer)
|
||||||
frappe.get_value("DATEV Settings", filters.get("company"), "client_number"),
|
filters.get('client_number', '00000'),
|
||||||
# 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',
|
'%d' % filters.get('acc_len', 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") if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '',
|
||||||
# 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") if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '',
|
||||||
# Q = Description (for example, "Sales Invoice") Max. 30 chars
|
# Q = Description (for example, "Sales Invoice") Max. 30 chars
|
||||||
'"{}"'.format(_(description)),
|
'"{}"'.format(_(description)) if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '',
|
||||||
# R = Diktatkürzel
|
# R = Diktatkürzel
|
||||||
'',
|
'',
|
||||||
# S = Buchungstyp
|
# S = Buchungstyp
|
||||||
@ -343,12 +350,12 @@ def get_header(filters, csv_class):
|
|||||||
# 40 = Kalkulatorik
|
# 40 = Kalkulatorik
|
||||||
# 11 = Reserviert
|
# 11 = Reserviert
|
||||||
# 12 = Reserviert
|
# 12 = Reserviert
|
||||||
'0',
|
'0' if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '',
|
||||||
# U = Festschreibung
|
# U = Festschreibung
|
||||||
# TODO: Filter by Accounting Period. In export for closed Accounting Period, this will be "1"
|
# TODO: Filter by Accounting Period. In export for closed Accounting Period, this will be "1"
|
||||||
'0',
|
'0',
|
||||||
# V = Default currency, for example, "EUR"
|
# V = Default currency, for example, "EUR"
|
||||||
'"%s"' % frappe.get_value("Company", filters.get("company"), "default_currency"),
|
'"%s"' % filters.get('default_currency', 'EUR') if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '',
|
||||||
# reserviert
|
# reserviert
|
||||||
'',
|
'',
|
||||||
# Derivatskennzeichen
|
# Derivatskennzeichen
|
||||||
@ -358,7 +365,7 @@ def get_header(filters, csv_class):
|
|||||||
# reserviert
|
# reserviert
|
||||||
'',
|
'',
|
||||||
# SKR
|
# SKR
|
||||||
'"%s"' % coa_used,
|
'"%s"' % filters.get('skr', '04'),
|
||||||
# Branchen-Lösungs-ID
|
# Branchen-Lösungs-ID
|
||||||
'',
|
'',
|
||||||
# reserviert
|
# reserviert
|
||||||
@ -389,6 +396,18 @@ def download_datev_csv(filters=None):
|
|||||||
|
|
||||||
validate(filters)
|
validate(filters)
|
||||||
|
|
||||||
|
# set chart of accounts used
|
||||||
|
coa = frappe.get_value('Company', filters.get('company'), 'chart_of_accounts')
|
||||||
|
filters['skr'] = '04' if 'SKR04' in coa else ('03' if 'SKR03' in coa else '')
|
||||||
|
|
||||||
|
# set account number length
|
||||||
|
account_numbers = frappe.get_list('Account', fields=['account_number'], filters={'is_group': 0, 'account_number': ('!=', '')})
|
||||||
|
filters['acc_len'] = max([len(a.account_number) for a in account_numbers])
|
||||||
|
|
||||||
|
filters['consultant_number'] = frappe.get_value('DATEV Settings', filters.get('company'), 'consultant_number')
|
||||||
|
filters['client_number'] = frappe.get_value('DATEV Settings', filters.get('company'), 'client_number')
|
||||||
|
filters['default_currency'] = frappe.get_value('Company', filters.get('company'), 'default_currency')
|
||||||
|
|
||||||
# This is where my zip will be written
|
# This is where my zip will be written
|
||||||
zip_buffer = BytesIO()
|
zip_buffer = BytesIO()
|
||||||
# This is my zip file
|
# This is my zip file
|
||||||
|
@ -465,60 +465,71 @@ QUERY_REPORT_COLUMNS = [
|
|||||||
"label": "Umsatz (ohne Soll/Haben-Kz)",
|
"label": "Umsatz (ohne Soll/Haben-Kz)",
|
||||||
"fieldname": "Umsatz (ohne Soll/Haben-Kz)",
|
"fieldname": "Umsatz (ohne Soll/Haben-Kz)",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
|
"width": 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Soll/Haben-Kennzeichen",
|
"label": "Soll/Haben-Kennzeichen",
|
||||||
"fieldname": "Soll/Haben-Kennzeichen",
|
"fieldname": "Soll/Haben-Kennzeichen",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
|
"width": 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Konto",
|
"label": "Konto",
|
||||||
"fieldname": "Konto",
|
"fieldname": "Konto",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
|
"width": 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Gegenkonto (ohne BU-Schlüssel)",
|
"label": "Gegenkonto (ohne BU-Schlüssel)",
|
||||||
"fieldname": "Gegenkonto (ohne BU-Schlüssel)",
|
"fieldname": "Gegenkonto (ohne BU-Schlüssel)",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
|
"width": 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Belegdatum",
|
"label": "Belegdatum",
|
||||||
"fieldname": "Belegdatum",
|
"fieldname": "Belegdatum",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
|
"width": 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Belegfeld 1",
|
"label": "Belegfeld 1",
|
||||||
"fieldname": "Belegfeld 1",
|
"fieldname": "Belegfeld 1",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
|
"width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Buchungstext",
|
"label": "Buchungstext",
|
||||||
"fieldname": "Buchungstext",
|
"fieldname": "Buchungstext",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Text",
|
||||||
|
"width": 300
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Beleginfo - Art 1",
|
"label": "Beleginfo - Art 1",
|
||||||
"fieldname": "Beleginfo - Art 1",
|
"fieldname": "Beleginfo - Art 1",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "DocType"
|
"options": "DocType",
|
||||||
|
"width": 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Beleginfo - Inhalt 1",
|
"label": "Beleginfo - Inhalt 1",
|
||||||
"fieldname": "Beleginfo - Inhalt 1",
|
"fieldname": "Beleginfo - Inhalt 1",
|
||||||
"fieldtype": "Dynamic Link",
|
"fieldtype": "Dynamic Link",
|
||||||
"options": "Beleginfo - Art 1"
|
"options": "Beleginfo - Art 1",
|
||||||
|
"width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Beleginfo - Art 2",
|
"label": "Beleginfo - Art 2",
|
||||||
"fieldname": "Beleginfo - Art 2",
|
"fieldname": "Beleginfo - Art 2",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "DocType"
|
"options": "DocType",
|
||||||
|
"width": 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Beleginfo - Inhalt 2",
|
"label": "Beleginfo - Inhalt 2",
|
||||||
"fieldname": "Beleginfo - Inhalt 2",
|
"fieldname": "Beleginfo - Inhalt 2",
|
||||||
"fieldtype": "Dynamic Link",
|
"fieldtype": "Dynamic Link",
|
||||||
"options": "Beleginfo - Art 2"
|
"options": "Beleginfo - Art 2",
|
||||||
|
"width": 150
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user