Verified Commit 5cb0e777 authored by Jakob Moser's avatar Jakob Moser
Browse files

Also load groups (using somewhat buggy heuristic)

parent 931bfcbc
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ output_rows = [
        remaining := item.amount - spent,
        item.amount,
    )
    for item in budget_plan.items.values()
    for item in budget_plan.items
]

formatted_output_rows = [
+22 −1
Original line number Diff line number Diff line
from dataclasses import dataclass
from typing import Self
from collections.abc import Iterable, Sequence

from .BudgetaryItem import BudgetaryItem
from .BudgetaryGroup import BudgetaryGroup


@dataclass(frozen=True, eq=False)
class BudgetPlan:

    items: dict[str, BudgetaryItem]
    _groups: dict[str, BudgetaryGroup]

    @classmethod
    def from_groups(cls, groups: Iterable[BudgetaryGroup]) -> Self:
        return cls({group.id: group for group in groups})

    @property
    def groups(self) -> Sequence[BudgetaryGroup]:
        return tuple(self._groups.values())

    def group(self, id: str) -> BudgetaryGroup:
        return self._groups

    @property
    def items(self) -> Sequence[BudgetaryItem]:
        return [item for group in self.groups for item in group.items]

    def item(self, id: str) -> BudgetaryItem:
        pass  # TODO
+61 −7
Original line number Diff line number Diff line
@@ -3,25 +3,79 @@ import subprocess
from pathlib import Path
from collections.abc import Sequence, Iterable

from ..amount.AmountParser import parse_euro_amount
from ..cash_flow.CashFlowDirection import CashFlowDirection

from .BudgetPlan import BudgetPlan
from .BudgetaryGroup import BudgetaryGroup
from .BudgetaryItem import BudgetaryItem
from ..amount.AmountParser import parse_euro_amount


def _is_budgetary_item_row(row: Sequence[str]) -> bool:
    return len(row) >= 3 and row[0] and row[1] and row[2]


def _parse_budgetary_item_row(row: Sequence[str]) -> BudgetaryItem:
    return BudgetaryItem(id=row[0], name=row[1], amount=parse_euro_amount(row[2]))


def _is_combined_row(row: Sequence[str]) -> bool:
    return row[0] and all(not row[i] for i in range(1, len(row)))


def _parse_combined_row(row: Sequence[str]) -> ...:
    lines = row[0].split("\n")

    return (lines[0][0], lines[0][1:])  # TODO


def _load_csv_lines(csv_lines: Iterable[str]) -> BudgetPlan:
    reader = csv.reader(csv_lines)
    items = [
        BudgetaryItem(id=row[0], name=row[1], amount=parse_euro_amount(row[2]))
        for row in reader
        if _is_budgetary_item_row(row)
    ]

    return BudgetPlan({item.id: item for item in items})
    groups: list[BudgetaryGroup] = []

    current_group_id: Optional[str] = None
    current_group_name: Optional[str] = None
    current_cash_flow_direction: Optional[CashFlowDirection] = None
    current_items: list[BudgetaryItem] = []

    def add_group():
        nonlocal current_group_id
        nonlocal current_group_name
        nonlocal current_items

        if current_group_id is None:
            return

        groups.append(
            BudgetaryGroup.from_items(
                id=current_group_id,
                name=current_group_name,
                cash_flow_direction=current_cash_flow_direction,
                items=current_items,
            )
        )

        current_group_id = None
        current_group_name = None
        current_items = []

    for row in reader:
        if not row:
            continue
        elif row[0] == "Einnahmen":
            current_cash_flow_direction = CashFlowDirection.INCOMING
        elif row[0] == "Ausgaben":
            current_cash_flow_direction = CashFlowDirection.OUTGOING
        elif _is_budgetary_item_row(row):
            current_items.append(_parse_budgetary_item_row(row))
        elif _is_combined_row(row):
            add_group()  # Add the previous group, which is now completed
            current_group_id, current_group_name = _parse_combined_row(row)

    add_group()  # Add the last group

    return BudgetPlan.from_groups(groups)


def load_csv(csv_path: Path | str) -> BudgetPlan:
+6 −0
Original line number Diff line number Diff line
from enum import Enum


class CashFlowDirection(Enum):
    INCOMING = 1
    OUTGOING = -1