feat(sp32): wire rendering_provider_npi and service_provider_npi through ORM builders
This commit is contained in:
@@ -53,6 +53,10 @@ def _claim_837_row(claim: ClaimOutput, batch_id: str) -> Claim:
|
||||
service_date_to=d_to,
|
||||
charge_amount=Decimal(claim.claim.total_charge or 0),
|
||||
provider_npi=claim.billing_provider.npi,
|
||||
# SP32: wire NM1*82 (Loop 2420A) rendering provider NPI from
|
||||
# ClaimOutput (T3 parser extraction) into the typed ORM column
|
||||
# (T1 migration 0019). Falls back to None if absent.
|
||||
rendering_provider_npi=claim.rendering_provider_npi,
|
||||
payer_id=claim.payer.id,
|
||||
state=ClaimState.SUBMITTED,
|
||||
raw_json=json.loads(claim.model_dump_json()),
|
||||
@@ -89,6 +93,10 @@ def _remittance_835_row(cp: ClaimPayment, batch_id: str) -> Remittance:
|
||||
total_paid=Decimal(cp.total_paid or 0),
|
||||
patient_responsibility=cp.patient_responsibility,
|
||||
adjustment_amount=adjustment,
|
||||
# SP32: wire NM1*1P (Loop 2100) service provider NPI from
|
||||
# ClaimPayment (T2 parser extraction) into the typed ORM column
|
||||
# (T1 migration 0019). Falls back to None if absent.
|
||||
rendering_provider_npi=cp.service_provider_npi,
|
||||
received_at=received_at,
|
||||
service_date=service_date,
|
||||
is_reversal=cp.status_code in ("21", "22"),
|
||||
|
||||
@@ -792,3 +792,57 @@ def test_reconcile_run_no_match_leaves_remit_unlinked(db_session, make_claim, ma
|
||||
assert claim.state == ClaimState.SUBMITTED # unchanged
|
||||
db_session.refresh(remit)
|
||||
assert remit.claim_id is None # unchanged
|
||||
|
||||
|
||||
# --- SP32 Task 4: ORM builders wire rendering_provider_npi -----------------
|
||||
|
||||
|
||||
def test_claim_837_row_includes_rendering_provider_npi():
|
||||
"""SP32: Claim.rendering_provider_npi is populated from ClaimOutput in ORM builder."""
|
||||
from pathlib import Path
|
||||
from cyclone.parsers.parse_837 import parse
|
||||
from cyclone.parsers.payer import PayerConfig
|
||||
from cyclone.store.orm_builders import _claim_837_row
|
||||
|
||||
text = Path("tests/fixtures/co_medicaid_837p_with_renderer.txt").read_text()
|
||||
parsed = parse(text, PayerConfig.co_medicaid())
|
||||
# Find the claim whose rendering NPI was extracted.
|
||||
targets = [c for c in parsed.claims if c.rendering_provider_npi == "1234567893"]
|
||||
assert len(targets) == 1
|
||||
row = _claim_837_row(targets[0], batch_id="test-batch")
|
||||
assert row.rendering_provider_npi == "1234567893"
|
||||
|
||||
|
||||
def test_remittance_835_row_includes_service_provider_npi():
|
||||
"""SP32: Remittance.rendering_provider_npi is populated from ClaimPayment in ORM builder."""
|
||||
from cyclone.parsers.parse_835 import parse as parse_835
|
||||
from cyclone.store.orm_builders import _remittance_835_row
|
||||
|
||||
text = (
|
||||
"ISA*00* *00* *ZZ*RECEIVERID *ZZ*SENDERID *250101*1200*^*00501*000000001*0*P*:~"
|
||||
"GS*HP*RECEIVER*SENDER*20250101*1200*1*X*005010X221A1~"
|
||||
"ST*835*0001~"
|
||||
"BPR*I*85.40*C*NON*****01*021000021*DA*123456*1511111**01*031302955*DA*9876543~"
|
||||
"TRN*1*1511111*1511111~"
|
||||
"DTM*405*20250101~"
|
||||
"N1*PR*COLORADO MEDICAID*XV*CO MEDICAID~"
|
||||
"N3*PO BOX 1100*~"
|
||||
"N4*DENVER*CO*80203~"
|
||||
"REF*2U*12345~"
|
||||
"PER*BL*SUPPORT*TE*8005551212~"
|
||||
"N1*PE*ACME CLINIC*XX*1111111111~"
|
||||
"LX*1~"
|
||||
"CLP*CLM001*1*85.40*85.40*0.00*MC*CLM001*11*1~"
|
||||
"CAS*PR*1*0.00~"
|
||||
"NM1*1P*2*RENDERING PROVIDER*****XX*2222222222~"
|
||||
"SVC*HC:99213*85.40*85.40**1~"
|
||||
"DTM*472*20250101~"
|
||||
"SE*18*0001~"
|
||||
"GE*1*1~"
|
||||
"IEA*1*000000001~"
|
||||
)
|
||||
parsed = parse_835(text, payer_config=None) # type: ignore[arg-type]
|
||||
assert len(parsed.claims) == 1
|
||||
assert parsed.claims[0].service_provider_npi == "2222222222"
|
||||
row = _remittance_835_row(parsed.claims[0], batch_id="test-batch")
|
||||
assert row.rendering_provider_npi == "2222222222"
|
||||
|
||||
Reference in New Issue
Block a user