brotherton-erpnext/erpnext/regional/report/datev/test_datev.py
Raffael Meyer 0de066c3b1 feat(regional): Add master data to DATEV Export (#18755)
* Add master data to export

* add SQL statements to get customers and suppliers

* make data category a string

* fix SQL error

* fix SQL errors

* unique column names

* add encoding of constants

* get customer primary address and contact

* fix typo

* fix typo

* binary response

* add filename

* add filecontent

* rename account columns

* exclude account groups

* use compression, close file before transfer

* fix StringIO

* add basic tests

* fix assertion, merge test methods

* fix indentation

* relative import of constants

* fix path

* import os

* Add default currency to test company

* root accounts with parent = null

* move account-related things to setup()

* add: test headers

* company and filters become class properties

* add: test csv creation

* (fix): add missing account

* (fix): remove wrong space

* add items to sales invoice

* refactor: create test data

* fix: create cost center

* fix: doctype Accoutn

* fix: make sure account belongs to company

* fix: remove customer group and territory, save on a new line

* create default warehouses

* fix: make Item myself

* fix: item defaults are a list

* fix: use my own warehouse

* fix: use my own expense account

* fix: let you take care of the Sales Invoice Item

* fix: import zipfile

* add TODOs

* fix: workaround for pandas bug

* SQL: utf-8 everywhere to make conversion in tests unnecessary

* tests: zipfile must be encoded string

* fix(tests): invalid start byte

* fix(test): give is_zipfile() the file-like object it expects

* fix(test): fix encoding of colums

* fix(get_transactions): as_dict is 1 by default

* fix(tests): allow empty data

* refactor: rename columns in get_account_names

* fix(pandas): keep sorting columns

* fix: "lineterminator" must be a string

* fix(test): check if cost center exists

* fix: credit limit became a child table

* fix: save company after creation

* insert instead of save

* tests: setup_fiscal_year

* fix(test): import cstr

* fix(tests): fiscal year

* fix: can't concat str to bytes

* fix: make csv-encoding work for py2 and py3

* fix(test): use frappe.as_unicode instead of unicode

* fix: use BytesIO instead of StringIO for py3 compatibility

* fix(tests): use BytesIO instead of StringIO for py3 compatibility
2019-11-29 17:32:17 +05:30

245 lines
7.2 KiB
Python

# coding=utf-8
from __future__ import unicode_literals
import os
import json
import zipfile
from six import BytesIO
from unittest import TestCase
import frappe
from frappe.utils import getdate, today, now_datetime, cstr
from frappe.test_runner import make_test_objects
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts
from erpnext.regional.report.datev.datev import validate
from erpnext.regional.report.datev.datev import get_transactions
from erpnext.regional.report.datev.datev import get_customers
from erpnext.regional.report.datev.datev import get_suppliers
from erpnext.regional.report.datev.datev import get_account_names
from erpnext.regional.report.datev.datev import get_datev_csv
from erpnext.regional.report.datev.datev import get_header
from erpnext.regional.report.datev.datev import download_datev_csv
from erpnext.regional.report.datev.datev_constants import DataCategory
from erpnext.regional.report.datev.datev_constants import Transactions
from erpnext.regional.report.datev.datev_constants import DebtorsCreditors
from erpnext.regional.report.datev.datev_constants import AccountNames
from erpnext.regional.report.datev.datev_constants import QUERY_REPORT_COLUMNS
def make_company(company_name, abbr):
if not frappe.db.exists("Company", company_name):
company = frappe.get_doc({
"doctype": "Company",
"company_name": company_name,
"abbr": abbr,
"default_currency": "EUR",
"country": "Germany",
"create_chart_of_accounts_based_on": "Standard Template",
"chart_of_accounts": "SKR04 mit Kontonummern"
})
company.insert()
else:
company = frappe.get_doc("Company", company_name)
# indempotent
company.create_default_warehouses()
if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": company.name}):
company.create_default_cost_center()
company.save()
return company
def setup_fiscal_year():
fiscal_year = None
year = cstr(now_datetime().year)
if not frappe.db.get_value("Fiscal Year", {"year": year}, "name"):
try:
fiscal_year = frappe.get_doc({
"doctype": "Fiscal Year",
"year": year,
"year_start_date": "{0}-01-01".format(year),
"year_end_date": "{0}-12-31".format(year)
})
fiscal_year.insert()
except frappe.NameError:
pass
if fiscal_year:
fiscal_year.set_as_default()
def make_customer_with_account(customer_name, company):
acc_name = frappe.db.get_value("Account", {
"account_name": customer_name,
"company": company.name
}, "name")
if not acc_name:
acc = frappe.get_doc({
"doctype": "Account",
"parent_account": "1 - Forderungen aus Lieferungen und Leistungen - _TG",
"account_name": customer_name,
"company": company.name,
"account_type": "Receivable",
"account_number": "10001"
})
acc.insert()
acc_name = acc.name
if not frappe.db.exists("Customer", customer_name):
customer = frappe.get_doc({
"doctype": "Customer",
"customer_name": customer_name,
"customer_type": "Company",
"accounts": [{
"company": company.name,
"account": acc_name
}]
})
customer.insert()
else:
customer = frappe.get_doc("Customer", customer_name)
return customer
def make_item(item_code, company):
warehouse_name = frappe.db.get_value("Warehouse", {
"warehouse_name": "Stores",
"company": company.name
}, "name")
if not frappe.db.exists("Item", item_code):
item = frappe.get_doc({
"doctype": "Item",
"item_code": item_code,
"item_name": item_code,
"description": item_code,
"item_group": "All Item Groups",
"is_stock_item": 0,
"is_purchase_item": 0,
"is_customer_provided_item": 0,
"item_defaults": [{
"default_warehouse": warehouse_name,
"company": company.name
}]
})
item.insert()
else:
item = frappe.get_doc("Item", item_code)
return item
def make_datev_settings(company):
if not frappe.db.exists("DATEV Settings", company.name):
frappe.get_doc({
"doctype": "DATEV Settings",
"client": company.name,
"client_number": "12345",
"consultant_number": "67890"
}).insert()
class TestDatev(TestCase):
def setUp(self):
self.company = make_company("_Test GmbH", "_TG")
self.customer = make_customer_with_account("_Test Kunde GmbH", self.company)
self.filters = {
"company": self.company.name,
"from_date": today(),
"to_date": today()
}
make_datev_settings(self.company)
item = make_item("_Test Item", self.company)
setup_fiscal_year()
warehouse = frappe.db.get_value("Item Default", {
"parent": item.name,
"company": self.company.name
}, "default_warehouse")
income_account = frappe.db.get_value("Account", {
"account_number": "4200",
"company": self.company.name
}, "name")
tax_account = frappe.db.get_value("Account", {
"account_number": "3806",
"company": self.company.name
}, "name")
si = create_sales_invoice(
company=self.company.name,
customer=self.customer.name,
currency=self.company.default_currency,
debit_to=self.customer.accounts[0].account,
income_account="4200 - Erlöse - _TG",
expense_account="6990 - Herstellungskosten - _TG",
cost_center=self.company.cost_center,
warehouse=warehouse,
item=item.name,
do_not_save=1
)
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": tax_account,
"description": "Umsatzsteuer 19 %",
"rate": 19
})
si.save()
si.submit()
def test_columns(self):
def is_subset(get_data, allowed_keys):
"""
Validate that the dict contains only allowed keys.
Params:
get_data -- Function that returns a list of dicts.
allowed_keys -- List of allowed keys
"""
data = get_data(self.filters)
if data == []:
# No data and, therefore, no columns is okay
return True
actual_set = set(data[0].keys())
# allowed set must be interpreted as unicode to match the actual set
allowed_set = set({frappe.as_unicode(key) for key in allowed_keys})
return actual_set.issubset(allowed_set)
self.assertTrue(is_subset(get_transactions, Transactions.COLUMNS))
self.assertTrue(is_subset(get_customers, DebtorsCreditors.COLUMNS))
self.assertTrue(is_subset(get_suppliers, DebtorsCreditors.COLUMNS))
self.assertTrue(is_subset(get_account_names, AccountNames.COLUMNS))
def test_header(self):
self.assertTrue(Transactions.DATA_CATEGORY in get_header(self.filters, Transactions))
self.assertTrue(AccountNames.DATA_CATEGORY in get_header(self.filters, AccountNames))
self.assertTrue(DebtorsCreditors.DATA_CATEGORY in get_header(self.filters, DebtorsCreditors))
def test_csv(self):
test_data = [{
"Umsatz (ohne Soll/Haben-Kz)": 100,
"Soll/Haben-Kennzeichen": "H",
"Kontonummer": "4200",
"Gegenkonto (ohne BU-Schlüssel)": "10000",
"Belegdatum": today(),
"Buchungstext": "No remark",
"Beleginfo - Art 1": "Sales Invoice",
"Beleginfo - Inhalt 1": "SINV-0001"
}]
get_datev_csv(data=test_data, filters=self.filters, csv_class=Transactions)
def test_download(self):
"""Assert that the returned file is a ZIP file."""
download_datev_csv(self.filters)
# zipfile.is_zipfile() expects a file-like object
zip_buffer = BytesIO()
zip_buffer.write(frappe.response['filecontent'])
self.assertTrue(zipfile.is_zipfile(zip_buffer))