feat(accounts): выключатель счёта, ручное создание брокерских счетов, брокеры в капитале
Отключённый счёт выпадает из всех скоупов, капитала и подсказок импорта, события остаются в леджере. Брокерский счёт без баланса попадает в net worth по оценке из леджера. POST /accounts заводит счёт под импорт отчёта, AccountOut отдаёт value_rub. Сверка со снапшотом не считает расхождением позиции счетов, у которых снапшота нет (отчёты Сбера и ВТБ).
This commit is contained in:
@@ -198,3 +198,69 @@ async def test_missing_fx_days_are_named_and_total_stays_computed(app):
|
||||
assert found[0].severity == "warn"
|
||||
assert found[0].count == 3 # every day of the series is affected
|
||||
assert found[0].ref == {"currencies": ["XBT"], "days": 3}
|
||||
|
||||
|
||||
async def _broker(name: str, amount: str = "100000", **kwargs) -> int:
|
||||
from factories import make_event
|
||||
from fintracker.models import AccountKind, EventKind
|
||||
|
||||
account = await make_account(
|
||||
name=name, kind=AccountKind.broker, role=AccountRole.investment, balance=None, **kwargs
|
||||
)
|
||||
await make_event(
|
||||
today_local() - timedelta(days=3), account_id=account, kind=EventKind.deposit, amount=amount
|
||||
)
|
||||
return account
|
||||
|
||||
|
||||
async def test_broker_accounts_count_through_their_ledger_valuation(app):
|
||||
t = today_local()
|
||||
await make_account(name="Карта", balance="5000")
|
||||
await make_txn(t - timedelta(days=5), outcome="100")
|
||||
await _broker("Брокер 1", "100000")
|
||||
await _broker("Брокер 2", "50000")
|
||||
await refresh()
|
||||
|
||||
rows = await series()
|
||||
assert rows[t].investment_rub == Decimal("150000")
|
||||
assert rows[t].liquid_rub == Decimal("5000")
|
||||
assert rows[t].total_rub == Decimal("155000")
|
||||
assert rows[t].by_currency["RUB"].startswith("155000")
|
||||
# before the deposits the brokers were worth nothing: only the card is left
|
||||
assert rows[t - timedelta(days=4)].investment_rub == Decimal("0")
|
||||
assert rows[t - timedelta(days=4)].total_rub == Decimal("5000")
|
||||
|
||||
|
||||
async def test_broker_switches_keep_an_account_out_of_net_worth(app):
|
||||
t = today_local()
|
||||
await make_account(name="Карта", balance="1000")
|
||||
await make_txn(t - timedelta(days=5), outcome="10")
|
||||
await _broker("Считается", "10000")
|
||||
await _broker("Не в капитале", "20000", include_in_net_worth=False)
|
||||
await _broker("Отключён", "40000", disabled=True)
|
||||
mirrored = await _broker("Оригинал", "80000")
|
||||
await make_account(name="Зеркало", balance="80000", mirror_of_account_id=mirrored)
|
||||
await refresh()
|
||||
|
||||
row = (await series())[t]
|
||||
# ledger side: «Считается» + «Оригинал»; the mirror and the two switched-off ones stay out
|
||||
assert row.investment_rub == Decimal("90000")
|
||||
assert row.total_rub == Decimal("91000")
|
||||
|
||||
|
||||
async def test_a_broker_account_without_balance_is_not_a_finding(app):
|
||||
await make_account(name="Карта", balance=None)
|
||||
await _broker("Брокер")
|
||||
await refresh()
|
||||
|
||||
named = [f.detail for f in await findings("account_without_balance")]
|
||||
assert len(named) == 1
|
||||
assert "Карта" in named[0]
|
||||
|
||||
|
||||
async def test_net_worth_of_brokers_alone_is_reported(app):
|
||||
await _broker("Единственный", "70000")
|
||||
await refresh()
|
||||
|
||||
rows = await series()
|
||||
assert rows[today_local()].total_rub == Decimal("70000")
|
||||
|
||||
Reference in New Issue
Block a user