comdirect ingest: proper models
This commit is contained in:
+45
-18
@@ -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
@@ -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"])
|
||||
|
||||
Reference in New Issue
Block a user