refactor(store): code quality fixes per review

- iter_claims/iter_remittances now return list[dict] (snapshot under
  the lock, return outside) so slow consumers no longer hold the
  write lock during iteration
- iter_claims gains payer (case-insensitive substring) and
  date_from/date_to filters via the new _date_in_bounds helper
- iter_remittances wires date_from/date_to and payer
- BatchRecord split into BatchRecord837 / BatchRecord835 with
  __new__ dispatch so isinstance narrows result correctly,
  eliminating the four 'type: ignore[assignment]' band-aids
- BatchRecord now rejects naive parsed_at via model_validator
- to_ui_remittance's adjustmentAmount=0.0 is documented as a
  TODO for sub-project 2 reconciliation

151 passed, 1 skipped (no regressions; +6 tests for new filters)
This commit is contained in:
Tyler
2026-06-19 19:22:44 -06:00
parent d0411b8186
commit ca645db518
2 changed files with 238 additions and 46 deletions
+110
View File
@@ -485,3 +485,113 @@ def test_iter_remittances_fills_payer_name_from_batch():
out = list(s.iter_remittances())
assert len(out) == 1
assert out[0]["payerName"] == "CO_TXIX"
# ---------------------------------------------------------------------------
# Review fixes: payer / date filters, tz-aware validator
# ---------------------------------------------------------------------------
def _make_claim_with_payer(claim_id: str, payer_name: str) -> ClaimOutput:
"""ClaimOutput variant that lets us pick a payer name per row."""
c = _make_claim(claim_id)
c.payer = Payer(name=payer_name, id="P1")
return c
def test_iter_claims_filters_by_payer_substring_case_insensitive():
"""iter_claims(payer=...) is a case-insensitive substring match on payerName."""
s = InMemoryStore()
result = _make_result()
result.claims = [
_make_claim_with_payer("A", "Aetna Health"),
_make_claim_with_payer("B", "Blue Cross"),
_make_claim_with_payer("C", "aetna better health"),
]
s.add(BatchRecord(
id="b1", kind="837p", input_filename="a.txt",
parsed_at=_PARSED_AT, result=result,
))
out = s.iter_claims(payer="Aetna")
ids = sorted(c["id"] for c in out)
assert ids == ["A", "C"], f"expected Aetna matches, got {ids}"
def test_iter_claims_filters_by_date_from_includes_in_range_only():
"""date_from excludes items whose submissionDate is before the bound."""
s = InMemoryStore()
old = datetime(2026, 6, 10, 12, 0, 0, tzinfo=timezone.utc)
new = datetime(2026, 6, 25, 12, 0, 0, tzinfo=timezone.utc)
old_result = _make_result()
old_result.claims = [_make_claim("OLD")]
new_result = _make_result()
new_result.claims = [_make_claim("NEW")]
s.add(BatchRecord(
id="b-old", kind="837p", input_filename="a.txt",
parsed_at=old, result=old_result,
))
s.add(BatchRecord(
id="b-new", kind="837p", input_filename="b.txt",
parsed_at=new, result=new_result,
))
out = s.iter_claims(date_from="2026-06-20")
assert [c["id"] for c in out] == ["NEW"]
def test_iter_claims_filters_by_date_to_includes_in_range_only():
"""date_to excludes items whose submissionDate is after the bound."""
s = InMemoryStore()
old = datetime(2026, 6, 10, 12, 0, 0, tzinfo=timezone.utc)
new = datetime(2026, 6, 25, 12, 0, 0, tzinfo=timezone.utc)
old_result = _make_result()
old_result.claims = [_make_claim("OLD")]
new_result = _make_result()
new_result.claims = [_make_claim("NEW")]
s.add(BatchRecord(
id="b-old", kind="837p", input_filename="a.txt",
parsed_at=old, result=old_result,
))
s.add(BatchRecord(
id="b-new", kind="837p", input_filename="b.txt",
parsed_at=new, result=new_result,
))
out = s.iter_claims(date_to="2026-06-20")
assert [c["id"] for c in out] == ["OLD"]
def test_iter_remittances_filters_by_date_from_and_date_to():
"""Remit receivedDate respects both date_from and date_to bounds."""
s = InMemoryStore()
old = datetime(2026, 6, 10, 12, 0, 0, tzinfo=timezone.utc)
mid = datetime(2026, 6, 20, 12, 0, 0, tzinfo=timezone.utc)
new = datetime(2026, 6, 30, 12, 0, 0, tzinfo=timezone.utc)
for ts, tag in [(old, "OLD"), (mid, "MID"), (new, "NEW")]:
s.add(BatchRecord(
id=f"835-{tag}", kind="835", input_filename="a.txt",
parsed_at=ts, result=_make_835_result(claims=[_make_remit()]),
))
out = s.iter_remittances(date_from="2026-06-15", date_to="2026-06-25")
assert [r["batchId"] for r in out] == ["835-MID"]
def test_iter_claims_unbounded_date_filter_includes_all():
"""With no date bounds, the filter is a no-op (all items returned)."""
s = InMemoryStore()
result = _make_result()
result.claims = [_make_claim("A"), _make_claim("B")]
s.add(BatchRecord(
id="b1", kind="837p", input_filename="a.txt",
parsed_at=_PARSED_AT, result=result,
))
out = s.iter_claims()
assert len(out) == 2
def test_batch_record_rejects_naive_parsed_at():
"""tz-aware validator: a naive datetime should raise ValueError."""
import pytest
with pytest.raises(ValueError, match="tz-aware"):
BatchRecord(
id="x", kind="837p", input_filename="a.txt",
parsed_at=datetime(2025, 1, 1), result=_make_result(),
)