0.2.39: bitcoin-denominated view, first-login flow, unfunded + tax center
- BTC prices: btc_prices table, CSV upload on Import page (auto-detected date/close columns, upsert by date), entities.close_date as the BTC entry mark; statements carry btc_price_cents (as-of) + btc_close_price_cents. LP capital blocks show paid-in vs current value in bitcoin terms. - First login: accounts on the shared default password are flagged (must_change_password) and blocked behind a full-screen password change; external accounts then get a one-time welcome tour with a 2FA offer (users.onboarded_at). - LP portal: Unfunded (callable commitment) metric; Tax documents center aggregating K-1/tax docs across funds, grouped by year. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
0822eca887
commit
eac3262f29
@@ -2,10 +2,11 @@
|
||||
|
||||
import enum
|
||||
from datetime import date, datetime
|
||||
from datetime import date as _date # for fields literally named "date"
|
||||
from decimal import Decimal
|
||||
from typing import Optional
|
||||
|
||||
from sqlmodel import Field, SQLModel, Column, String, JSON, UniqueConstraint
|
||||
from sqlmodel import Field, SQLModel, Column, Date, String, JSON, UniqueConstraint
|
||||
|
||||
|
||||
# --- Enums ---
|
||||
@@ -85,6 +86,11 @@ class User(SQLModel, table=True):
|
||||
totp_enabled: bool = Field(default=False)
|
||||
# JSON list of sha256 hex digests of unused one-time recovery codes.
|
||||
totp_recovery_codes: str | None = Field(default=None)
|
||||
# True while the account is on the shared default password — the portal forces a
|
||||
# password change before anything else. Cleared by change-password / admin reset.
|
||||
must_change_password: bool = Field(default=False)
|
||||
# When the investor finished (or skipped) the first-login welcome flow. Null = show it.
|
||||
onboarded_at: datetime | None = Field(default=None)
|
||||
created_at: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
|
||||
@@ -100,9 +106,25 @@ class Entity(SQLModel, table=True):
|
||||
# For a GP/mgmt entity that is also an LP with capital accounts (e.g. Ten31 LLC), link to
|
||||
# its investor account so its Assets view can pull real per-fund balances from the eNAV.
|
||||
linked_user_id: int | None = Field(default=None, foreign_key="users.id", index=True)
|
||||
# Final close of the fund/SPV — the BTC entry mark: paid-in capital is valued at the BTC
|
||||
# price on this date for the bitcoin-denominated view. Null = no BTC view for this fund.
|
||||
close_date: date | None = Field(default=None)
|
||||
created_at: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
|
||||
class BtcPrice(SQLModel, table=True):
|
||||
"""Daily (or as-uploaded) BTC/USD closing prices from the admin's CSV.
|
||||
|
||||
Statements are valued at the newest price on or before their as-of date, so the CSV
|
||||
doesn't need every calendar day — quarter-end rows are enough."""
|
||||
|
||||
__tablename__ = "btc_prices"
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
date: _date = Field(sa_column=Column(Date, unique=True, nullable=False))
|
||||
price_cents: int
|
||||
|
||||
|
||||
class Holding(SQLModel, table=True):
|
||||
__tablename__ = "holdings"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user