docs: surface SP14 (Payer-Rejected UI + acknowledge) + SP15 (key rotation) #3
@@ -144,6 +144,7 @@ app.add_middleware(
|
||||
from cyclone.api_routers import ( # noqa: E402
|
||||
acks,
|
||||
activity,
|
||||
batches,
|
||||
clearhouse,
|
||||
config,
|
||||
health,
|
||||
@@ -158,6 +159,7 @@ app.include_router(providers.router)
|
||||
app.include_router(clearhouse.router)
|
||||
app.include_router(config.router)
|
||||
app.include_router(activity.router)
|
||||
app.include_router(batches.router)
|
||||
|
||||
# Backwards-compat re-exports: test_api_stream_live.py imports these
|
||||
# names directly from ``cyclone.api`` to invoke the endpoint coroutines
|
||||
@@ -1159,63 +1161,7 @@ def inbox_export_csv(lane: str):
|
||||
)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# GET endpoints (read views over the in-memory store)
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
|
||||
def _batch_summary_claim_count(rec: BatchRecord) -> int:
|
||||
"""Return the number of claims on a batch, handling both 837P and 835."""
|
||||
if rec.kind == "837p":
|
||||
return len(rec.result.claims) # type: ignore[attr-defined]
|
||||
if rec.kind == "835":
|
||||
return len(rec.result.claims) # type: ignore[attr-defined]
|
||||
return 0
|
||||
|
||||
|
||||
@app.get("/api/batches")
|
||||
def list_batches(
|
||||
request: Request,
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
) -> Any:
|
||||
"""Summary of all parsed batches, newest first."""
|
||||
records = store.list(limit=limit)
|
||||
items = [
|
||||
{
|
||||
"id": r.id,
|
||||
"kind": r.kind,
|
||||
"inputFilename": r.input_filename,
|
||||
"parsedAt": r.parsed_at.isoformat().replace("+00:00", "Z"),
|
||||
"claimCount": _batch_summary_claim_count(r),
|
||||
}
|
||||
for r in records
|
||||
]
|
||||
all_records = store.all()
|
||||
total = len(all_records)
|
||||
returned = len(items)
|
||||
has_more = total > returned
|
||||
if _wants_ndjson(request):
|
||||
return StreamingResponse(
|
||||
_ndjson_stream_list(items, total, returned, has_more),
|
||||
media_type="application/x-ndjson",
|
||||
)
|
||||
return {
|
||||
"items": items,
|
||||
"total": total,
|
||||
"returned": returned,
|
||||
"has_more": has_more,
|
||||
}
|
||||
|
||||
|
||||
@app.get("/api/batches/{batch_id}")
|
||||
def get_batch(batch_id: str) -> Any:
|
||||
rec = store.get(batch_id)
|
||||
if rec is None:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail={"error": "Not found", "detail": f"Batch {batch_id} not found"},
|
||||
)
|
||||
return json.loads(rec.result.model_dump_json())
|
||||
# --- /api/batches lives in cyclone.api_routers.batches ---
|
||||
|
||||
|
||||
@app.get("/api/claims")
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
"""``/api/batches`` — list & detail endpoints for parsed batches.
|
||||
|
||||
Each ``store.add(...)`` call (837P, 835, 999, TA1, 277CA) produces a
|
||||
``BatchRecord`` kept in memory by :class:`CycloneStore`. The list
|
||||
endpoint returns a lightweight summary (id, kind, filename, parsedAt,
|
||||
claim count) for the recent batches; the detail endpoint returns the
|
||||
full parsed payload for one batch.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Query, Request
|
||||
from fastapi.responses import StreamingResponse
|
||||
|
||||
from cyclone.api_helpers import ndjson_stream_list, wants_ndjson
|
||||
from cyclone.store import BatchRecord, store
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def _batch_summary_claim_count(rec: BatchRecord) -> int:
|
||||
"""Return the number of claims on a batch, handling both 837P and 835."""
|
||||
if rec.kind == "837p":
|
||||
return len(rec.result.claims) # type: ignore[attr-defined]
|
||||
if rec.kind == "835":
|
||||
return len(rec.result.claims) # type: ignore[attr-defined]
|
||||
return 0
|
||||
|
||||
|
||||
@router.get("/api/batches")
|
||||
def list_batches_endpoint(
|
||||
request: Request,
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
) -> Any:
|
||||
"""Summary of all parsed batches, newest first."""
|
||||
records = store.list(limit=limit)
|
||||
items = [
|
||||
{
|
||||
"id": r.id,
|
||||
"kind": r.kind,
|
||||
"inputFilename": r.input_filename,
|
||||
"parsedAt": r.parsed_at.isoformat().replace("+00:00", "Z"),
|
||||
"claimCount": _batch_summary_claim_count(r),
|
||||
}
|
||||
for r in records
|
||||
]
|
||||
all_records = store.all()
|
||||
total = len(all_records)
|
||||
returned = len(items)
|
||||
has_more = total > returned
|
||||
if wants_ndjson(request):
|
||||
return StreamingResponse(
|
||||
ndjson_stream_list(items, total, returned, has_more),
|
||||
media_type="application/x-ndjson",
|
||||
)
|
||||
return {
|
||||
"items": items,
|
||||
"total": total,
|
||||
"returned": returned,
|
||||
"has_more": has_more,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/api/batches/{batch_id}")
|
||||
def get_batch_endpoint(batch_id: str) -> Any:
|
||||
"""Return the full parsed payload for one batch."""
|
||||
rec = store.get(batch_id)
|
||||
if rec is None:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail={"error": "Not found", "detail": f"Batch {batch_id} not found"},
|
||||
)
|
||||
return json.loads(rec.result.model_dump_json())
|
||||
Reference in New Issue
Block a user