comdirect ingest: proper models

This commit is contained in:
2026-09-10 23:10:14 +02:00
parent 603be8db38
commit b93fd35f43
2 changed files with 56 additions and 19 deletions
+45 -18
View File
@@ -102,28 +102,51 @@ class Category(BaseModel):
return f'Category.from_str("{self.__str__()}")'
def _parse_date_german(date_str: str) -> date | None:
if date_str in ["offen", "neu", "--"]:
return None
day, month, year = list(map(int, date_str.split(".")))
return date(day=day, month=month, year=year)
def _parse_decimal_german(decimal_str: str) -> Decimal:
return Decimal(decimal_str.replace(".", "").replace(",", "."))
class ComdirectBase(BaseModel):
date_book: str = Field(alias="Buchungstag", examples=["07.09.2026"])
amount_eur: str = Field(alias="Umsatz in EUR", examples=["32,43"])
date_val: date | None = Field(alias="Wertstellung (Valuta)", examples=["07.09.2026"])
amount_eur: Decimal = Field(alias="Umsatz in EUR", examples=["32,43"])
@field_validator("date_val", mode="before")
@classmethod
def parse_date_val(cls, date_str: str) -> date | None:
return _parse_date_german(date_str)
@field_validator("amount_eur", mode="before")
@classmethod
def parse_amount(cls, decimal_str: str) -> Decimal:
return _parse_decimal_german(decimal_str)
class ComdirectCommon(ComdirectBase):
class ComdirectBaseBook(ComdirectBase):
date_book: date | None = Field(alias="Buchungstag", examples=["07.09.2026"])
@field_validator("date_book", mode="before")
@classmethod
def parse_date_book(cls, date_str: str) -> date | None:
return _parse_date_german(date_str)
class ComdirectGiro(ComdirectBaseBook):
type: str = Field(
alias="Vorgang", examples=["Lastschrift / Belastung", "Kartenumsatz"]
)
text: str = Field(alias="Buchungstext")
class ComdirectGiro(ComdirectCommon):
# "Buchungstag";"Wertstellung (Valuta)";"Vorgang";"Buchungstext";"Umsatz in EUR";
# "Buchungstag";"Wertstellung (Valuta)";"Vorgang";"Buchungstext";"Umsatz in EUR";
date_val: str = Field(alias="Wertstellung (Valuta)", examples=["07.09.2026"])
class ComdirectCreditCard(ComdirectCommon):
class ComdirectCreditCard(ComdirectBaseBook):
# "Buchungstag";"Umsatztag";"Vorgang";"Referenz";"Buchungstext";"Umsatz in EUR";
date_book: str = Field(alias="Buchungstag", examples=["07.09.2026"])
date_val: str = Field(alias="Umsatztag", default="")
date_book: date | None = Field(alias="Buchungstag", examples=["07.09.2026"])
date_val: date | None = Field(alias="Umsatztag", default=None)
type: str = Field(
alias="Vorgang",
examples=["Lastschrift / Belastung", "Kartenumsatz"],
@@ -131,14 +154,18 @@ class ComdirectCreditCard(ComdirectCommon):
)
reference: str = Field(alias="Referenz", default="")
text: str = Field(alias="Buchungstext", default="")
amount_eur: str = Field(alias="Umsatz in EUR", examples=["32,43"], default="")
amount_eur: Decimal | None = Field(alias="Umsatz in EUR", examples=["32,43"], default=None)
class ComdirectDepot(BaseModel):
# "Buchungstag";"Geschäftstag";"Stück / Nom.";"Bezeichnung";"WKN";"Währung";"Ausführungskurs";"Umsatz in EUR";
date_val: str = Field(alias="Geschäftstag")
num: str = Field(alias="Stück / Nom.")
class ComdirectDepot(ComdirectBase):
date_val: date | None = Field(alias="Geschäftstag")
num: Decimal = Field(alias="Stück / Nom.")
name: str = Field(alias="Bezeichnung")
wkn: str = Field(alias="WKN")
currency: str = Field(alias="Währung")
spot_price: str = Field(alias="Ausführungskurs")
spot_price: Decimal = Field(alias="Ausführungskurs")
@field_validator("num", "spot_price", mode="before")
@classmethod
def parse_decimals(cls, decimal_in: str) -> Decimal:
return _parse_decimal_german(decimal_in)
+11 -1
View File
@@ -1,10 +1,20 @@
from pathlib import Path
from src.models import ComdirectCreditCard, ComdirectDepot, ComdirectGiro
from src.reader import reader_comdirect
from src.settings.account_ingest import ACCOUNT_INGESTION_FUNCTIONS
def test_reader():
def test_reader_comdirect():
bank_name = "comdirect"
assert bank_name in ACCOUNT_INGESTION_FUNCTIONS
test_path = Path(".local/data/comdirect/umsaetze_9773063005_20260906-2043.csv")
assert test_path.exists()
data = reader_comdirect(test_path)
assert data
assert len(data) == len(ACCOUNT_INGESTION_FUNCTIONS.get(bank_name))
assert set(data) == set(ACCOUNT_INGESTION_FUNCTIONS.get(bank_name))
assert all(isinstance(row, ComdirectGiro) for row in data["Girokonto"])
assert all(isinstance(row, ComdirectCreditCard) for row in data["Visa-Karte (Kreditkarte)"])
assert all(isinstance(row, ComdirectGiro) for row in data["Tagesgeld PLUS-Konto"])
assert all(isinstance(row, ComdirectDepot) for row in data["Depot"])