Spaces:
Running
Running
| """Align UI encounter types to specialty Schedule listings by care setting. | |
| Specialty **26 (Paediatrics)** and **00 (Family Practice)** use different | |
| Consultations and Visits sections. Encounter labels map to letter-prefix | |
| families plus BM25 steering keywords for that specialty. | |
| """ | |
| from __future__ import annotations | |
| from .specialty_registry import normalize_specialty_code | |
| # Ordered (substring -> (prefixes, keywords)) rules. First match wins — more | |
| # specific Paediatrics phrases must precede generic ones. | |
| _PAEDS_RULES: list[tuple[tuple[str, ...], tuple[list[str], str]]] = [ | |
| # --- Newborn & delivery (H261 / H267 live in PAEDIATRICS (26)) --- | |
| ( | |
| ("maternal delivery", "attendance at maternal", "delivery attendance"), | |
| (["H"], "attendance at maternal delivery H267 Paediatrics"), | |
| ), | |
| ( | |
| ("newborn",), | |
| (["H"], "newborn care in hospital or home H261 Paediatrics"), | |
| ), | |
| # --- Prenatal (before hospital so "Hospital - Prenatal …" keeps A+C) --- | |
| # SoB PAEDIATRICS (26) lists A665 with the same-section alternatives below; | |
| # keep them in-scope so limited/repeat/MSA can be recommended when prenatal | |
| # elements are not met. | |
| ( | |
| ("prenatal",), | |
| ( | |
| ["A", "C"], | |
| "prenatal consultation A665 C665 Paediatrics " | |
| "limited consultation A565 repeat consultation A266 " | |
| "medical specific assessment A263 A264 A661 " | |
| "level 1 level 2 paediatric assessment A261 A262", | |
| ), | |
| ), | |
| # --- Long-term care (must precede generic 'complex') --- | |
| ( | |
| ("long-term", "long term", "continuing care", "ltc"), | |
| ( | |
| ["W"], | |
| "long-term care paediatric consultation subsequent visit " | |
| "periodic health visit", | |
| ), | |
| ), | |
| # --- Hospital in-patient (C-series Paediatrics mirrors) --- | |
| # Before developmental so "Hospital - … Neurodevelopmental" stays C. | |
| ( | |
| ("subsequent", "concurrent", "daily round"), | |
| ( | |
| ["C"], | |
| "hospital in-patient subsequent visit concurrent care " | |
| "medical specific re-assessment", | |
| ), | |
| ), | |
| ( | |
| ("hospital", "admission", "inpatient", "in-patient", "mrp"), | |
| ( | |
| ["C"], | |
| "hospital in-patient paediatric consultation medical specific " | |
| "assessment concurrent care neurodevelopmental", | |
| ), | |
| ), | |
| # --- Ambulatory consultations (before developmental; "neurodevelopmental | |
| # consultation" is an A/C/W consult listing, not K developmental care) --- | |
| ( | |
| ("well-baby", "well baby", "18 month", "18-month", "enhanced 18"), | |
| ( | |
| ["A"], | |
| "enhanced 18 month well baby visit A268 Paediatrics", | |
| ), | |
| ), | |
| ( | |
| ( | |
| "special paediatric", | |
| "extended special", | |
| "neurodevelopmental consultation", | |
| "special / extended", | |
| "consultation / limited", | |
| "specialist consultation", | |
| "consultation", | |
| ), | |
| ( | |
| ["A"], | |
| "paediatric consultation limited repeat special extended " | |
| "neurodevelopmental A260 A265 A565 A266 A662 A667 A695", | |
| ), | |
| ), | |
| ( | |
| ("medical specific", "level 2", "general assessment"), | |
| ( | |
| ["A"], | |
| "level 2 paediatric assessment medical specific assessment " | |
| "re-assessment A262 A263 A264 A661", | |
| ), | |
| ), | |
| ( | |
| ("level 1", "partial", "recheck", "minor"), | |
| ( | |
| ["A"], | |
| "level 1 paediatric assessment A261", | |
| ), | |
| ), | |
| # --- Developmental / behavioural care (K119 / K122 / K123) --- | |
| # Narrow needles so "neurodevelopmental consultation" stays on A/C/W. | |
| ( | |
| ( | |
| "developmental -", | |
| "behavioural care", | |
| "behavioral care", | |
| "developmental care", | |
| "developmental assessment incentive", | |
| "family developmental", | |
| "individual developmental", | |
| ), | |
| ( | |
| ["K", "A"], | |
| "paediatric developmental behavioural care K119 K122 K123 " | |
| "neurodevelopmental", | |
| ), | |
| ), | |
| # --- Interprofessional / case conference --- | |
| ( | |
| ( | |
| "case conference", | |
| "multi-disciplinary", | |
| "multidisciplinary", | |
| "inter-professional", | |
| "interprofessional", | |
| ), | |
| ( | |
| ["K"], | |
| "developmental behavioural care case conference " | |
| "interprofessional special services", | |
| ), | |
| ), | |
| # --- Virtual: audio/telephone before generic "virtual" --- | |
| ( | |
| ("audio", "telephone"), | |
| ( | |
| ["A"], | |
| "office paediatric assessment consultation virtual telephone", | |
| ), | |
| ), | |
| ( | |
| ("virtual", "video"), | |
| (["A"], "office paediatric assessment consultation virtual video"), | |
| ), | |
| ( | |
| ("ambulatory", "office", "outpatient"), | |
| ( | |
| ["A"], | |
| "paediatric assessment consultation well baby office ambulatory", | |
| ), | |
| ), | |
| # --- Emergency: Paediatrics (26) only lists newborn/delivery under H --- | |
| ( | |
| ("emergency",), | |
| ( | |
| ["H", "A"], | |
| "paediatric assessment consultation emergency urgent", | |
| ), | |
| ), | |
| ] | |
| # Family Practice (00) — A001/A007/A003 ladder + hospital/LTC/K017. | |
| _FP_RULES: list[tuple[tuple[str, ...], tuple[list[str], str]]] = [ | |
| ( | |
| ("periodic health", "annual health", "complete physical"), | |
| ( | |
| ["K", "A"], | |
| "periodic health visit K017 Family Practice office", | |
| ), | |
| ), | |
| ( | |
| ("long-term", "long term", "continuing care", "ltc", "nursing home"), | |
| ( | |
| ["W"], | |
| "long-term care subsequent visit periodic health W001 W002 W003 " | |
| "W004 W109 Family Practice", | |
| ), | |
| ), | |
| ( | |
| ("subsequent", "concurrent", "supportive", "daily round"), | |
| ( | |
| ["C"], | |
| "hospital in-patient subsequent visit concurrent care supportive " | |
| "care C002 C007 C008 C010 Family Practice", | |
| ), | |
| ), | |
| ( | |
| ("hospital", "admission", "inpatient", "in-patient", "mrp"), | |
| ( | |
| ["C"], | |
| "hospital in-patient general assessment consultation " | |
| "C003 C004 C005 C006 Family Practice", | |
| ), | |
| ), | |
| # Intermediate before well-baby so "Intermediate assessment / well baby care" | |
| # steers to A007; pure enhanced-18 / well-baby labels still hit the next rule. | |
| ( | |
| ("intermediate",), | |
| ( | |
| ["A"], | |
| "intermediate assessment A007 Family Practice", | |
| ), | |
| ), | |
| ( | |
| ("well-baby", "well baby", "18 month", "18-month", "enhanced 18"), | |
| ( | |
| ["A"], | |
| "well baby care A007 enhanced 18 month well baby visit A002 " | |
| "Family Practice", | |
| ), | |
| ), | |
| # Ambulatory consult → office A only (hospital C mirrors stay on Hospital rules). | |
| ( | |
| ("repeat consultation", "repeat consult"), | |
| ( | |
| ["A"], | |
| "repeat consultation A006 Family Practice office", | |
| ), | |
| ), | |
| ( | |
| ("consultation", "consult"), | |
| ( | |
| ["A"], | |
| "consultation repeat consultation A006 Family Practice office", | |
| ), | |
| ), | |
| ( | |
| ("general assessment", "complete assessment", "comprehensive"), | |
| ( | |
| ["A"], | |
| "general assessment A003 Family Practice", | |
| ), | |
| ), | |
| ( | |
| ("re-assessment", "reassessment", "general re"), | |
| ( | |
| ["A"], | |
| "general re-assessment A004 Family Practice", | |
| ), | |
| ), | |
| ( | |
| ("mini",), | |
| ( | |
| ["A"], | |
| "mini assessment A008 Family Practice", | |
| ), | |
| ), | |
| ( | |
| ("minor", "brief", "focused", "single complaint"), | |
| ( | |
| ["A"], | |
| "minor assessment A001 Family Practice", | |
| ), | |
| ), | |
| ( | |
| ("audio", "telephone", "virtual", "video"), | |
| ( | |
| ["A"], | |
| "office assessment Family Practice virtual visit A001 A007 A003", | |
| ), | |
| ), | |
| ( | |
| ("ambulatory", "office", "outpatient", "clinic"), | |
| ( | |
| ["A"], | |
| "office assessment Family Practice A001 A007 A003 A004 A008", | |
| ), | |
| ), | |
| ( | |
| ("emergency", "urgent"), | |
| ( | |
| ["A", "H"], | |
| "office assessment urgent Family Practice A001 A007", | |
| ), | |
| ), | |
| ] | |
| def align_encounter( | |
| encounter_type: str | None, | |
| specialty_code: str | None = None, | |
| ) -> tuple[list[str], str]: | |
| """Return (preferred code prefixes, specialty steering keywords).""" | |
| if not encounter_type: | |
| return [], "" | |
| et = encounter_type.lower() | |
| code = normalize_specialty_code(specialty_code) | |
| rules = _FP_RULES if code == "00" else _PAEDS_RULES | |
| for needles, result in rules: | |
| if any(n in et for n in needles): | |
| return list(result[0]), result[1] | |
| return [], "" | |
| def prefix_filter(prefixes: list[str]) -> list[dict]: | |
| """OpenSearch filter clause restricting billing_code to the given prefixes.""" | |
| if not prefixes: | |
| return [] | |
| return [ | |
| { | |
| "bool": { | |
| "should": [{"prefix": {"billing_code": p}} for p in prefixes], | |
| "minimum_should_match": 1, | |
| } | |
| } | |
| ] | |