feat(parsers+api+ui): expose CARC-labeled CAS adjustments (SP3 P2)

This commit is contained in:
Tyler
2026-06-20 07:44:41 -06:00
parent 76eb33e029
commit 2a853857b1
10 changed files with 927 additions and 26 deletions
+169
View File
@@ -637,3 +637,172 @@ def test_post_unmatch_removes_match(client: TestClient):
assert body["claim"]["matchedRemittanceId"] is None
# No Match rows existed before the call → 0 deleted.
assert body["deletedMatches"] == 0
# --------------------------------------------------------------------------- #
# /api/remittances/{remittance_id} (T7 / SP3 P2)
# --------------------------------------------------------------------------- #
def test_get_remittance_404_when_missing(client: TestClient) -> None:
"""A missing remittance returns 404 (not 500)."""
resp = client.get("/api/remittances/does-not-exist")
assert resp.status_code == 404
def _seed_835_remittance(
*,
pcns: list[str],
cas_rows: dict[str, list[tuple[str, str, str, str]]] | None = None,
status_code: str = "1",
total_charge: str = "100",
total_paid: str = "100",
) -> None:
"""Helper: insert one 835 batch with one ClaimPayment per PCN.
``cas_rows`` maps ``pcn -> [(group, reason, amount, qty_or_None), ...]``
so a single CAS row maps cleanly to ``CasAdjustment``.
"""
from datetime import date, datetime, timezone
from decimal import Decimal
from cyclone.parsers.models_835 import (
BatchSummary as BatchSummary835,
ClaimAdjustment as ClaimAdjustment835,
ClaimPayment,
Envelope as Envelope835,
FinancialInfo,
Payer835,
ParseResult835,
Payee835,
ReassociationTrace,
ServicePayment,
)
from cyclone.store import BatchRecord835
claims = []
for pcn in pcns:
adjustments: list[ClaimAdjustment835] = []
rows = (cas_rows or {}).get(pcn, [])
for group, reason, amount, qty in rows:
adjustments.append(ClaimAdjustment835(
group_code=group, reason_code=reason,
amount=Decimal(amount),
quantity=Decimal(qty) if qty else None,
))
sp = ServicePayment(
line_number=1,
procedure_qualifier="HC",
procedure_code="T1019",
modifiers=[],
charge=Decimal(total_charge),
payment=Decimal(total_paid),
units=Decimal("1"),
unit_type="UN",
adjustments=adjustments,
)
claims.append(ClaimPayment(
payer_claim_control_number=pcn,
status_code=status_code,
total_charge=Decimal(total_charge),
total_paid=Decimal(total_paid),
service_payments=[sp] if rows else [],
))
global_store.add(BatchRecord835(
id=f"b-835-{pcns[0]}", kind="835", input_filename="era.txt",
parsed_at=datetime(2026, 6, 19, 12, 5, tzinfo=timezone.utc),
result=ParseResult835(
envelope=Envelope835(
sender_id="S", receiver_id="R", control_number="0001",
transaction_date=date(2026, 6, 19),
),
financial_info=FinancialInfo(
handling_code="C", paid_amount=Decimal(total_paid),
credit_debit_flag="C", payment_method=None,
),
trace=ReassociationTrace(
trace_type_code="1", trace_number="0001",
originating_company_id="S",
),
payer=Payer835(name="Colorado Medicaid", id="SKCO0"),
payee=Payee835(name="TOC, Inc.", npi="1881068062"),
claims=claims,
summary=BatchSummary835(
input_file="era.txt", control_number="0001",
transaction_date=date(2026, 6, 19),
total_claims=len(claims), passed=len(claims), failed=0,
),
),
))
def test_get_remittance_with_empty_adjustments(client: TestClient) -> None:
"""A remittance with no CAS rows returns ``adjustments == []``."""
_seed_835_remittance(pcns=["PCN-EMPTY"])
resp = client.get("/api/remittances/PCN-EMPTY")
assert resp.status_code == 200, resp.text
body = resp.json()
assert body["id"] == "PCN-EMPTY"
assert body["adjustments"] == []
def test_get_remittance_with_adjustments_returns_labeled(client: TestClient) -> None:
"""A remittance with two CAS rows surfaces both with the correct labels.
Seeds CO-45 (the fee-schedule code) and PR-1 (deductible) so we
exercise both a CO group code and a PR group code, plus both a
quantified and non-quantified row.
"""
_seed_835_remittance(
pcns=["PCN-LABELED"],
cas_rows={
"PCN-LABELED": [
("CO", "45", "50.00", ""), # no quantity
("PR", "1", "10.00", "1"), # quantified
],
},
)
resp = client.get("/api/remittances/PCN-LABELED")
assert resp.status_code == 200, resp.text
body = resp.json()
assert body["id"] == "PCN-LABELED"
adjs = body["adjustments"]
assert len(adjs) == 2
by_key = {(a["group"], a["reason"]): a for a in adjs}
assert ("CO", "45") in by_key
assert ("PR", "1") in by_key
co45 = by_key[("CO", "45")]
assert co45["amount"] == 50.00
assert co45["quantity"] is None
# Label is non-empty and isn't the "Unknown" fallback (both are in the dict).
assert co45["label"] and "Unknown" not in co45["label"]
pr1 = by_key[("PR", "1")]
assert pr1["amount"] == 10.00
assert pr1["quantity"] == 1
assert pr1["label"] and "Unknown" not in pr1["label"]
# The CO and PR rows must have distinct labels (different codes → different meanings).
assert co45["label"] != pr1["label"]
def test_get_remittance_basic_fields_preserved(client: TestClient) -> None:
"""claimId, payerName, paidAmount, status all surface unchanged."""
_seed_835_remittance(
pcns=["PCN-FIELDS"],
cas_rows={"PCN-FIELDS": [("CO", "45", "12.34", "")]},
total_paid="75.50",
)
resp = client.get("/api/remittances/PCN-FIELDS")
assert resp.status_code == 200, resp.text
body = resp.json()
assert body["id"] == "PCN-FIELDS"
assert body["payerName"] == "Colorado Medicaid"
assert body["paidAmount"] == 75.50
assert body["status"] == "received"
assert body["batchId"] # populated; not pinned to a specific value
assert body["receivedDate"] # populated
assert body["parsedAt"] # populated