feat(sp8): GET /api/claims/{id}/serialize-837 endpoint

Returns the persisted ClaimOutput as a regenerated X12 837P file via
the new outbound serializer (Approach A — full rebuild from canonical
fields). 404 on missing claim, 422 if the stored raw_json cannot be
validated as a ClaimOutput. text/x12 content-type, attachment
disposition with the claim id as the filename.

3 tests:
- endpoint returns text/x12 attachment starting with ISA*
- 404 for missing claim id
- regenerated text round-trips back through parse()
This commit is contained in:
Tyler
2026-06-20 20:34:44 -06:00
parent 561018c690
commit 3f4e6849c6
2 changed files with 108 additions and 1 deletions
+54
View File
@@ -0,0 +1,54 @@
"""Tests for the GET /api/claims/{id}/serialize-837 endpoint (SP8)."""
import io
from pathlib import Path
from fastapi.testclient import TestClient
from cyclone.api import app
def _seed_claim(client: TestClient) -> str:
fixture = Path("tests/fixtures/co_medicaid_837p.txt").read_text()
r = client.post(
"/api/parse-837",
files={"file": ("claim.txt", io.BytesIO(fixture.encode()), "text/plain")},
headers={"Accept": "application/json"},
)
assert r.status_code == 200, r.text
claim_id = r.json()["claims"][0]["claim_id"]
return claim_id
def test_endpoint_returns_x12_attachment():
with TestClient(app) as client:
claim_id = _seed_claim(client)
r = client.get(f"/api/claims/{claim_id}/serialize-837")
assert r.status_code == 200
assert r.headers["content-type"].startswith("text/x12")
cd = r.headers["content-disposition"]
assert "attachment" in cd
assert f"claim-{claim_id}.x12" in cd
assert r.text.startswith("ISA*")
def test_endpoint_404_for_missing_claim():
with TestClient(app) as client:
r = client.get("/api/claims/CLM-DOES-NOT-EXIST/serialize-837")
assert r.status_code == 404
body = r.json()
assert body["error"] == "Not found"
assert "CLM-DOES-NOT-EXIST" in body["detail"]
def test_endpoint_regenerated_text_round_trips_through_parser():
"""The endpoint's body should be a parseable 837 — round-trip test."""
from cyclone.parsers.parse_837 import parse
from cyclone.parsers.payer import PayerConfig
with TestClient(app) as client:
claim_id = _seed_claim(client)
r = client.get(f"/api/claims/{claim_id}/serialize-837")
assert r.status_code == 200
result = parse(r.text, PayerConfig(name="CO_MEDICAID"))
assert result.claims, "endpoint body didn't parse back to any claims"
assert result.claims[0].claim.claim_id == claim_id