diff --git a/backend/ten31portal/routers/import_router.py b/backend/ten31portal/routers/import_router.py index 38f28a4..bf23c4b 100644 --- a/backend/ten31portal/routers/import_router.py +++ b/backend/ten31portal/routers/import_router.py @@ -269,6 +269,8 @@ def _parse_schedule_xlsx(file_bytes: bytes) -> tuple[str | None, list[dict], lis # Parse data rows (starting at row 6) current_company: str | None = None 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): 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 if col_b: - security_name = str(col_b).strip() + raw_security_name = str(col_b).strip() 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 inv_date: date | None = None if isinstance(col_c, datetime): diff --git a/frontend/src/pages/Import.tsx b/frontend/src/pages/Import.tsx index 8ab5461..e354738 100644 --- a/frontend/src/pages/Import.tsx +++ b/frontend/src/pages/Import.tsx @@ -66,7 +66,14 @@ export default function Import() { } 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) { setError(data.detail || "Import failed"); } else {