File size: 3,742 Bytes
ae6ca67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# src/billing.py
from __future__ import annotations
"""Billing helpers: CPT autosuggest and 837 claim builder (demo-only)."""

from dataclasses import dataclass
from typing import List, Dict, Any, Optional
from datetime import datetime, timezone
import json
from pathlib import Path

from .config import CPT, PROVIDER

@dataclass
class CPTSuggestion:
    code: str
    rate: float
    descriptor: str
    eligible: bool
    why: str

def _why_for_minutes(code: str, minutes: int, spoke: bool) -> str:
    if code == "99451":
        if not spoke:
            return "Eligible when no live interprofessional call; written report only; requires β‰₯5 minutes."
        return "Ineligible: 99451 is for written report without live discussion; 'spoke' was checked."
    ranges = {
        "99446": (5, 10),
        "99447": (11, 20),
        "99448": (21, 30),
        "99449": (31, 10**9),
    }
    lo, hi = ranges[code]
    base = f"Eligible minutes window {lo}–{hi if hi<10**9 else '∞'}; requires live discussion with referring clinician."
    if not spoke:
        return f"Ineligible: requires live discussion (spoke=False). Suggested 99451 if β‰₯5 minutes."
    if minutes < lo:
        return f"Ineligible for {code}: minutes below required threshold ({minutes}<{lo})."
    return base

def autosuggest_cpt(minutes: int, spoke: bool) -> List[CPTSuggestion]:
    """Suggest CPT codes based on minutes and whether a live discussion occurred."""
    suggestions: List[CPTSuggestion] = []
    if spoke:
        for code in ["99446", "99447", "99448", "99449"]:
            lo_hi = {
                "99446": (5, 10),
                "99447": (11, 20),
                "99448": (21, 30),
                "99449": (31, 10**9),
            }[code]
            eligible = (minutes >= lo_hi[0]) and (minutes <= lo_hi[1])
            suggestions.append(CPTSuggestion(
                code=code,
                rate=float(CPT[code]["rate"]),
                descriptor=str(CPT[code]["descriptor"]),
                eligible=eligible,
                why=_why_for_minutes(code, minutes, spoke),
            ))
    else:
        eligible = minutes >= 5
        suggestions.append(CPTSuggestion(
            code="99451",
            rate=float(CPT["99451"]["rate"]),
            descriptor=str(CPT["99451"]["descriptor"]),
            eligible=eligible,
            why=_why_for_minutes("99451", minutes, spoke),
        ))
    return suggestions

def build_837_claim(case: Dict[str, Any], code: str, rate: float, minutes: int,
                    spoke: bool, attested: bool, *, template_path: Optional[Path] = None) -> Dict[str, Any]:
    """Build a demo 837 claim JSON from a case and billing selection."""
    now = datetime.now(timezone.utc).isoformat()
    # Load optional template
    template: Dict[str, Any] = {}
    try:
        if template_path and Path(template_path).exists():
            template = json.loads(Path(template_path).read_text(encoding="utf-8"))
    except Exception:
        template = {}

    claim_id = f"EC-{case.get('case_id','UNKNOWN')}-{datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ')}"
    out: Dict[str, Any] = {
        "schema_version": 2,
        "demo_only": True,
        "claim_id": claim_id,
        "created_at": now,
        "provider": PROVIDER,
        "patient": case.get("patient", {}),
        "referring": {"name": (case.get("referrer") or {}).get("name", "Referring Clinician")},
        "service": {
            "cpt_code": code,
            "minutes": minutes,
            "spoke_to_referrer": bool(spoke),
            "amount": float(rate),
        },
        "attested": bool(attested),
        "source_case_id": case.get("case_id"),
    }
    out = {**template, **out}
    return out