0.2.36: Investor View carries exit status + grey out fully-exited fund cards

The admin read-only Investor View built capital-account responses
without exited_on, so an exited position showed the active card with
$0s (the LP's own portal was correct). Extracted exit_dates() into
capital_account_router and stamp it in investor_view too; regression
test added. A fund card where every position is exited now renders
greyed (bg + title) so it reads as closed at a glance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jonathan Kirkwood
2026-07-03 09:35:03 -05:00
co-authored by Claude Opus 4.8
parent 2c87ab499a
commit 1deb6586b0
9 changed files with 65 additions and 18 deletions
@@ -21,6 +21,22 @@ def _dollars_to_cents(dollars: float) -> int:
return round(dollars * 100)
def exit_dates(session: Session, rows) -> dict:
"""(investor_user_id, entity_id) -> exited_on for every exited pair in these statements,
so a sold/transferred stake renders as "Exited" instead of a phantom -100% loss."""
if not rows:
return {}
return {
(a.user_id, a.entity_id): a.exited_on
for a in session.exec(
select(EntityAccess).where(
col(EntityAccess.user_id).in_({r.investor_user_id for r in rows}),
col(EntityAccess.exited_on).is_not(None),
)
).all()
}
@router.get("")
def list_statements(
entity_id: int | None = None,
@@ -57,17 +73,7 @@ def list_statements(
col(User.id).in_({r.investor_user_id for r in rows})
)
).all()) if rows else {}
# And each (investor, entity)'s exit date, so a sold/transferred stake renders as
# "Exited" instead of a phantom -100% loss.
exits = {
(a.user_id, a.entity_id): a.exited_on
for a in session.exec(
select(EntityAccess).where(
col(EntityAccess.user_id).in_({r.investor_user_id for r in rows}),
col(EntityAccess.exited_on).is_not(None),
)
).all()
} if rows else {}
exits = exit_dates(session, rows)
out: list[CapitalAccountResponse] = []
for r in rows:
data = CapitalAccountResponse.model_validate(r, from_attributes=True)