Creating a budget overview from a SuperX export.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
2.5 KiB

""" superx_budget
Creating a budget overview from a SuperX export
"""
__version__ = "0.0.1"
from datetime import datetime
from collections import namedtuple
EXPECTED_HEADLINE = "Verwendungsnachweis und Kassenstand SAP"
EXPECTED_METADATA_KEYS = {"Haushaltsjahr", "Stand", "Gruppierung"}
EXPECTED_EXPORT_GROUPING = "automatisch"
EXPECTED_DATA_TABLE_HEADER = "Kostenstelle"
SuperXResult = namedtuple(
"SuperXResult", ["account_year", "export_date", "data"]
)
SuperXData = namedtuple(
"SuperXData",
[
"cost_center",
"fonds",
"project",
"kind",
"budget_year",
"obligo",
"expenses",
"revenue_actual",
"revenue_target",
"acutal_value",
],
)
class SuperXError(ValueError):
pass
def _check_export_headline(row):
""" checks the first line of the excel data if it's what we'd expect """
headline = row[0].value
if headline != EXPECTED_HEADLINE:
raise SuperXError(f"unexpected headline: '{headline}'")
def _get_export_metadata(row):
""" extracts the metadata from the second row of the excel sheet """
data = row[0].value
entries = data.split(";")
parts = [entry.split(":", 1) for entry in entries]
metadata = {key.strip(): value.strip() for key, value in parts}
if EXPECTED_METADATA_KEYS - set(metadata.keys()):
raise SuperXError(f"unexpected metadata: '{data}'")
if metadata["Gruppierung"] != EXPECTED_EXPORT_GROUPING:
raise SuperXError(f"unexpected grouping: {metadata['Gruppierung']}")
return SuperXResult(
metadata["Haushaltsjahr"],
datetime.strptime(metadata["Stand"], "%d.%m.%Y"),
None,
)
def _skip_export_data_until_table_header(rows):
""" skip rows until data table headers """
for line in rows:
first_cell = line[0]
if first_cell.value == EXPECTED_DATA_TABLE_HEADER:
break
else:
raise SuperXError("could not find table header")
def _parse_data_table(rows):
""" parses non-empty lines of the data table """
for line in rows:
if not line[0].value:
continue
data = [cell.value for cell in line[:10]]
yield SuperXData(*data)
def parse_export_data(xls_sheet):
""" parses the exported superx data """
rows = xls_sheet.rows
_check_export_headline(next(rows))
metadata = _get_export_metadata(next(rows))
_skip_export_data_until_table_header(rows)
data = list(_parse_data_table(rows))
return SuperXResult(metadata.account_year, metadata.export_date, data)