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:
parent
5cfe9702e2
commit
695ace207c
7 changed files with 381 additions and 54 deletions
|
|
@ -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]]:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue