feat: History tab on Upload page with one-click Re-export ZIP
Add a second tab to the Upload page that surfaces the persisted batch
archive and lets the user re-download any 837P batch as a ZIP without
re-parsing the original file.
- Backend: /api/batches now carries per-row claimIds (837P only).
835 batches return an empty list, which the UI uses as the signal
to hide the Re-export button on those rows. Avoids an extra
round-trip to /api/batches/{id} per row.
- Frontend: BatchSummary.claimIds added to the list-endpoint type.
- Upload page: page body wrapped in Tabs.Root with a History trigger
that mirrors ?tab= in the URL for deep-link round-trip. The
History tab renders UploadHistory → HistoryTable → HistoryRow with
a one-click Re-export ZIP button per 837P row. The button calls
POST /api/batches/{id}/export-837 with the row's claim ids and
downloads the ZIP via downloadBlob. Falls back to the in-memory
parsedBatches store when the backend returns no rows so the tab
stays useful in sample-data mode.
- Backend tests: claimIds present on 837P rows, empty on 835 rows.
- Frontend tests: 13 tests covering tab switching, URL deep-link,
loading/error/empty states, the 837P-vs-835 button visibility
split, the Re-export happy path, and the failure toast.
This commit is contained in:
@@ -65,6 +65,42 @@ def test_batches_returns_summary_after_parse(seeded_store):
|
||||
assert body["items"][0]["inputFilename"] == "x.txt"
|
||||
|
||||
|
||||
def test_batches_includes_claim_ids_for_837p(seeded_store):
|
||||
"""The Upload page's History tab renders a Re-export ZIP button per
|
||||
row that fires ``POST /api/batches/{id}/export-837`` with the row's
|
||||
claim ids. Carry those ids in the list response so the UI doesn't
|
||||
need an extra round-trip per row to fetch them."""
|
||||
batches = seeded_store.get("/api/batches", headers=JSON).json()["items"]
|
||||
assert len(batches) == 1
|
||||
item = batches[0]
|
||||
assert item["kind"] == "837p"
|
||||
# claimIds is a non-empty list of the same claim ids that live
|
||||
# inside the parsed result — see `seeded_store` in conftest.py.
|
||||
assert isinstance(item["claimIds"], list)
|
||||
assert len(item["claimIds"]) == 2
|
||||
full = seeded_store.get(f"/api/batches/{item['id']}").json()
|
||||
assert sorted(item["claimIds"]) == sorted(c["claim_id"] for c in full["claims"])
|
||||
|
||||
|
||||
def test_batches_claim_ids_empty_for_835(client: TestClient, tmp_path):
|
||||
"""835 has no re-export endpoint — the field is always ``[]`` so the
|
||||
History tab can use it as the signal to hide the Re-export button."""
|
||||
src = Path(__file__).parent / "fixtures" / "minimal_835.txt"
|
||||
files = {"file": ("minimal_835.txt", src.read_bytes(), "text/plain")}
|
||||
r = client.post(
|
||||
"/api/parse-835",
|
||||
params={"payer": "co_medicaid_835"},
|
||||
files=files,
|
||||
headers=JSON,
|
||||
)
|
||||
assert r.status_code == 200, r.text
|
||||
body = client.get("/api/batches", headers=JSON).json()
|
||||
assert body["total"] == 1
|
||||
item = body["items"][0]
|
||||
assert item["kind"] == "835"
|
||||
assert item["claimIds"] == []
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# /api/batches/{id}
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
Reference in New Issue
Block a user