fix(sp41): tighten pipeline_a write_files contract + cleanup imports

This commit is contained in:
Nora
2026-07-07 20:57:18 -06:00
parent e946a4f7aa
commit a3831213cc
2 changed files with 11 additions and 8 deletions
+11 -6
View File
@@ -19,6 +19,8 @@ from cyclone.rebill.reconcile import ReconcileOutcome, OutcomeCategory
@dataclass(frozen=True) @dataclass(frozen=True)
class RebillClaim: class RebillClaim:
"""Pre-emission 837P shape for Pipeline A. The serializer adapter (Task 12) converts this to a ClaimOutput for serialize_837."""
claim_id: str # reuses original claim_submit_id claim_id: str # reuses original claim_submit_id
member_id: str member_id: str
procedure: str procedure: str
@@ -35,9 +37,10 @@ def build_pipeline_a_claims(
carc_decisions: list[CarcDecision], carc_decisions: list[CarcDecision],
cas_reasons_per_visit: list[tuple[str, ...]], cas_reasons_per_visit: list[tuple[str, ...]],
) -> list[RebillClaim]: ) -> list[RebillClaim]:
"""One input list per visit; align by index.""" """Zip three parallel per-visit lists by index; drop PAID/NOT_IN_835 outcomes and EXCLUDED CARC decisions; emit one frequency-7 RebillClaim per survivor."""
out: list[RebillClaim] = [] out: list[RebillClaim] = []
for vo, carc, reasons in zip(visit_outcomes, carc_decisions, cas_reasons_per_visit): # strict=True: all three lists must be the same length; a mismatch is a contract bug, fail loud.
for vo, carc, reasons in zip(visit_outcomes, carc_decisions, cas_reasons_per_visit, strict=True):
if vo.category not in (OutcomeCategory.DENIED, OutcomeCategory.PARTIAL): if vo.category not in (OutcomeCategory.DENIED, OutcomeCategory.PARTIAL):
continue continue
if carc == CarcDecision.EXCLUDED: if carc == CarcDecision.EXCLUDED:
@@ -50,7 +53,7 @@ def build_pipeline_a_claims(
charge=vo.visit.billed, charge=vo.visit.billed,
frequency_code="7", frequency_code="7",
needs_review=(carc == CarcDecision.REVIEW), needs_review=(carc == CarcDecision.REVIEW),
original_carc_reasons=tuple(reasons), original_carc_reasons=reasons,
)) ))
return out return out
@@ -58,14 +61,16 @@ def build_pipeline_a_claims(
def write_pipeline_a_files( def write_pipeline_a_files(
claims: list[RebillClaim], claims: list[RebillClaim],
out_dir: Path, out_dir: Path,
serialize_837_fn, # injected: cyclone.parsers.serialize_837.serialize_837 serialize_837_fn, # injected: callable[[RebillClaim], str] (orchestrator-supplied adapter)
tpid: str, tpid: str,
) -> list[Path]: ) -> list[Path]:
"""Write one 837P per claim, using HCPF-spec filenames via build_outbound_filename. """Write one 837P per claim, using HCPF-spec filenames via build_outbound_filename.
`serialize_837_fn(claim)` returns the X12 byte string. The filename is `serialize_837_fn(claim)` returns the X12 string. The 837P envelope is
pure ASCII so we write it as text. The filename is
`cyclone.edi.filenames.build_outbound_filename(tpid, '837P')`. `cyclone.edi.filenames.build_outbound_filename(tpid, '837P')`.
""" """
# Lazy: keep cyclone.rebill.pipeline_a importable without zoneinfo from filenames.
from cyclone.edi.filenames import build_outbound_filename from cyclone.edi.filenames import build_outbound_filename
out_dir.mkdir(parents=True, exist_ok=True) out_dir.mkdir(parents=True, exist_ok=True)
@@ -74,6 +79,6 @@ def write_pipeline_a_files(
body = serialize_837_fn(c) body = serialize_837_fn(c)
fname = build_outbound_filename(tpid, "837P") fname = build_outbound_filename(tpid, "837P")
path = out_dir / fname path = out_dir / fname
path.write_bytes(body) path.write_text(body, encoding="ascii")
paths.append(path) paths.append(path)
return paths return paths
-2
View File
@@ -1,9 +1,7 @@
"""Pipeline A: denied/partial visits become frequency-7 replacement claims.""" """Pipeline A: denied/partial visits become frequency-7 replacement claims."""
from datetime import date from datetime import date
from decimal import Decimal from decimal import Decimal
from pathlib import Path
from cyclone.rebill.pipeline_a import ( from cyclone.rebill.pipeline_a import (
RebillClaim,
build_pipeline_a_claims, build_pipeline_a_claims,
write_pipeline_a_files, write_pipeline_a_files,
) )