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.
91 lines
2.5 KiB
91 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)
|
|
|