|
|
|
""" Budget Parser """
|
|
|
|
|
|
|
|
from collections import namedtuple
|
|
|
|
|
|
|
|
from .helpers import get_sheet_of_file, strip_excel_value, is_empty_excel_value
|
|
|
|
from .exceptions import BudgetParserError
|
|
|
|
|
|
|
|
EXPECTED_TABLE_HEADERS = [
|
|
|
|
"Nr.",
|
|
|
|
"Projekt",
|
|
|
|
"Laufzeit",
|
|
|
|
"BA",
|
|
|
|
"Budget",
|
|
|
|
"Ausgaben",
|
|
|
|
"Rest",
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
ExcelRow = namedtuple("ExcelRow", ["row", "data"])
|
|
|
|
|
|
|
|
BudgetData = namedtuple(
|
|
|
|
"BudgetData",
|
|
|
|
[
|
|
|
|
"row",
|
|
|
|
"number",
|
|
|
|
"project_name",
|
|
|
|
"period",
|
|
|
|
"project",
|
|
|
|
"budget",
|
|
|
|
"expenses",
|
|
|
|
"rest",
|
|
|
|
],
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def _check_table_header(xl_row):
|
|
|
|
fields_ignore_none = (("" if c is None else c) for c in xl_row.data[:7])
|
|
|
|
fields_str = (str(c) for c in fields_ignore_none)
|
|
|
|
fields = [c.strip() for c in fields_str]
|
|
|
|
if fields != EXPECTED_TABLE_HEADERS:
|
|
|
|
raise BudgetParserError(f"unexpected headers: '{xl_row.data}'")
|
|
|
|
|
|
|
|
|
|
|
|
def _skip_empty_lines(rows):
|
|
|
|
for xl_row in rows:
|
|
|
|
first_cell = xl_row.data[0]
|
|
|
|
if is_empty_excel_value(first_cell):
|
|
|
|
continue
|
|
|
|
yield xl_row
|
|
|
|
|
|
|
|
|
|
|
|
def _parse_data_table(rows):
|
|
|
|
for xl_row in _skip_empty_lines(rows):
|
|
|
|
data = [strip_excel_value(value) for value in xl_row.data[:7]]
|
|
|
|
yield BudgetData(xl_row.row, *data)
|
|
|
|
|
|
|
|
|
|
|
|
def parse_budget_data(xls_sheet):
|
|
|
|
"""parses the budget data"""
|
|
|
|
rows = (ExcelRow(i, v) for i, v in enumerate(xls_sheet.values, start=1))
|
|
|
|
_check_table_header(next(rows))
|
|
|
|
return list(_parse_data_table(rows))
|
|
|
|
|
|
|
|
|
|
|
|
def parse_budget_file(file_path):
|
|
|
|
"""parses the budget file"""
|
|
|
|
sheet = get_sheet_of_file(file_path, sheet=None)
|
|
|
|
return parse_budget_data(sheet)
|