feat(sp31): add _score_fallback_candidates DB helper with ±30-day candidate pool
This commit is contained in:
@@ -487,3 +487,125 @@ def test_content_keys_empty_npi_does_not_count():
|
||||
assert _content_keys_match(r, c) is True # PCN + charge still match
|
||||
c2 = _make_claim_for_keys("c2", "XYZ", Decimal("100.00"), "1111111111")
|
||||
assert _content_keys_match(r, c2) is False # only charge, no PCN
|
||||
|
||||
|
||||
# --- SP31: content-keys fallback matcher (DB helper) ------------------------
|
||||
|
||||
|
||||
def test_score_fallback_unique_match_returns_claim_id(db_session, make_claim, make_remit):
|
||||
"""One claim in pool matches 2-of-3 → returns that claim."""
|
||||
from decimal import Decimal
|
||||
from datetime import date, timedelta
|
||||
from cyclone.reconcile import _score_fallback_candidates
|
||||
c1 = make_claim(patient_control_number="ABC", total_charge=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date_from=date(2026, 6, 1))
|
||||
c2 = make_claim(patient_control_number="XYZ", total_charge=Decimal("999.99"),
|
||||
rendering_provider_npi="2222222222",
|
||||
service_date_from=date(2026, 6, 1))
|
||||
r = make_remit(payer_claim_control_number="ABC",
|
||||
total_charge_amount=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date=date(2026, 6, 5)) # ±30-day window
|
||||
assert _score_fallback_candidates(db_session, r) == c1.id
|
||||
|
||||
|
||||
def test_score_fallback_zero_matches_returns_none(db_session, make_claim, make_remit):
|
||||
"""No claim in pool matches 2-of-3 → returns None."""
|
||||
from decimal import Decimal
|
||||
from datetime import date
|
||||
from cyclone.reconcile import _score_fallback_candidates
|
||||
make_claim(patient_control_number="XYZ", total_charge=Decimal("999.99"),
|
||||
rendering_provider_npi="2222222222",
|
||||
service_date_from=date(2026, 6, 1))
|
||||
r = make_remit(payer_claim_control_number="ABC",
|
||||
total_charge_amount=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date=date(2026, 6, 5))
|
||||
assert _score_fallback_candidates(db_session, r) is None
|
||||
|
||||
|
||||
def test_score_fallback_two_matches_returns_none(db_session, make_claim, make_remit):
|
||||
"""Two claims in pool both match 2-of-3 → returns None (ambiguous)."""
|
||||
from decimal import Decimal
|
||||
from datetime import date
|
||||
from cyclone.reconcile import _score_fallback_candidates
|
||||
# Both claims have same PCN and same charge — both would match PCN+charge.
|
||||
make_claim(patient_control_number="ABC", total_charge=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date_from=date(2026, 6, 1))
|
||||
make_claim(patient_control_number="ABC", total_charge=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date_from=date(2026, 6, 2))
|
||||
r = make_remit(payer_claim_control_number="ABC",
|
||||
total_charge_amount=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date=date(2026, 6, 5))
|
||||
assert _score_fallback_candidates(db_session, r) is None
|
||||
|
||||
|
||||
def test_score_fallback_skips_already_matched(db_session, make_claim, make_remit):
|
||||
"""Claim with matched_remittance_id set → excluded from pool."""
|
||||
from decimal import Decimal
|
||||
from datetime import date
|
||||
from cyclone.reconcile import _score_fallback_candidates
|
||||
c1 = make_claim(patient_control_number="ABC", total_charge=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date_from=date(2026, 6, 1),
|
||||
matched_remittance_id="some-other-remit-id")
|
||||
r = make_remit(payer_claim_control_number="ABC",
|
||||
total_charge_amount=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date=date(2026, 6, 5))
|
||||
assert _score_fallback_candidates(db_session, r) is None # only candidate was excluded
|
||||
|
||||
|
||||
def test_score_fallback_skips_terminal_state(db_session, make_claim, make_remit):
|
||||
"""Claim in PAID/DENIED/REJECTED/REVERSED/RECONCILED → excluded from pool."""
|
||||
from decimal import Decimal
|
||||
from datetime import date
|
||||
from cyclone.db import ClaimState
|
||||
from cyclone.reconcile import _score_fallback_candidates
|
||||
make_claim(patient_control_number="ABC", total_charge=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date_from=date(2026, 6, 1),
|
||||
state=ClaimState.PAID)
|
||||
r = make_remit(payer_claim_control_number="ABC",
|
||||
total_charge_amount=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date=date(2026, 6, 5))
|
||||
assert _score_fallback_candidates(db_session, r) is None
|
||||
|
||||
|
||||
def test_score_fallback_widened_window_catches_late_remit(db_session, make_claim, make_remit):
|
||||
"""Remit 25 days after claim → still in pool (30-day window)."""
|
||||
from decimal import Decimal
|
||||
from datetime import date, timedelta
|
||||
from cyclone.reconcile import _score_fallback_candidates
|
||||
claim_date = date(2026, 6, 1)
|
||||
remit_date = claim_date + timedelta(days=25)
|
||||
c1 = make_claim(patient_control_number="ABC", total_charge=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date_from=claim_date)
|
||||
r = make_remit(payer_claim_control_number="ABC",
|
||||
total_charge_amount=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date=remit_date)
|
||||
assert _score_fallback_candidates(db_session, r) == c1.id
|
||||
|
||||
|
||||
def test_score_fallback_outside_window_excluded(db_session, make_claim, make_remit):
|
||||
"""Remit 60 days after claim → excluded (outside 30-day window)."""
|
||||
from decimal import Decimal
|
||||
from datetime import date, timedelta
|
||||
from cyclone.reconcile import _score_fallback_candidates
|
||||
claim_date = date(2026, 6, 1)
|
||||
remit_date = claim_date + timedelta(days=60)
|
||||
make_claim(patient_control_number="ABC", total_charge=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date_from=claim_date)
|
||||
r = make_remit(payer_claim_control_number="ABC",
|
||||
total_charge_amount=Decimal("100.00"),
|
||||
rendering_provider_npi="1111111111",
|
||||
service_date=remit_date)
|
||||
assert _score_fallback_candidates(db_session, r) is None
|
||||
|
||||
Reference in New Issue
Block a user