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
|
from cyclone.api_routers import ( # noqa: E402
|
||||||
acks,
|
acks,
|
||||||
activity,
|
activity,
|
||||||
|
batches,
|
||||||
clearhouse,
|
clearhouse,
|
||||||
config,
|
config,
|
||||||
health,
|
health,
|
||||||
@@ -158,6 +159,7 @@ app.include_router(providers.router)
|
|||||||
app.include_router(clearhouse.router)
|
app.include_router(clearhouse.router)
|
||||||
app.include_router(config.router)
|
app.include_router(config.router)
|
||||||
app.include_router(activity.router)
|
app.include_router(activity.router)
|
||||||
|
app.include_router(batches.router)
|
||||||
|
|
||||||
# Backwards-compat re-exports: test_api_stream_live.py imports these
|
# Backwards-compat re-exports: test_api_stream_live.py imports these
|
||||||
# names directly from ``cyclone.api`` to invoke the endpoint coroutines
|
# names directly from ``cyclone.api`` to invoke the endpoint coroutines
|
||||||
@@ -1159,63 +1161,7 @@ def inbox_export_csv(lane: str):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
# --- /api/batches lives in cyclone.api_routers.batches ---
|
||||||
# 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())
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/claims")
|
@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