Holger Frey
5 years ago
4 changed files with 121 additions and 120 deletions
@ -0,0 +1,85 @@ |
|||||||
|
""" SuperX Parser """ |
||||||
|
|
||||||
|
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] |
||||||
|
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] |
||||||
|
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 == 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]: |
||||||
|
continue |
||||||
|
yield SuperXData(*line[:10]) |
||||||
|
|
||||||
|
|
||||||
|
def parse_export_data(xls_sheet): |
||||||
|
""" parses the exported superx data """ |
||||||
|
rows = xls_sheet.values |
||||||
|
_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) |
@ -0,0 +1,10 @@ |
|||||||
|
from pathlib import Path |
||||||
|
|
||||||
|
import pytest |
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture |
||||||
|
def example_file(request): |
||||||
|
root_dir = Path(request.config.rootdir) |
||||||
|
data_dir = root_dir / "test data" |
||||||
|
return data_dir / "Verwendungsnachweis_und_Kassenstand_SAP_Zahlen.xlsx" |
Loading…
Reference in new issue