Ingest comdirect #5
@@ -11,6 +11,7 @@ wheels/
|
|||||||
|
|
||||||
# Environment variables
|
# Environment variables
|
||||||
.env
|
.env
|
||||||
|
settings.py
|
||||||
|
|
||||||
# Database instances
|
# Database instances
|
||||||
*.db
|
*.db
|
||||||
|
|||||||
@@ -32,5 +32,6 @@ build-backend = "uv_build"
|
|||||||
dev = [
|
dev = [
|
||||||
"black>=26.5.1",
|
"black>=26.5.1",
|
||||||
"debugpy>=1.8.21",
|
"debugpy>=1.8.21",
|
||||||
|
"faker>=40.38.0",
|
||||||
"polyfactory>=3.3.0",
|
"polyfactory>=3.3.0",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
from faker import Faker
|
||||||
|
|
||||||
|
from src.models import ComdirectCreditCard, ComdirectDepot, ComdirectGiro
|
||||||
|
from src.settings.constants import Currency
|
||||||
|
from src.settings.models import AccountInfo
|
||||||
|
|
||||||
|
fake = Faker()
|
||||||
|
|
||||||
|
BANK_ACCOUNTS = {
|
||||||
|
"comdirect": {
|
||||||
|
"Girokonto": AccountInfo(
|
||||||
|
iban=fake.iban(),
|
||||||
|
ingestion_function=lambda x: ComdirectGiro.model_validate(x),
|
||||||
|
currency=Currency.EUR,
|
||||||
|
),
|
||||||
|
"Visa-Karte (Kreditkarte)": AccountInfo(
|
||||||
|
iban=fake.iban(),
|
||||||
|
ingestion_function=lambda x: ComdirectCreditCard.model_validate(x),
|
||||||
|
currency=Currency.EUR,
|
||||||
|
),
|
||||||
|
"Tagesgeld PLUS-Konto": AccountInfo(
|
||||||
|
iban=fake.iban(),
|
||||||
|
ingestion_function=lambda x: ComdirectGiro.model_validate(x),
|
||||||
|
currency=Currency.EUR,
|
||||||
|
),
|
||||||
|
"Depot": AccountInfo(
|
||||||
|
iban=fake.iban(),
|
||||||
|
ingestion_function=lambda x: ComdirectDepot.model_validate(x),
|
||||||
|
currency=Currency.EUR,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-14
@@ -4,20 +4,7 @@ from enum import Enum
|
|||||||
|
|
||||||
from pydantic import BaseModel, Field, field_validator
|
from pydantic import BaseModel, Field, field_validator
|
||||||
|
|
||||||
IBAN_PATTERN = r"^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$"
|
from src.settings.constants import IBAN_PATTERN, Currency
|
||||||
|
|
||||||
|
|
||||||
class Currency(str, Enum):
|
|
||||||
EUR = "EUR"
|
|
||||||
USD = "USD"
|
|
||||||
GBP = "GBP"
|
|
||||||
CHF = "CHF"
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.value
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f"Currency.{self.name}"
|
|
||||||
|
|
||||||
|
|
||||||
class Sign(str, Enum):
|
class Sign(str, Enum):
|
||||||
|
|||||||
+8
-9
@@ -3,8 +3,9 @@ import re
|
|||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from settings import BANK_ACCOUNTS
|
||||||
from src.models import B4wExport
|
from src.models import B4wExport
|
||||||
from src.settings.account_ingest import ACCOUNT_INGESTION_FUNCTIONS
|
from src.settings.models import AccountInfo
|
||||||
|
|
||||||
|
|
||||||
def _reader_raw(path: Path):
|
def _reader_raw(path: Path):
|
||||||
@@ -29,18 +30,16 @@ class EXPECT_LINE(Enum):
|
|||||||
DATA = auto()
|
DATA = auto()
|
||||||
|
|
||||||
|
|
||||||
|
COMDIRECT_ACCOUNTS = BANK_ACCOUNTS.get("comdirect", {})
|
||||||
|
assert isinstance(COMDIRECT_ACCOUNTS, dict)
|
||||||
|
|
||||||
def reader_comdirect(path: Path):
|
def reader_comdirect(path: Path):
|
||||||
bank_name = "comdirect"
|
|
||||||
ingestion_functions = ACCOUNT_INGESTION_FUNCTIONS.get(bank_name)
|
|
||||||
assert ingestion_functions
|
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
raw = _reader_raw_comdirect(path)
|
raw = _reader_raw_comdirect(path)
|
||||||
for account_name, account_data in raw.items():
|
for account_name, account_data in raw.items():
|
||||||
ingestion_function = ingestion_functions.get(account_name)
|
account = COMDIRECT_ACCOUNTS.get(account_name)
|
||||||
assert ingestion_function
|
assert isinstance(account, AccountInfo)
|
||||||
result[account_name] = list(map(ingestion_function, account_data))
|
result[account_name] = list(map(account.ingestion_function, account_data))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _reader_raw_comdirect(path: Path):
|
def _reader_raw_comdirect(path: Path):
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
from src.models import ComdirectCreditCard, ComdirectDepot, ComdirectGiro
|
|
||||||
|
|
||||||
ACCOUNT_INGESTION_FUNCTIONS = {
|
|
||||||
"comdirect": {
|
|
||||||
"Girokonto": lambda x: ComdirectGiro.model_validate(x),
|
|
||||||
"Visa-Karte (Kreditkarte)": lambda x: ComdirectCreditCard.model_validate(x),
|
|
||||||
"Tagesgeld PLUS-Konto": lambda x: ComdirectGiro.model_validate(x),
|
|
||||||
"Depot": lambda x: ComdirectDepot.model_validate(x),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
IBAN_PATTERN = r"^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$"
|
||||||
|
|
||||||
|
class Currency(str, Enum):
|
||||||
|
EUR = "EUR"
|
||||||
|
USD = "USD"
|
||||||
|
GBP = "GBP"
|
||||||
|
CHF = "CHF"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"Currency.{self.name}"
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
from collections.abc import Callable
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
from src.settings.constants import IBAN_PATTERN, Currency
|
||||||
|
|
||||||
|
|
||||||
|
class AccountInfo(BaseModel):
|
||||||
|
iban: str = Field(pattern=IBAN_PATTERN)
|
||||||
|
ingestion_function: Callable
|
||||||
|
currency: Currency
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,19 +1,18 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from src.models import ComdirectCreditCard, ComdirectDepot, ComdirectGiro
|
from src.models import ComdirectCreditCard, ComdirectDepot, ComdirectGiro
|
||||||
from src.reader import reader_comdirect
|
from src.reader import COMDIRECT_ACCOUNTS, reader_comdirect
|
||||||
from src.settings.account_ingest import ACCOUNT_INGESTION_FUNCTIONS
|
|
||||||
|
TEST_DATA_PATH = ".local/data/comdirect/umsaetze_9773063005_20260906-2043.csv"
|
||||||
|
|
||||||
|
|
||||||
def test_reader_comdirect():
|
def test_reader_comdirect():
|
||||||
bank_name = "comdirect"
|
test_path = Path(TEST_DATA_PATH)
|
||||||
assert bank_name in ACCOUNT_INGESTION_FUNCTIONS
|
|
||||||
test_path = Path(".local/data/comdirect/umsaetze_9773063005_20260906-2043.csv")
|
|
||||||
assert test_path.exists()
|
assert test_path.exists()
|
||||||
data = reader_comdirect(test_path)
|
data = reader_comdirect(test_path)
|
||||||
assert data
|
assert data
|
||||||
assert len(data) == len(ACCOUNT_INGESTION_FUNCTIONS.get(bank_name))
|
assert len(data) == len(COMDIRECT_ACCOUNTS)
|
||||||
assert set(data) == set(ACCOUNT_INGESTION_FUNCTIONS.get(bank_name))
|
assert set(data) == set(COMDIRECT_ACCOUNTS)
|
||||||
assert all(isinstance(row, ComdirectGiro) for row in data["Girokonto"])
|
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, ComdirectCreditCard) for row in data["Visa-Karte (Kreditkarte)"])
|
||||||
assert all(isinstance(row, ComdirectGiro) for row in data["Tagesgeld PLUS-Konto"])
|
assert all(isinstance(row, ComdirectGiro) for row in data["Tagesgeld PLUS-Konto"])
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ dependencies = [
|
|||||||
dev = [
|
dev = [
|
||||||
{ name = "black" },
|
{ name = "black" },
|
||||||
{ name = "debugpy" },
|
{ name = "debugpy" },
|
||||||
|
{ name = "faker" },
|
||||||
{ name = "polyfactory" },
|
{ name = "polyfactory" },
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -146,6 +147,7 @@ requires-dist = [
|
|||||||
dev = [
|
dev = [
|
||||||
{ name = "black", specifier = ">=26.5.1" },
|
{ name = "black", specifier = ">=26.5.1" },
|
||||||
{ name = "debugpy", specifier = ">=1.8.21" },
|
{ name = "debugpy", specifier = ">=1.8.21" },
|
||||||
|
{ name = "faker", specifier = ">=40.38.0" },
|
||||||
{ name = "polyfactory", specifier = ">=3.3.0" },
|
{ name = "polyfactory", specifier = ">=3.3.0" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user