feat: сеть (network) для крипто-холдингов

Свободное текстовое поле на холдинге — какой сети принадлежит конкретная
монета (Ethereum, Tron и т.д.), с редактированием прямо в таблице и
разбивкой % по сетям на отдельной вкладке. Помогает увидеть, что часть
стейблкоинов лежит на рискованных сетях и стоит перевести на безопасные.
This commit is contained in:
ZProger
2026-09-09 00:52:11 +03:00
parent 526bfe104d
commit c3047c6d6a
16 changed files with 421 additions and 13 deletions

View File

@@ -42,6 +42,7 @@ from app.schemas.crypto import (
CryptoHistoryResponse,
CryptoHoldingCreate,
CryptoHoldingRead,
CryptoHoldingUpdate,
CryptoPerformancePoint,
CryptoPerformanceResponse,
CryptoPortfolioCreate,
@@ -217,6 +218,7 @@ def _to_read(holding: CryptoHolding) -> CryptoHoldingRead:
name=holding.name,
thumb_url=holding.thumb_url,
risk_level=holding.asset.risk_level,
network=holding.network,
quantity=quantity,
avg_buy_price=avg_buy_price,
current_price=current_price,
@@ -442,6 +444,7 @@ async def create_holding(session: AsyncSession, payload: CryptoHoldingCreate) ->
symbol=payload.symbol.upper(),
name=payload.name,
thumb_url=payload.thumb_url,
network=payload.network,
)
# Wired explicitly rather than left for a lazy load off asset_id — under
# async SQLAlchemy, a relationship access with no eager load and no prior
@@ -488,6 +491,17 @@ async def create_holding(session: AsyncSession, payload: CryptoHoldingCreate) ->
return _to_read(holding)
async def update_holding(session: AsyncSession, asset_id: int, payload: CryptoHoldingUpdate) -> CryptoHoldingRead:
"""Updates CryptoHolding-only metadata — currently just `network`.
Quantity/price/date go through add_transaction/update_transaction
instead; risk_level lives on the Asset via PATCH /assets/{asset_id}."""
holding = await _get_holding_or_404(session, asset_id)
for field, value in payload.model_dump(exclude_unset=True).items():
setattr(holding, field, value)
await session.commit()
return _to_read(holding)
async def add_transaction(session: AsyncSession, asset_id: int, payload: CryptoTransactionCreate) -> CryptoHoldingRead:
"""A buy or sell against an existing holding — never calls CoinGecko
(see module docstring): value is recomputed from the last cached