broker-sync/tests/test_models.py

127 lines
3.5 KiB
Python
Raw Normal View History

from datetime import UTC, datetime
from decimal import Decimal
import pytest
from broker_sync.models import (
Account,
AccountType,
Activity,
ActivityType,
FxRateSource,
)
def test_account_type_covers_uk_wrappers() -> None:
assert {
AccountType.ISA,
AccountType.SIPP,
AccountType.GIA,
AccountType.LISA,
AccountType.JISA,
AccountType.WORKPLACE_PENSION,
} <= set(AccountType)
def test_activity_type_covers_wealthfolio_types() -> None:
# Mirrors Wealthfolio docs/activities/activity-types.md
for name in (
"BUY",
"SELL",
"DIVIDEND",
"INTEREST",
"DEPOSIT",
"WITHDRAWAL",
"TRANSFER_IN",
"TRANSFER_OUT",
"CONVERSION_IN",
"CONVERSION_OUT",
"FEE",
"TAX",
):
assert hasattr(ActivityType, name), f"missing {name}"
def test_activity_minimal_construct() -> None:
a = Activity(
external_id="t212:order:1",
account_id="t212-isa",
account_type=AccountType.ISA,
date=datetime(2026, 1, 15, tzinfo=UTC),
activity_type=ActivityType.BUY,
symbol="VUAG",
quantity=Decimal("10"),
unit_price=Decimal("85.5"),
currency="GBP",
)
assert a.external_id == "t212:order:1"
assert a.fee == Decimal("0")
assert a.fx_rate_source is None
def test_buy_requires_qty_and_price() -> None:
with pytest.raises(ValueError, match="BUY.*quantity"):
Activity(
external_id="x",
account_id="a",
account_type=AccountType.GIA,
date=datetime(2026, 1, 1, tzinfo=UTC),
activity_type=ActivityType.BUY,
symbol="VUAG",
currency="GBP",
)
def test_dividend_requires_amount() -> None:
with pytest.raises(ValueError, match="DIVIDEND.*amount"):
Activity(
external_id="x",
account_id="a",
account_type=AccountType.GIA,
date=datetime(2026, 1, 1, tzinfo=UTC),
activity_type=ActivityType.DIVIDEND,
currency="GBP",
)
def test_wealthfolio_csv_row_shape() -> None:
a = Activity(
external_id="ie:2026-04:0001",
account_id="ie-isa",
account_type=AccountType.ISA,
date=datetime(2026, 4, 1, 10, 30, tzinfo=UTC),
activity_type=ActivityType.BUY,
symbol="VWRP",
quantity=Decimal("2.5"),
unit_price=Decimal("110.00"),
currency="GBP",
fee=Decimal("0.50"),
amount_gbp=Decimal("275.50"),
fx_rate_gbp=Decimal("1.0"),
fx_rate_source=FxRateSource.ECB_LIVE,
notes="sync:invest-engine:ie:2026-04:0001",
)
row = a.to_wealthfolio_csv_row()
# Wealthfolio activity import columns (from docs):
# date, activity_type, symbol, quantity, unit_price, currency, fee, amount, notes, ...
assert row["date"] == "2026-04-01T10:30:00+00:00"
assert row["activity_type"] == "BUY"
assert row["symbol"] == "VWRP"
assert row["quantity"] == "2.5"
assert row["unit_price"] == "110.00"
assert row["currency"] == "GBP"
assert row["fee"] == "0.50"
assert row["notes"] == "sync:invest-engine:ie:2026-04:0001"
def test_account_construct() -> None:
acc = Account(
id="t212-isa",
name="Trading212 ISA",
account_type=AccountType.ISA,
currency="GBP",
provider="trading212",
)
assert acc.id == "t212-isa"
assert acc.account_type is AccountType.ISA