Files
fin-tracker/backend/pyproject.toml
T
Dmitry 2e742a093b feat(reports): протокол и парсеры отчётов Сбера, ВТБ и Snowball CSV
sources/reports/base.py — контракт ReportParser (плагины: sniff/parse, чистые
функции без БД). registry.py выбирает парсер по содержимому файла, CSV
последним: он узнаёт файл по набору колонок и иначе перехватил бы чужой
формат.

Комиссия капитализируется в сделку, отдельным событием не эмитится: и Сбер,
и ВТБ печатают её дважды — колонками в сделках и строками в движении денег,
суммы совпадают, второе прочтение задвоило бы её. Расчётные строки («Сделка
от …», «Сальдо расчетов по сделкам») не эмитятся — это денежные ноги уже
учтённых сделок. У Сбера таблица «Информация о зачислениях на ИИС»
кумулятивна за календарный год и в леджер не идёт, иначе два пересекающихся
отчёта задвоили бы пополнения. CSV Snowball сводный по всем брокерам —
годится как сверка потоков и сделок на уровне портфеля, но не позиций по
счетам; CUSTOM_HOLDING_PRICE не событие, а цена — уходит в meta для
price_manual.

Обезличивание — anonymize.py + scripts/anonymize_reports.py, секреты
собираются по всему корпусу отчётов разом (Snowball цитирует номер договора
Сбера в примечании к переводу). test_fixtures_anonymized.py падает, если
в tests/fixtures/reports/ вне raw/ найдётся ИНН, ФИО или номер счёта — и по
форме (работает в CI без raw/), и по фактическому содержимому raw/, когда оно
на месте.
2026-09-19 10:39:37 +03:00

85 lines
1.9 KiB
TOML

[project]
name = "fintracker"
version = "0.1.0"
description = "Personal finance + investment analytics: ZenMoney and brokers in one place"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"fastapi>=0.115",
"uvicorn[standard]>=0.30",
"sqlalchemy[asyncio]>=2.0.36",
"asyncpg>=0.30",
"alembic>=1.14",
"pydantic[email]>=2.9",
"pydantic-settings>=2.5",
"httpx[socks]>=0.27",
"pyjwt>=2.9",
"pwdlib[argon2]>=0.2",
"typer>=0.12",
"apscheduler>=3.10,<4",
"python-multipart>=0.0.12",
"t-tech-investments>=1.51.0",
"pyxirr>=0.10.8",
"openpyxl>=3.1",
"lxml>=5.3",
]
[project.scripts]
fintracker = "fintracker.cli:app"
[dependency-groups]
dev = [
"pytest>=8.3",
"pytest-asyncio>=0.24",
"pytest-postgresql>=6.1",
"psycopg[binary]>=3.2",
"ruff>=0.7",
"pyright>=1.1.380",
"respx>=0.21",
]
# T-Invest SDK lives on T-Bank's own index (public PyPI copy is quarantined).
[[tool.uv.index]]
name = "tbank-invest"
url = "https://opensource.tbank.ru/api/v4/projects/238/packages/pypi/simple"
explicit = true
[tool.uv.sources]
t-tech-investments = { index = "tbank-invest" }
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/fintracker"]
[tool.ruff]
line-length = 100
src = ["src", "tests"]
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]
ignore = ["RUF001", "RUF002", "RUF003"] # cyrillic in strings/comments is intended
[tool.ruff.lint.per-file-ignores]
"tests/*" = ["E501"]
"alembic/versions/*" = ["E501"]
[tool.pyright]
venvPath = "."
venv = ".venv"
include = ["src", "tests"]
extraPaths = ["src"]
pythonVersion = "3.12"
typeCheckingMode = "standard"
reportMissingImports = "warning"
[tool.pytest.ini_options]
pythonpath = ["src"]
testpaths = ["tests"]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "session"
asyncio_default_test_loop_scope = "session"