fix: handle duplicate security names and non-JSON error responses
Build Service / build (push) Canceled after 0s

- Disambiguate duplicate (company, security) pairs in Carta exports:
  e.g. two 'Warrants' under BIP21 become 'Warrants' and 'Warrants (2)'
- Tested against Fund II: 33 holdings, 41 positions (3 companies with
  duplicate tranches), zero errors
- Frontend: graceful handling of 500 responses (shows status code
  instead of JSON parse crash)
This commit is contained in:
Johnny 5
2026-06-08 03:20:37 +00:00
parent 30d2284feb
commit 758fac3ab5
2 changed files with 20 additions and 2 deletions
+12 -1
View File
@@ -269,6 +269,8 @@ def _parse_schedule_xlsx(file_bytes: bytes) -> tuple[str | None, list[dict], lis
# Parse data rows (starting at row 6) # Parse data rows (starting at row 6)
current_company: str | None = None current_company: str | None = None
seen_companies: set[str] = set() seen_companies: set[str] = set()
# Track (company, security) occurrences to disambiguate duplicate tranches
security_counts: dict[tuple[str, str], int] = {}
for row_idx in range(6, ws.max_row + 1): for row_idx in range(6, ws.max_row + 1):
col_a = ws.cell(row=row_idx, column=1).value # Investment (company) col_a = ws.cell(row=row_idx, column=1).value # Investment (company)
@@ -301,9 +303,18 @@ def _parse_schedule_xlsx(file_bytes: bytes) -> tuple[str | None, list[dict], lis
# Position row: col B has security name # Position row: col B has security name
if col_b: if col_b:
security_name = str(col_b).strip() raw_security_name = str(col_b).strip()
company = current_company or "(unknown)" company = current_company or "(unknown)"
# Disambiguate duplicate (company, security) pairs
# e.g. two "Warrants" under BIP21 become "Warrants" and "Warrants (2)"
pair_key = (company, raw_security_name)
security_counts[pair_key] = security_counts.get(pair_key, 0) + 1
if security_counts[pair_key] == 1:
security_name = raw_security_name
else:
security_name = f"{raw_security_name} ({security_counts[pair_key]})"
# Parse investment date # Parse investment date
inv_date: date | None = None inv_date: date | None = None
if isinstance(col_c, datetime): if isinstance(col_c, datetime):
+8 -1
View File
@@ -66,7 +66,14 @@ export default function Import() {
} }
const res = await fetch(url, { method: "POST", body: form }); const res = await fetch(url, { method: "POST", body: form });
const data = await res.json(); let data: any;
try {
data = await res.json();
} catch {
setError(`Server error (${res.status}). Check file format and try again.`);
setLoading(false);
return;
}
if (!res.ok) { if (!res.ok) {
setError(data.detail || "Import failed"); setError(data.detail || "Import failed");
} else { } else {