Issues 19+20: entity-aware schedule import and rollup endpoint
Issue 19: - entity_id now optional on POST /api/import/schedule - Resolution: explicit entity_id > name match from row 1 > auto-create - New params: create_entity_type (default fund), create_vintage_year - Dry-run reports resolution (will_create/matched/existing) - Frontend: radio toggle between 'Create from file' and 'Use existing' Issue 20: - GET /api/entities/rollup: invested_cents and last_signed_value_cents per entity in one pass (SQL aggregates, no waterfall) - EntitiesList uses rollup instead of N+1 API calls
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { api, type Entity, type EntityType } from "../api";
|
||||
import { api, type EntityType } from "../api";
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
import { formatMoney, formatGainLoss } from "../format";
|
||||
|
||||
interface EntityRow extends Entity {
|
||||
interface EntityRow {
|
||||
id: number;
|
||||
name: string;
|
||||
type: string;
|
||||
vintage_year: number | null;
|
||||
fund_size_cents: number | null;
|
||||
status: string;
|
||||
investedCents: number;
|
||||
lastValueCents: number;
|
||||
}
|
||||
@@ -33,32 +39,19 @@ export default function EntitiesList() {
|
||||
async function loadData() {
|
||||
setLoading(true);
|
||||
try {
|
||||
const ents = await api.listEntities();
|
||||
const enriched: EntityRow[] = [];
|
||||
|
||||
for (const ent of ents) {
|
||||
const holdings = await api.listHoldings(ent.id);
|
||||
let investedCents = 0;
|
||||
let lastValueCents = 0;
|
||||
|
||||
for (const h of holdings) {
|
||||
const positions = await api.listPositions(h.id);
|
||||
for (const p of positions) {
|
||||
investedCents += p.cost_cents;
|
||||
}
|
||||
}
|
||||
|
||||
const rounds = await api.listRounds(ent.id);
|
||||
const approved = rounds.filter((r) => r.status === "approved");
|
||||
if (approved.length > 0) {
|
||||
const latest = approved[0];
|
||||
lastValueCents = latest.valuations.reduce((sum, v) => sum + v.value_cents, 0);
|
||||
}
|
||||
|
||||
enriched.push({ ...ent, investedCents, lastValueCents });
|
||||
}
|
||||
|
||||
setEntities(enriched);
|
||||
const rollup = await api.listEntityRollup();
|
||||
setEntities(
|
||||
rollup.map((r) => ({
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
type: r.type,
|
||||
vintage_year: r.vintage_year,
|
||||
fund_size_cents: r.fund_size_cents,
|
||||
status: r.status,
|
||||
investedCents: r.invested_cents,
|
||||
lastValueCents: r.last_signed_value_cents,
|
||||
})),
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user