Reframe healthcare filing as standard vs expedited; e2e test + bug fixes

Copy: drop paper/electronic/fax framing across the revalidation + enrollment
marketing pages and the order-confirmation email; present two service tiers:
- Standard filing  (no CMS account; we prepare CMS-855, you sign, we submit to MAC)
- Expedited filing (CMS I&A surrogate access; same-day PECOS filing + tracking)
Internal worker todos + the _STANDARD_FILING_SLUGS identifier updated to match.

New scripts/test_healthcare_e2e.py validates the whole order line (slug
consistency x6 places, price agreement, intake field collection+enforcement,
worker dispatch, handler execution producing CMS-855 PDF+anchor, free-tool
action_urls). 45 checks.

Bugs found + fixed by the test:
- medicare-enrollment requires practice_state server-side but the wizard never
  enforced it -> orders could be paid then stall. Wizard now requires it.
- determine_form_type defaulted org NPIs to the individual 855I because
  enumeration_type is never collected -> wrong form, CMS rejection. Now does a
  live NPPES lookup (safe 855I fallback).
This commit is contained in:
justin 2026-06-05 03:58:46 -05:00
parent 5cfe9702e2
commit 695ace207c
7 changed files with 381 additions and 54 deletions

View file

@ -23,6 +23,7 @@ from __future__ import annotations
import io
import logging
import re
from pathlib import Path
LOG = logging.getLogger("cms855_pdf_filler")
@ -93,15 +94,45 @@ def _split_name(full: str) -> tuple[str, str, str]:
return parts[0], parts[1][0], " ".join(parts[2:])
def _lookup_enumeration_type(npi: str) -> str:
"""Best-effort NPPES lookup of an NPI's enumeration_type (NPI-1 / NPI-2).
Returns "" if the NPI is missing, malformed, or the lookup fails callers
fall back to the individual form (855I), the safe default.
"""
npi = (npi or "").strip()
if not re.fullmatch(r"\d{10}", npi):
return ""
try:
import json as _json
from urllib.request import urlopen
url = f"https://npiregistry.cms.hhs.gov/api/?version=2.1&number={npi}"
with urlopen(url, timeout=8) as resp: # nosec - public, read-only
data = _json.loads(resp.read().decode("utf-8"))
results = data.get("results") or []
if results:
return (results[0].get("enumeration_type") or "").upper()
except Exception:
LOG.warning("NPPES enumeration_type lookup failed for %s", npi)
return ""
def determine_form_type(slug: str, intake: dict) -> str:
"""Pick which 855 form applies for the order."""
"""Pick which 855 form applies for the order.
Org NPIs (Type 2 / NPI-2) revalidate/enroll on 855B; individuals on 855I.
The wizard does not collect enumeration_type, so when it is absent we look
it up live from NPPES rather than silently defaulting an organization to the
wrong (individual) form, which CMS would reject.
"""
if slug not in ("npi-revalidation", "medicare-enrollment"):
return "855i"
enum_type = (intake.get("enumeration_type") or "").upper()
if slug == "npi-revalidation":
# Org NPIs (Type 2) revalidate on 855B; individuals on 855I.
return "855b" if enum_type in ("NPI-2", "2", "ORGANIZATION") else "855i"
if slug == "medicare-enrollment":
return "855b" if enum_type in ("NPI-2", "2", "ORGANIZATION") else "855i"
return "855i"
if not enum_type:
enum_type = _lookup_enumeration_type(intake.get("npi", ""))
return "855b" if enum_type in ("NPI-2", "2", "ORGANIZATION") else "855i"
def fill_cms855(form_type: str, intake: dict, order_number: str = "") -> tuple[bytes, list[dict], list[str]]: